diff --git a/zdev/include/device.h b/zdev/include/device.h index c35c3bd0..fe0895f5 100644 --- a/zdev/include/device.h +++ b/zdev/include/device.h @@ -45,6 +45,7 @@ struct device_state { * @node: Node for adding this device to a list * @active: Device state in the active configuration * @persistent: Device state in the persistent configuration + * @autoconf: Auto-configured device state * @errors: A strlist of error and warning messages issued for the device * @processed: Device has been processed */ @@ -59,6 +60,7 @@ struct device { struct device_state active; struct device_state persistent; + struct device_state autoconf; unsigned int processed:1; }; @@ -97,4 +99,6 @@ void device_list_print(struct device_list *, int); struct setting_list *device_get_setting_list(struct device *dev, config_t config); +config_t device_get_config(struct device *dev); + #endif /* DEVICE_H */ diff --git a/zdev/include/misc.h b/zdev/include/misc.h index 9883571e..2fc2ab1f 100644 --- a/zdev/include/misc.h +++ b/zdev/include/misc.h @@ -19,9 +19,14 @@ #include "exit_code.h" #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#define SCOPE_ACTIVE(x) (((x) == config_active) || ((x) == config_all)) -#define SCOPE_PERSISTENT(x) (((x) == config_persistent) || \ - ((x) == config_all)) +#define SCOPE_ACTIVE(x) ((x) & config_active ? 1 : 0) +#define SCOPE_PERSISTENT(x) ((x) & config_persistent ? 1 : 0) +#define SCOPE_AUTOCONF(x) ((x) & config_autoconf ? 1 : 0) +#define SCOPE_ALL(x) ((x) == (config_active | config_persistent |\ + config_autoconf)) +#define SCOPE_SINGLE(x) ((x) == config_active || \ + (x) == config_persistent || \ + (x) == config_autoconf) #define DELAY_INDENT 4 @@ -34,12 +39,15 @@ #define EVEN(x) (((x) & 1) == 0) -/* Enumeration of configuration sets. */ -typedef enum { - config_active, - config_persistent, - config_all, -} config_t; +/* Enumeration of configuration sets. Multiple configuration sets can be + * combined using bit-wise or. */ +enum { + config_active = 1, + config_persistent = 2, + config_autoconf = 4, + config_all = 7, +}; +typedef int config_t; typedef enum { err_ignore, @@ -167,7 +175,7 @@ exit_code_t misc_write_text_file(const char *, const char *, err_t); exit_code_t misc_write_text_file_retry(const char *, const char *, err_t); exit_code_t misc_mktemp(char **, int *); char *misc_readlink(const char *path); -config_t get_config(int, int); +config_t get_config(int act, int pers, int ac); bool is_zvm(void); bool is_terminal(void); const char *config_to_str(config_t); diff --git a/zdev/include/path.h b/zdev/include/path.h index 536ca066..5d2b8369 100644 --- a/zdev/include/path.h +++ b/zdev/include/path.h @@ -24,6 +24,7 @@ #define PATH_CCW_BUS "/sys/bus/ccw" #define PATH_CCWGROUP_BUS "/sys/bus/ccwgroup" #define PATH_UDEV_RULES "/etc/udev/rules.d" +#define PATH_UDEV_RULES_VOLATILE "/run/udev/rules.d" #define PATH_PROC "/proc" #define PATH_UDEVADM "udevadm" @@ -55,8 +56,8 @@ char *path_get_ccw_device(const char *, const char *); char *path_get_ccw_devices(const char *); char *path_get_ccwgroup_device(const char *, const char *); char *path_get_ccwgroup_devices(const char *); -char *path_get_udev_rule(const char *, const char *); -char *path_get_udev_rules(void); +char *path_get_udev_rule(const char *type, const char *id, bool vol); +char *path_get_udev_rules(bool vol); char *path_get_proc(const char *); char *path_get_sys_bus_dev(const char *, const char *); char *path_get_sys_bus_drv(const char *, const char *); diff --git a/zdev/include/setting.h b/zdev/include/setting.h index 0a7e39ff..20e9c7ff 100644 --- a/zdev/include/setting.h +++ b/zdev/include/setting.h @@ -94,7 +94,8 @@ void setting_list_map_values(struct setting_list *); void setting_list_mark_default_derived(struct setting_list *); int setting_list_count_set(struct setting_list *); void setting_list_remove_derived(struct setting_list *); -char *setting_get_changes(struct setting_list *, struct setting_list *); +char *setting_get_changes(struct setting_list *act, struct setting_list *pers, + struct setting_list *ac); bool setting_match_value(struct setting *, const char *); #endif /* SETTING_H */ diff --git a/zdev/include/subtype.h b/zdev/include/subtype.h index 0ec56a67..2142998d 100644 --- a/zdev/include/subtype.h +++ b/zdev/include/subtype.h @@ -67,17 +67,22 @@ typedef exit_code_t (*subtype_cb_t)(struct subtype *st, const char *id, * * @exists_active: Check if device exists in active configuration * @exists_persistent: Check if device exists in persistent configuration + * @exists_autoconf: Check if device exists in autoconf configuration * * @add_active_ids: Add IDs of all devices existing in active configuration to * specified strlist * @add_persistent_ids: Add IDs of all devices existing in persistent * configuration to specified strlist + * @add_autoconf_ids: Add IDs of all devices existing in autoconf + * configuration to specified strlist * * @read_active: Read device configuration from active configuration * @read_persistent: Read device configuration from persistent configuration + * @read_autoconf: Read device configuration from autoconf configuration * * @configure_active: Apply configuration to active configuration * @configure_persistent: Apply configuration to persistent configuration + * @configure_autoconf: Apply configuration to autoconf configuration * * @check_pre_write: Optional: Determine if the given configuration is valid * for the specified device. If not, emit warning messages @@ -150,24 +155,33 @@ struct subtype { bool (*exists_active)(struct subtype *, const char *); bool (*exists_persistent)(struct subtype *, const char *); + bool (*exists_autoconf)(struct subtype *, const char *); void (*add_active_ids)(struct subtype *, struct util_list *); void (*add_persistent_ids)(struct subtype *, struct util_list *); + void (*add_autoconf_ids)(struct subtype *, + struct util_list *); exit_code_t (*read_active)(struct subtype *, struct device *, read_scope_t); exit_code_t (*read_persistent)(struct subtype *, struct device *, read_scope_t); + exit_code_t (*read_autoconf)(struct subtype *, struct device *, + read_scope_t); exit_code_t (*configure_active)(struct subtype *, struct device *); exit_code_t (*configure_persistent)(struct subtype *, struct device *); + exit_code_t (*configure_autoconf)(struct subtype *, + struct device *); exit_code_t (*deconfigure_active)(struct subtype *, struct device *); exit_code_t (*deconfigure_persistent)(struct subtype *, struct device *); + exit_code_t (*deconfigure_autoconf)(struct subtype *, + struct device *); exit_code_t (*check_pre_configure)(struct subtype *, struct device *, int, config_t); @@ -217,23 +231,31 @@ void subtype_exit(struct subtype *); bool subtype_device_exists_active(struct subtype *, const char *); bool subtype_device_exists_persistent(struct subtype *, const char *); +bool subtype_device_exists_autoconf(struct subtype *st, const char *id); void subtype_add_active_ids(struct subtype *, struct util_list *); void subtype_add_persistent_ids(struct subtype *, struct util_list *); +void subtype_add_autoconf_ids(struct subtype *st, struct util_list *ids); exit_code_t subtype_device_read_active(struct subtype *, struct device *, read_scope_t); exit_code_t subtype_device_read_persistent(struct subtype *, struct device *, read_scope_t); +exit_code_t subtype_device_read_autoconf(struct subtype *st, struct device *dev, + read_scope_t scope); exit_code_t subtype_device_configure_active(struct subtype *, struct device *); exit_code_t subtype_device_configure_persistent(struct subtype *, struct device *); +exit_code_t subtype_device_configure_autoconf(struct subtype *st, + struct device *dev); exit_code_t subtype_device_deconfigure_active(struct subtype *, struct device *); exit_code_t subtype_device_deconfigure_persistent(struct subtype *st, struct device *); +exit_code_t subtype_device_deconfigure_autoconf(struct subtype *st, + struct device *dev); exit_code_t subtype_check_pre_configure(struct subtype *, struct device *, int, config_t); diff --git a/zdev/include/udev.h b/zdev/include/udev.h index cfcb8407..d47a4e9a 100644 --- a/zdev/include/udev.h +++ b/zdev/include/udev.h @@ -40,8 +40,9 @@ exit_code_t udev_read_file(const char *, struct udev_file **); void udev_free_file(struct udev_file *); void udev_file_print(struct udev_file *); -void udev_get_device_ids(const char *, struct util_list *); -exit_code_t udev_remove_rule(const char *, const char *); +void udev_get_device_ids(const char *type, struct util_list *list, + bool autoconf); +exit_code_t udev_remove_rule(const char *type, const char *id, bool autoconf); void udev_settle(void); diff --git a/zdev/include/udev_ccw.h b/zdev/include/udev_ccw.h index 353d3c13..9f94a71f 100644 --- a/zdev/include/udev_ccw.h +++ b/zdev/include/udev_ccw.h @@ -15,9 +15,9 @@ struct device; -bool udev_ccw_exists(const char *, const char *); -exit_code_t udev_ccw_read_device(struct device *); -exit_code_t udev_ccw_write_device(struct device *); -exit_code_t udev_ccw_write_cio_ignore(const char *); +bool udev_ccw_exists(const char *type, const char *id, bool autoconf); +exit_code_t udev_ccw_read_device(struct device *dev, bool autoconf); +exit_code_t udev_ccw_write_device(struct device *dev, bool autoconf); +exit_code_t udev_ccw_write_cio_ignore(const char *id_list, bool autoconf); #endif /* UDEV_CCW_H */ diff --git a/zdev/include/udev_ccwgroup.h b/zdev/include/udev_ccwgroup.h index e4534fe0..e1d185be 100644 --- a/zdev/include/udev_ccwgroup.h +++ b/zdev/include/udev_ccwgroup.h @@ -16,10 +16,12 @@ struct device; struct util_list; -bool udev_ccwgroup_exists(const char *, const char *); -exit_code_t udev_ccwgroup_read_device(struct device *); -exit_code_t udev_ccwgroup_write_device(struct device *); -void udev_ccwgroup_add_device_ids(const char *, struct util_list *); -exit_code_t udev_ccwgroup_remove_rule(const char *, const char *); +bool udev_ccwgroup_exists(const char *type, const char *id, bool autoconf); +exit_code_t udev_ccwgroup_read_device(struct device *dev, bool autoconf); +exit_code_t udev_ccwgroup_write_device(struct device *dev, bool autoconf); +void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list, + bool autoconf); +exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id, + bool autoconf); #endif /* UDEV_CCWGROUP_H */ diff --git a/zdev/include/udev_zfcp_lun.h b/zdev/include/udev_zfcp_lun.h index 6bbdcba0..33c5d00d 100644 --- a/zdev/include/udev_zfcp_lun.h +++ b/zdev/include/udev_zfcp_lun.h @@ -15,10 +15,10 @@ struct device; -void udev_zfcp_lun_add_device_ids(struct util_list *); -bool udev_zfcp_lun_exists(const char *); -exit_code_t udev_zfcp_lun_read_device(struct device *); -exit_code_t udev_zfcp_lun_write_device(struct device *); -exit_code_t udev_zfcp_lun_remove_rule(const char *); +void udev_zfcp_lun_add_device_ids(struct util_list *list, bool autoconf); +bool udev_zfcp_lun_exists(const char *id, bool autoconf); +exit_code_t udev_zfcp_lun_read_device(struct device *dev, bool autoconf); +exit_code_t udev_zfcp_lun_write_device(struct device *dev, bool autoconf); +exit_code_t udev_zfcp_lun_remove_rule(const char *id, bool autoconf); #endif /* UDEV_ZFCP_LUN_H */ diff --git a/zdev/man/chzdev.8 b/zdev/man/chzdev.8 index 1c0e6bcd..b0c24af5 100644 --- a/zdev/man/chzdev.8 +++ b/zdev/man/chzdev.8 @@ -428,8 +428,8 @@ using the \-\-import action like in the following example .B Note: By default all configuration data that is read is also applied. To reduce the scope of imported configuration data, you can select specific devices, a device -type, or define whether only data for the active or persistent configuration -should be imported. +type, or define whether only data for the active, persistent or +auto-configuration should be imported. .PP . .OD list-attributes "l" "" @@ -472,6 +472,18 @@ on reboot, or when a device becomes unavailable, or when a device driver is unloaded. .PP . +.OD auto-conf "" "" +Apply changes to the auto-configuration only. + +This option is used internally to apply machine-provided I/O configuration data +to a Linux system. + +.B Note: +There is typically no need for users to specify this option directly. +In particular, user-initiated changes to this configuration will be lost +the next time that machine-provided data is obtained (i.e. during boot). +.PP +. .OD base "" "PATH" | "KEY" = "VALUE" Change file system paths used to access files. diff --git a/zdev/man/lszdev.8 b/zdev/man/lszdev.8 index 4d663eac..902dd256 100644 --- a/zdev/man/lszdev.8 +++ b/zdev/man/lszdev.8 @@ -69,12 +69,13 @@ With no further options specified, the output format defaults to list format. . . .SS "Configurations" -There are two sources for configuration information: the active configuration -of the currently running system, and the persistent configuration stored in -configuration files. +There are three sources for configuration information: the active configuration +of the currently running system, the persistent configuration stored in +configuration files, and the auto-configuration that is provided by some +machine types to automatically enable I/O devices. .PP By default lszdev displays information from both the active and the persistent -configuration. +configuration, and, if available, from the auto-configuration. .PP . . @@ -319,6 +320,19 @@ Restricts output to information obtained from the active configuration, that is information from the running system. .PP . +.OD auto-conf "" "" +List information from the auto-configuration only. + +Restricts output to information obtained from the auto-configuration. +The auto-configuration is the collection of configuration data obtained +automatically on some machine models during boot. + +.B Note: +This data is refreshed during each boot. Also configuration directives in +the auto-configuration only take effect if there is no directive for the +same device in the persistent configuration. +.PP +. .OD base "" "PATH" | "KEY" = "VALUE" Change file system paths used to access files. diff --git a/zdev/src/ccw.c b/zdev/src/ccw.c index 0de27333..78429bc7 100644 --- a/zdev/src/ccw.c +++ b/zdev/src/ccw.c @@ -892,12 +892,13 @@ static exit_code_t collect_group_cb(struct subtype *st, const char *id, } /* Set bits for all persistently configured CCW devices. */ -static char ***id_bitmap_collect(void) +static char ***id_bitmap_collect(bool autoconf) { char ***id_bitmap; int i, j; struct devtype *dt; struct subtype *st; + config_t config = autoconf ? config_autoconf : config_persistent; id_bitmap = id_bitmap_new(); @@ -906,14 +907,14 @@ static char ***id_bitmap_collect(void) for (j = 0; (st = dt->subtypes[j]); j++) { /* Collect CCW device IDs. */ if (st->namespace == &ccw_namespace) { - subtype_for_each_id(st, config_persistent, + subtype_for_each_id(st, config, collect_cb, id_bitmap); } /* Collect CCWGROUP device IDs. Since there may be * multiple namespaces, we need to make use of this * hack. */ if (ccwgroup_compatible_namespace(st->namespace)) { - subtype_for_each_id(st, config_persistent, + subtype_for_each_id(st, config, collect_group_cb, id_bitmap); } @@ -952,7 +953,7 @@ static void range_add(struct util_list *list, struct ccw_devid *from, free(f_str); } -static struct util_list *cio_ignore_get_ranges(void) +static struct util_list *cio_ignore_get_ranges(bool autoconf) { char ***id_bitmap; unsigned int cssid, ssid, devno; @@ -962,7 +963,7 @@ static struct util_list *cio_ignore_get_ranges(void) ranges = strlist_new(); - id_bitmap = id_bitmap_collect(); + id_bitmap = id_bitmap_collect(autoconf); for (cssid = 0; cssid < CSSID_MAX; cssid++) { if (!id_bitmap[cssid]) continue; @@ -1003,24 +1004,34 @@ static struct util_list *cio_ignore_get_ranges(void) } /* Persistently configure cio_ignore. */ -exit_code_t ccw_blacklist_persist(void) +static exit_code_t _ccw_blacklist_persist(bool autoconf) { struct util_list *ranges; char *id_list; exit_code_t rc; /* Get string to write to /proc/cio_ignore. */ - ranges = cio_ignore_get_ranges(); + ranges = cio_ignore_get_ranges(autoconf); id_list = strlist_flatten(ranges, ","); strlist_free(ranges); /* Write udev rule to automatically write cio_ignore. */ - rc = udev_ccw_write_cio_ignore(id_list); + rc = udev_ccw_write_cio_ignore(id_list, autoconf); free(id_list); return rc; } +exit_code_t ccw_blacklist_persist(void) +{ + exit_code_t rc1, rc2; + + rc1 = _ccw_blacklist_persist(false); + rc2 = _ccw_blacklist_persist(true); + + return rc1 ? rc1 : rc2; +} + /* * CCW device ID namespace. */ @@ -1368,7 +1379,13 @@ static bool ccw_st_exists_active(struct subtype *st, const char *id) /* Check if a configuration exists for a CCW device with the specified @id. */ static bool ccw_st_exists_persistent(struct subtype *st, const char *id) { - return udev_ccw_exists(st->name, id); + return udev_ccw_exists(st->name, id, false); +} + +/* Check if a configuration exists for a CCW device with the specified @id. */ +static bool ccw_st_exists_autoconf(struct subtype *st, const char *id) +{ + return udev_ccw_exists(st->name, id, true); } static bool get_ids_cb(const char *file, void *data) @@ -1404,7 +1421,14 @@ static void ccw_st_add_active_ids(struct subtype *st, struct util_list *ids) * to strlist @ids. */ static void ccw_st_add_persistent_ids(struct subtype *st, struct util_list *ids) { - udev_get_device_ids(st->name, ids); + udev_get_device_ids(st->name, ids, false); +} + +/* Add the IDs of all CCW devices for which a autoconf configuration exists + * to strlist @ids. */ +static void ccw_st_add_autoconf_ids(struct subtype *st, struct util_list *ids) +{ + udev_get_device_ids(st->name, ids, true); } /* Read the configuration of the CCW device with the specified @id from the @@ -1440,7 +1464,16 @@ static exit_code_t ccw_st_read_persistent(struct subtype *st, struct device *dev, read_scope_t scope) { - return udev_ccw_read_device(dev); + return udev_ccw_read_device(dev, false); +} + +/* Read the configuration of the CCW device with the specified @id from the + * autoconf configuration and add the resulting data to @dev. */ +static exit_code_t ccw_st_read_autoconf(struct subtype *st, + struct device *dev, + read_scope_t scope) +{ + return udev_ccw_read_device(dev, true); } static int get_online(struct setting_list *list) @@ -1505,7 +1538,14 @@ static exit_code_t ccw_st_configure_active(struct subtype *st, static exit_code_t ccw_st_configure_persistent(struct subtype *st, struct device *dev) { - return udev_ccw_write_device(dev); + return udev_ccw_write_device(dev, false); +} + +/* Create a autoconf configuration for the specified device @dev. */ +static exit_code_t ccw_st_configure_autoconf(struct subtype *st, + struct device *dev) +{ + return udev_ccw_write_device(dev, true); } @@ -1552,7 +1592,22 @@ static exit_code_t ccw_st_deconfigure_active(struct subtype *st, static exit_code_t ccw_st_deconfigure_persistent(struct subtype *st, struct device *dev) { - return udev_remove_rule(st->name, dev->id); + return udev_remove_rule(st->name, dev->id, false); +} + +/** + * ccw_st_deconfigure_autoconf - Deconfigure device in autoconf + * configuration set + * @st: Subtype of target device + * @dev: Target device + * + * Deconfigure device @dev in the autoconf configuration set. Return %EXIT_OK + * on success, an error code otherwise. + */ +static exit_code_t ccw_st_deconfigure_autoconf(struct subtype *st, + struct device *dev) +{ + return udev_remove_rule(st->name, dev->id, true); } /* Perform basic sanity checks. */ @@ -1589,6 +1644,8 @@ static void ccw_st_online_set(struct subtype *st, struct device *dev, setting_list_apply(dev->active.settings, a, name, value); if (SCOPE_PERSISTENT(config)) setting_list_apply(dev->persistent.settings, a, name, value); + if (SCOPE_AUTOCONF(config)) + setting_list_apply(dev->autoconf.settings, a, name, value); } /* Determine the online state of the specified CCW device (0=offline, 1=online, @@ -1596,14 +1653,16 @@ static void ccw_st_online_set(struct subtype *st, struct device *dev, static int ccw_st_online_get(struct subtype *st, struct device *dev, config_t config) { - int act_online = 1, pers_online = 1; + int act_online = 1, pers_online = 1, auto_online = 1; if (SCOPE_ACTIVE(config)) act_online = get_online(dev->active.settings); if (SCOPE_PERSISTENT(config)) pers_online = get_online(dev->persistent.settings); + if (SCOPE_AUTOCONF(config)) + auto_online = get_online(dev->autoconf.settings); - return MIN(act_online, pers_online); + return MIN(MIN(act_online, pers_online), auto_online); } /* Determine if the online state of the specified CCW device was specified */ @@ -1622,6 +1681,11 @@ static bool ccw_st_online_specified(struct subtype *st, struct device *dev, if (s && s->specified) return true; } + if (SCOPE_AUTOCONF(config) && dev->autoconf.settings) { + s = setting_list_find(dev->autoconf.settings, "online"); + if (s && s->specified) + return true; + } return false; } @@ -1769,18 +1833,23 @@ struct subtype ccw_subtype = { .exists_active = &ccw_st_exists_active, .exists_persistent = &ccw_st_exists_persistent, + .exists_autoconf = &ccw_st_exists_autoconf, .add_active_ids = &ccw_st_add_active_ids, .add_persistent_ids = &ccw_st_add_persistent_ids, + .add_autoconf_ids = &ccw_st_add_autoconf_ids, .read_active = &ccw_st_read_active, .read_persistent = &ccw_st_read_persistent, + .read_autoconf = &ccw_st_read_autoconf, .configure_active = &ccw_st_configure_active, .configure_persistent = &ccw_st_configure_persistent, + .configure_autoconf = &ccw_st_configure_autoconf, .deconfigure_active = &ccw_st_deconfigure_active, .deconfigure_persistent = &ccw_st_deconfigure_persistent, + .deconfigure_autoconf = &ccw_st_deconfigure_autoconf, .check_pre_configure = &ccw_st_check_pre_configure, diff --git a/zdev/src/ccwgroup.c b/zdev/src/ccwgroup.c index 53d7eb09..61e12ccf 100644 --- a/zdev/src/ccwgroup.c +++ b/zdev/src/ccwgroup.c @@ -426,6 +426,8 @@ static void ccwgroup_st_online_set(struct subtype *st, struct device *dev, } if (SCOPE_PERSISTENT(config)) setting_list_apply(dev->persistent.settings, a, name, value); + if (SCOPE_AUTOCONF(config)) + setting_list_apply(dev->autoconf.settings, a, name, value); } static int get_online(struct setting_list *list) @@ -446,18 +448,20 @@ static int get_online(struct setting_list *list) } /* Return -1 if online state is not configured, 0 for offline and 1 for online. - * If multiple configurations are specified, return the minimum of both. */ + * If multiple configurations are specified, return the minimum of all. */ static int ccwgroup_st_online_get(struct subtype *st, struct device *dev, config_t config) { - int act_online = 1, pers_online = 1; + int act_online = 1, pers_online = 1, auto_online = 1; if (SCOPE_ACTIVE(config)) act_online = get_online(dev->active.settings); if (SCOPE_PERSISTENT(config)) pers_online = get_online(dev->persistent.settings); + if (SCOPE_AUTOCONF(config)) + auto_online = get_online(dev->autoconf.settings); - return MIN(act_online, pers_online); + return MIN(MIN(act_online, pers_online), auto_online); } /* Determine if the online state of the specified device was modified. */ @@ -476,6 +480,11 @@ static bool ccwgroup_st_online_specified(struct subtype *st, if (s && s->specified) return true; } + if (SCOPE_AUTOCONF(config) && dev->autoconf.settings) { + s = setting_list_find(dev->autoconf.settings, "online"); + if (s && s->specified) + return true; + } return false; } @@ -682,7 +691,18 @@ static exit_code_t ccwgroup_st_read_persistent(struct subtype *st, expand_id(data->ccwgroupdrv, dev); - return udev_ccwgroup_read_device(dev); + return udev_ccwgroup_read_device(dev, false); +} + +static exit_code_t ccwgroup_st_read_autoconf(struct subtype *st, + struct device *dev, + read_scope_t scope) +{ + struct ccwgroup_subtype_data *data = st->data; + + expand_id(data->ccwgroupdrv, dev); + + return udev_ccwgroup_read_device(dev, true); } static exit_code_t ccwgroup_st_configure_active(struct subtype *st, @@ -693,8 +713,9 @@ static exit_code_t ccwgroup_st_configure_active(struct subtype *st, return device_write_active_settings(dev); } -static exit_code_t ccwgroup_st_configure_persistent(struct subtype *st, - struct device *dev) +static exit_code_t _ccwgroup_st_configure_persistent(struct subtype *st, + struct device *dev, + bool autoconf) { struct ccwgroup_subtype_data *data = st->data; struct ccwgroup_devid *devid = dev->devid; @@ -703,9 +724,22 @@ static exit_code_t ccwgroup_st_configure_persistent(struct subtype *st, delayed_err("Incomplete device ID specified\n"); return EXIT_INCOMPLETE_ID; } - return udev_ccwgroup_write_device(dev); + return udev_ccwgroup_write_device(dev, autoconf); } +static exit_code_t ccwgroup_st_configure_persistent(struct subtype *st, + struct device *dev) +{ + return _ccwgroup_st_configure_persistent(st, dev, false); +} + +static exit_code_t ccwgroup_st_configure_autoconf(struct subtype *st, + struct device *dev) +{ + return _ccwgroup_st_configure_persistent(st, dev, true); +} + + static char *ccwgroup_st_get_active_attrib_path(struct subtype *, struct device *, const char *); @@ -733,7 +767,13 @@ static exit_code_t ccwgroup_st_deconfigure_active(struct subtype *st, static exit_code_t ccwgroup_st_deconfigure_persistent(struct subtype *st, struct device *dev) { - return udev_ccwgroup_remove_rule(st->name, dev->id); + return udev_ccwgroup_remove_rule(st->name, dev->id, false); +} + +static exit_code_t ccwgroup_st_deconfigure_autoconf(struct subtype *st, + struct device *dev) +{ + return udev_ccwgroup_remove_rule(st->name, dev->id, true); } /* Check if a CCWGROUP device with the specified ID exists. */ @@ -774,7 +814,12 @@ static bool ccwgroup_st_exists_active(struct subtype *st, const char *id) static bool ccwgroup_st_exists_persistent(struct subtype *st, const char *id) { - return udev_ccwgroup_exists(st->name, id); + return udev_ccwgroup_exists(st->name, id, false); +} + +static bool ccwgroup_st_exists_autoconf(struct subtype *st, const char *id) +{ + return udev_ccwgroup_exists(st->name, id, true); } int ccwgroup_qsort_cmp(const void *a_ptr, const void *b_ptr) @@ -796,7 +841,13 @@ static void ccwgroup_st_add_active_ids(struct subtype *st, static void ccwgroup_st_add_persistent_ids(struct subtype *st, struct util_list *ids) { - udev_ccwgroup_add_device_ids(st->name, ids); + udev_ccwgroup_add_device_ids(st->name, ids, false); +} + +static void ccwgroup_st_add_autoconf_ids(struct subtype *st, + struct util_list *ids) +{ + udev_ccwgroup_add_device_ids(st->name, ids, true); } /* Check if CCW device ID @b is part of CCW group device ID @a. */ @@ -1185,18 +1236,23 @@ struct subtype ccwgroup_subtype = { .exists_active = &ccwgroup_st_exists_active, .exists_persistent = &ccwgroup_st_exists_persistent, + .exists_autoconf = &ccwgroup_st_exists_autoconf, .add_active_ids = &ccwgroup_st_add_active_ids, .add_persistent_ids = &ccwgroup_st_add_persistent_ids, + .add_autoconf_ids = &ccwgroup_st_add_autoconf_ids, .read_active = &ccwgroup_st_read_active, .read_persistent = &ccwgroup_st_read_persistent, + .read_autoconf = &ccwgroup_st_read_autoconf, .configure_active = &ccwgroup_st_configure_active, .configure_persistent = &ccwgroup_st_configure_persistent, + .configure_autoconf = &ccwgroup_st_configure_autoconf, .deconfigure_active = &ccwgroup_st_deconfigure_active, .deconfigure_persistent = &ccwgroup_st_deconfigure_persistent, + .deconfigure_autoconf = &ccwgroup_st_deconfigure_autoconf, .online_set = &ccwgroup_st_online_set, .online_get = &ccwgroup_st_online_get, diff --git a/zdev/src/chzdev.c b/zdev/src/chzdev.c index 3dee631d..4372e546 100644 --- a/zdev/src/chzdev.c +++ b/zdev/src/chzdev.c @@ -86,6 +86,7 @@ struct options { config_t config; unsigned int active:1; unsigned int persistent:1; + unsigned int auto_conf:1; struct util_list *remove; /* List of struct strlist_node */ unsigned int remove_all:1; unsigned int force:1; @@ -138,6 +139,7 @@ enum { OPT_VERBOSE = 'V', OPT_QUIET = 'q', OPT_NO_SETTLE = (OPT_ANONYMOUS_BASE+__COUNTER__), + OPT_AUTO_CONF = (OPT_ANONYMOUS_BASE+__COUNTER__), }; static struct opts_conflict conflict_list[] = { @@ -172,11 +174,13 @@ static struct opts_conflict conflict_list[] = { OPTS_CONFLICT(OPT_APPLY, OPT_DECONFIGURE, OPT_LIST_ATTRIBS, OPT_HELP_ATTRIBS, OPT_LIST_TYPES, OPT_EXPORT, OPT_IMPORT, OPT_REMOVE, - OPT_REMOVE_ALL, OPT_ACTIVE, OPT_PERSISTENT, 0), + OPT_REMOVE_ALL, OPT_ACTIVE, 0), OPTS_CONFLICT(OPT_ONLINE, OPT_OFFLINE), OPTS_CONFLICT(OPT_QUIET, OPT_VERBOSE), + OPTS_CONFLICT(OPT_AUTO_CONF, + OPT_TYPE, OPT_LIST_ATTRIBS, OPT_LIST_TYPES), OPTS_CONFLICT(0, 0), }; @@ -210,6 +214,7 @@ static const struct option opt_list[] = { /* Options. */ { "active", no_argument, NULL, OPT_ACTIVE }, { "persistent", no_argument, NULL, OPT_PERSISTENT }, + { "auto-conf", no_argument, NULL, OPT_AUTO_CONF }, { "remove", required_argument, NULL, OPT_REMOVE }, { "remove-all", no_argument, NULL, OPT_REMOVE_ALL }, { "force", no_argument, NULL, OPT_FORCE }, @@ -883,6 +888,11 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[]) opts->persistent = 1; break; + case OPT_AUTO_CONF: + /* --auto-conf */ + opts->auto_conf = 1; + break; + case OPT_REMOVE: /* --remove ATTRIB */ strlist_add(opts->remove, "%s", optarg); @@ -977,7 +987,13 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[]) goto out; /* Determine configuration set. */ - opts->config = get_config(opts->active, opts->persistent); + if (!opts->active && !opts->persistent && !opts->auto_conf) { + /* Default configuration targets are active + persistent */ + opts->config = config_active | config_persistent; + } else { + opts->config = get_config(opts->active, opts->persistent, + opts->auto_conf); + } /* Handle positional parameters. */ rc = parse_positional(opts, argc, argv, optind); @@ -1049,13 +1065,15 @@ static void remove_all_settings(struct setting_list *settings, int active) /* Perform --remove-all operation for specified config on device. */ static exit_code_t device_remove_all(struct device *dev, config_t config) { - int active, persistent; + int active, persistent, autoconf; active = SCOPE_ACTIVE(config) ? count_removable(dev->active.settings, 1) : 0; persistent = SCOPE_PERSISTENT(config) ? count_removable(dev->persistent.settings, 0) : 0; - if (active == 0 && persistent == 0) { + autoconf = SCOPE_AUTOCONF(config) ? + count_removable(dev->autoconf.settings, 0) : 0; + if (active == 0 && persistent == 0 && autoconf == 0) { delayed_err("No removable settings found\n"); return EXIT_SETTING_NOT_FOUND; } @@ -1063,6 +1081,8 @@ static exit_code_t device_remove_all(struct device *dev, config_t config) remove_all_settings(dev->active.settings, 1); if (persistent) remove_all_settings(dev->persistent.settings, 0); + if (autoconf) + remove_all_settings(dev->autoconf.settings, 0); return EXIT_OK; } @@ -1132,6 +1152,13 @@ static exit_code_t device_remove_settings(struct device *dev, goto out; } + if (SCOPE_AUTOCONF(config)) { + rc = remove_settings(dev->autoconf.settings, names, found, + notfound, 0); + if (rc) + goto out; + } + if (!util_list_is_empty(notfound)) { flat = strlist_flatten(notfound, " "); delayed_err("Setting not found: %s\n", flat); @@ -1199,7 +1226,8 @@ static void print_dev_config_info(struct device *dev, config_t config) changes = setting_get_changes( SCOPE_ACTIVE(config) ? dev->active.settings : NULL, - SCOPE_PERSISTENT(config) ? dev->persistent.settings : NULL); + SCOPE_PERSISTENT(config) ? dev->persistent.settings : NULL, + SCOPE_AUTOCONF(config) ? dev->autoconf.settings : NULL); if (changes) info(" Changes: %s\n", changes); free(changes); @@ -1257,6 +1285,12 @@ static exit_code_t cfg_mod_existence(struct device *dev, config_t config) dev->persistent.modified = 1; } + /* Create autoconf config if necessary. */ + if (SCOPE_AUTOCONF(config) && !dev->autoconf.exists) { + dev->autoconf.exists = 1; + dev->autoconf.modified = 1; + } + return EXIT_OK; } @@ -1296,11 +1330,14 @@ online: /* Make sure there's an online attribute. */ ensure_online(dev, config_active); ensure_online(dev, config_persistent); + ensure_online(dev, config_autoconf); mand: /* Ensure default values for mandatory attributes. */ setting_list_apply_defaults(dev->persistent.settings, dev->subtype->dev_attribs, true); + setting_list_apply_defaults(dev->autoconf.settings, + dev->subtype->dev_attribs, true); return EXIT_OK; } @@ -1336,7 +1373,8 @@ static exit_code_t cfg_write(struct device *dev, int prereq, config_t config, if (!device_needs_writing(dev, config) && !force) goto out; - if (check_active && config == config_persistent && + if (check_active && !SCOPE_ACTIVE(config) && + (SCOPE_PERSISTENT(config) || SCOPE_AUTOCONF(config)) && (!dev->active.exists && !dev->active.definable)) { rc = handle_nonexistent(dev); if (rc) @@ -1377,7 +1415,7 @@ static exit_code_t cfg_configure(struct subtype *st, const char *id, if (proc_ptr) *proc_ptr = 0; - /* Read current device data. Note that we read data from both + /* Read current device data. Note that we read data from all * configurations to enable QETH autodetection and subtype * detection (e.g. dasd -> dasd_fba).*/ dev = NULL; @@ -1398,23 +1436,17 @@ static exit_code_t cfg_configure(struct subtype *st, const char *id, /* Exit here if we're only trying and device cannot be configured. */ if (try && !(dev->active.exists || dev->active.definable || - dev->persistent.exists)) { + dev->persistent.exists || dev->autoconf.exists)) { return EXIT_DEVICE_NOT_FOUND; } - if (config == config_persistent) { - /* Abort if a modification action is triggered for a - * non-existing persistent device. */ - if (!dev->persistent.exists && - (!util_list_is_empty(opts->remove) || opts->remove_all)) - return EXIT_DEVICE_NOT_FOUND; + /* Create device if needed by action. */ + if (opts->enable || !util_list_is_empty(opts->settings)) { + rc = cfg_mod_existence(dev, config); + if (rc) + return rc; } - /* Apply changes to device existence. */ - rc = cfg_mod_existence(dev, config); - if (rc) - return rc; - /* Apply changes to device settings. */ rc = cfg_mod_settings(dev, opts, prereq); if (rc) @@ -1426,10 +1458,12 @@ static exit_code_t cfg_configure(struct subtype *st, const char *id, /* Apply persistent configuration to active configuration. */ static exit_code_t cfg_apply(struct subtype *st, const char *id, int prereq, - struct device **dev_ptr, int *proc_ptr) + struct device **dev_ptr, int *proc_ptr, + bool autoconf) { exit_code_t rc; struct device *dev; + struct device_state *state; /* Reset processed flag. */ if (proc_ptr) @@ -1452,8 +1486,9 @@ static exit_code_t cfg_apply(struct subtype *st, const char *id, int prereq, *proc_ptr = 1; dev->processed = 1; + state = autoconf ? &dev->autoconf : &dev->persistent; /* Exit here if there is no persistent configuration. */ - if (!dev->persistent.exists) + if (!state->exists) return EXIT_NO_DATA; /* Apply changes to device existence. */ @@ -1462,8 +1497,7 @@ static exit_code_t cfg_apply(struct subtype *st, const char *id, int prereq, return rc; /* Copy persistent settings to active configuration. */ - rc = device_apply_settings(dev, config_active, - &dev->persistent.settings->list); + rc = device_apply_settings(dev, config_active, &state->settings->list); if (rc) return rc; @@ -1477,7 +1511,8 @@ static exit_code_t cfg_import(struct subtype *st, const char *id, struct device **dev_ptr, int *proc_ptr) { exit_code_t rc; - struct setting_list *active = NULL, *persistent = NULL; + struct setting_list *active = NULL, *persistent = NULL, + *autoconf = NULL; struct device *dev; /* Reset processed flag. */ @@ -1495,6 +1530,7 @@ static exit_code_t cfg_import(struct subtype *st, const char *id, return EXIT_OK; active = setting_list_copy(dev->active.settings); persistent = setting_list_copy(dev->persistent.settings); + autoconf = setting_list_copy(dev->autoconf.settings); } else if (!prereq) { /* Should not happen. */ return EXIT_OK; @@ -1524,14 +1560,20 @@ static exit_code_t cfg_import(struct subtype *st, const char *id, &persistent->list); if (rc) goto out; + rc = device_apply_settings(dev, config_autoconf, + &autoconf->list); + if (rc) + goto out; } ensure_online(dev, config_active); ensure_online(dev, config_persistent); + ensure_online(dev, config_autoconf); /* Write resulting device data. */ rc = cfg_write(dev, prereq, config, 0); out: + setting_list_free(autoconf); setting_list_free(persistent); setting_list_free(active); @@ -1609,11 +1651,13 @@ static exit_code_t print_config_result(struct selected_dev_node *sel, if (opts->deconfigure) { op = "deconfigure"; verb = "deconfigured"; - if (dev) + if (dev) { already = !dev->active.modified && - !dev->persistent.modified; - else if (rc == EXIT_DEVICE_NOT_FOUND && - config == config_persistent) { + !dev->persistent.modified && + !dev->autoconf.modified; + } else if (rc == EXIT_DEVICE_NOT_FOUND && + (!SCOPE_ACTIVE(config) && (SCOPE_PERSISTENT(config) || + SCOPE_AUTOCONF(config)))) { rc = EXIT_OK; already = 1; } @@ -1685,9 +1729,10 @@ static exit_code_t cfg_prereqs(struct subtype *st, const char *id, prereqs = selected_dev_list_new(); subtype_add_prereqs(st, id, prereqs); util_list_iterate(prereqs, sel) { - if (opts->apply) - rc = cfg_apply(sel->st, sel->id, 1, &dev, &proc); - else if (opts->import) { + if (opts->apply) { + rc = cfg_apply(sel->st, sel->id, 1, &dev, &proc, + opts->auto_conf); + } else if (opts->import) { rc = cfg_import(sel->st, sel->id, config, 1, &dev, &proc); } else { @@ -1760,9 +1805,11 @@ static exit_code_t configure_devices(struct options *opts, int specified, struct namespace *ns; const char *param; struct device *dev; + config_t config = opts->config; /* Determine list of selected devices. */ - if (opts->config == config_persistent || + if ((!SCOPE_ACTIVE(config) && + (SCOPE_PERSISTENT(config) || SCOPE_AUTOCONF(config))) || (opts->select->subtype && opts->select->subtype->support_definable)) existing = 0; else @@ -1808,9 +1855,10 @@ static exit_code_t configure_devices(struct options *opts, int specified, goto next; /* Configure actual target device. */ - if (opts->apply) - rc = cfg_apply(sel->st, sel->id, 0, &dev, &proc); - else { + if (opts->apply) { + rc = cfg_apply(sel->st, sel->id, 0, &dev, &proc, + opts->auto_conf); + } else { rc = cfg_configure(sel->st, sel->id, opts, 0, 0, &dev, &proc); } @@ -1906,7 +1954,7 @@ static exit_code_t deconfigure_one_device(struct subtype *st, const char *id, dev->processed = 1; if (try && !(dev->active.exists || dev->active.definable || - dev->persistent.exists)) { + dev->persistent.exists || dev->autoconf.exists)) { /* Attempt to deconfigure this device will fail. */ return EXIT_DEVICE_NOT_FOUND; } @@ -1916,7 +1964,8 @@ static exit_code_t deconfigure_one_device(struct subtype *st, const char *id, * dev. */ if (SCOPE_ACTIVE(config) && !(dev->active.exists || dev->active.definable)) { - if (!SCOPE_PERSISTENT(config) || !dev->persistent.exists) + if (!((SCOPE_PERSISTENT(config) && dev->persistent.exists) || + (SCOPE_AUTOCONF(config) && dev->autoconf.exists))) return EXIT_DEVICE_NOT_FOUND; } @@ -1940,7 +1989,12 @@ static exit_code_t deconfigure_one_device(struct subtype *st, const char *id, dev->persistent.deconfigured = 1; dev->persistent.modified = 1; } - if (!dev->active.modified && !dev->persistent.modified) + if (SCOPE_AUTOCONF(config) && dev->autoconf.exists) { + dev->autoconf.deconfigured = 1; + dev->autoconf.modified = 1; + } + if (!dev->active.modified && !dev->persistent.modified && + !dev->autoconf.modified) return EXIT_OK; /* Pre-write check. */ @@ -2084,7 +2138,8 @@ static void print_type_config_info(struct devtype *dt, const char *title, changes = setting_get_changes( SCOPE_ACTIVE(config) ? dt->active_settings : NULL, - SCOPE_PERSISTENT(config) ? dt->persistent_settings : NULL); + SCOPE_PERSISTENT(config) ? dt->persistent_settings : NULL, + NULL); if (changes) info(" %s: %s\n", title, changes); free(changes); @@ -2498,6 +2553,8 @@ static void action_note(const char *msg, config_t config) info("%s the active configuration only\n", msg); else if (config == config_persistent) info("%s the persistent configuration only\n", msg); + else if (config == config_autoconf) + info("%s the auto-configuration only\n", msg); } /* Export configuration of selected devices and/or device type to file. */ @@ -2619,7 +2676,7 @@ static exit_code_t import_device(struct device *dev, struct options *opts) struct subtype *st = dev->subtype; exit_code_t rc; config_t config; - int proc = 0, active, persistent; + int proc = 0, active, persistent, autoconf; if (SCOPE_ACTIVE(opts->config)) active = (dev->active.exists || dev->active.definable); @@ -2629,7 +2686,16 @@ static exit_code_t import_device(struct device *dev, struct options *opts) persistent = dev->persistent.exists; else persistent = 0; - config = get_config(active, persistent); + if (SCOPE_AUTOCONF(opts->config)) + autoconf = dev->autoconf.exists; + else + autoconf = 0; + + if (!active && !persistent && !autoconf) { + /* Nothing to import */ + return EXIT_OK; + } + config = get_config(active, persistent, autoconf); /* First check for prerequisite devices that need to be configured. */ rc = cfg_prereqs(st, dev->id, opts, config, 0); @@ -2656,17 +2722,9 @@ static bool import_device_selected(struct device *dev, struct options *opts) if (!select_opts_dev_specified(select)) return false; - /* --active */ - if (opts->config == config_active) { - if (!dev->active.exists && !dev->active.definable) - return false; - } - - /* --persistent */ - if (opts->config == config_persistent) { - if (!dev->persistent.exists) - return false; - } + /* Target configuration */ + if ((device_get_config(dev) & opts->config) == 0) + return false; /* Devtype */ if (select->devtype && dt != select->devtype) diff --git a/zdev/src/chzdev_usage.txt b/zdev/src/chzdev_usage.txt index 12d71a29..b7bc04c4 100644 --- a/zdev/src/chzdev_usage.txt +++ b/zdev/src/chzdev_usage.txt @@ -55,5 +55,6 @@ OPTIONS --dry-run Display changes without applying --base PATH Use PATH as base for accessing files --no-settle Do not wait for udev to settle + --auto-conf Apply changes to auto-configuration only -V, --verbose Print additional run-time information -q, --quiet Print only minimal run-time information diff --git a/zdev/src/dasd.c b/zdev/src/dasd.c index a1ee0285..510339fc 100644 --- a/zdev/src/dasd.c +++ b/zdev/src/dasd.c @@ -316,34 +316,34 @@ static struct attrib dasd_attr_safe_offline = { * DASD subtype methods. */ +static bool _check_use_diag(struct setting_list *list) +{ + struct setting *u; + + u = setting_list_find(list, dasd_attr_use_diag.name); + if (u && u->modified) { + if (u->value && atoi(u->value) == 1) { + delayed_warn("Cannot set 'use_diag=1' on non-z/VM system\n"); + return false; + } + } + return true; +} + /* Check if use_diag setting can be correctly applied. */ static exit_code_t check_use_diag(struct device *dev, config_t config) { - struct setting *u; - int zvm = is_zvm(); + if (is_zvm()) + return EXIT_OK; - if (SCOPE_ACTIVE(config)) { - u = setting_list_find(dev->active.settings, - dasd_attr_use_diag.name); - if (u && u->modified) { - if (u->value && atoi(u->value) == 1 && !zvm) { - delayed_warn("Cannot set 'use_diag=1' on " - "non-z/VM system\n"); - return EXIT_INVALID_CONFIG; - } - } - } - if (SCOPE_PERSISTENT(config)) { - u = setting_list_find(dev->persistent.settings, - dasd_attr_use_diag.name); - if (u && u->modified) { - if (u->value && atoi(u->value) == 1 && !zvm) { - delayed_warn("Cannot set 'use_diag=1' on " - "non-z/VM system\n"); - return EXIT_INVALID_CONFIG; - } - } - } + if (SCOPE_ACTIVE(config) && !_check_use_diag(dev->active.settings)) + return EXIT_INVALID_CONFIG; + if (SCOPE_PERSISTENT(config) && + !_check_use_diag(dev->persistent.settings)) + return EXIT_INVALID_CONFIG; + if (SCOPE_AUTOCONF(config) && + !_check_use_diag(dev->autoconf.settings)) + return EXIT_INVALID_CONFIG; return EXIT_OK; } @@ -376,6 +376,8 @@ static void dasd_st_add_modules(struct subtype *st, struct device *dev, dasd_attr_use_diag.name, &changed, &aset); setting_list_get_bool_state(dev->persistent.settings, dasd_attr_use_diag.name, &changed, &pset); + setting_list_get_bool_state(dev->autoconf.settings, + dasd_attr_use_diag.name, &changed, &pset); if (aset || pset) strlist_add_unique(modules, DASD_DIAG_MOD_NAME); diff --git a/zdev/src/device.c b/zdev/src/device.c index ededc74e..5f187eb3 100644 --- a/zdev/src/device.c +++ b/zdev/src/device.c @@ -40,6 +40,7 @@ struct device *device_new(struct subtype *st, const char *id) dev->active.settings = setting_list_new(); dev->persistent.settings = setting_list_new(); + dev->autoconf.settings = setting_list_new(); return dev; } @@ -53,6 +54,7 @@ void device_free(struct device *dev) free(dev->devid); setting_list_free(dev->active.settings); setting_list_free(dev->persistent.settings); + setting_list_free(dev->autoconf.settings); free(dev); } @@ -83,6 +85,15 @@ void device_print(struct device *dev, int level) setting_list_print(dev->persistent.settings, level + 8); else printf("%*s\n", level + 8, ""); + + printf("%*sautoconf:\n", level + 4, ""); + printf("%*sexists=%d mod=%d deconf=%d\n", + level + 8, "", dev->autoconf.exists, dev->autoconf.modified, + dev->autoconf.deconfigured); + if (dev->autoconf.settings) + setting_list_print(dev->autoconf.settings, level + 8); + else + printf("%*s\n", level + 8, ""); } static const void *device_hash_get_id(void *dev_ptr) @@ -182,6 +193,10 @@ bool device_needs_writing(struct device *dev, config_t config) (dev->persistent.modified || dev->persistent.deconfigured || setting_list_modified(dev->persistent.settings))) return true; + if (SCOPE_AUTOCONF(config) && + (dev->autoconf.modified || dev->autoconf.deconfigured || + setting_list_modified(dev->autoconf.settings))) + return true; return false; } @@ -204,6 +219,8 @@ static exit_code_t apply_setting(struct device *dev, config_t config, /* Check for activeonly. */ if (!force && SCOPE_PERSISTENT(config) && a->activeonly) goto err_activeonly_forceable; + if (!force && SCOPE_AUTOCONF(config) && a->activeonly) + goto err_activeonly_forceable; /* Check for multiple values. */ if (!force && !a->multi && strlist_find(processed, key)) goto err_multi_forceable; @@ -231,8 +248,15 @@ static exit_code_t apply_setting(struct device *dev, config_t config, a, key, value); } + /* Apply to autoconf config. */ + if (SCOPE_AUTOCONF(config)) { + setting_list_apply_specified(dev->autoconf.settings, + a, key, value); + } + /* Additional warning when trying to persist read-only setting. */ - if (config == config_persistent) { + if (!SCOPE_ACTIVE(config) && (SCOPE_PERSISTENT(config) || + SCOPE_AUTOCONF(config))) { s = setting_list_find(dev->active.settings, key); if (s && s->readonly) warn_readonly = true; @@ -341,6 +365,8 @@ void device_reset(struct device *dev, config_t config) reset_device_state(&dev->active); if (SCOPE_PERSISTENT(config)) reset_device_state(&dev->persistent); + if (SCOPE_AUTOCONF(config)) + reset_device_state(&dev->autoconf); dev->processed = 0; } @@ -567,6 +593,12 @@ exit_code_t device_check_settings(struct device *dev, config_t config, err)) return EXIT_INVALID_CONFIG; } + if (SCOPE_AUTOCONF(config)) { + if (!setting_list_check_conflict(dev->autoconf.settings, + config_autoconf, + err)) + return EXIT_INVALID_CONFIG; + } return EXIT_OK; } @@ -578,8 +610,27 @@ struct setting_list *device_get_setting_list(struct device *dev, if (config == config_active) settings = dev->active.settings; - else + else if (config == config_persistent) settings = dev->persistent.settings; + else if (config == config_autoconf) + settings = dev->autoconf.settings; return settings; } + +/* Return configuration set in which device exists. */ +config_t device_get_config(struct device *dev) +{ + config_t config = 0; + + if (dev->active.exists || dev->active.definable) + config |= config_active; + + if (dev->persistent.exists) + config |= config_persistent; + + if (dev->autoconf.exists) + config |= config_autoconf; + + return config; +} diff --git a/zdev/src/export.c b/zdev/src/export.c index a4c425fc..f1acb8a6 100644 --- a/zdev/src/export.c +++ b/zdev/src/export.c @@ -83,7 +83,7 @@ static bool is_exportable(struct setting *s, config_t config) return true; } } - if (SCOPE_PERSISTENT(config)) { + if (SCOPE_PERSISTENT(config) || SCOPE_AUTOCONF(config)) { if (setting_is_set(s)) return true; } @@ -148,10 +148,9 @@ static int count_exportable(struct device *dev, config_t config) struct setting *s; int count; - if (config == config_active) - list = dev->active.settings; - else - list = dev->persistent.settings; + list = device_get_setting_list(dev, config); + if (!list) + return 0; count = 0; util_list_iterate(&list->list, s) { @@ -169,12 +168,26 @@ exit_code_t export_write_device(FILE *fd, struct device *dev, config_t config, exit_code_t rc; struct setting_list *settings; - if (config == config_all) { - rc = export_write_device(fd, dev, config_active, first_ptr); - if (rc) - return rc; - return export_write_device(fd, dev, config_persistent, - first_ptr); + if (!SCOPE_SINGLE(config)) { + if (SCOPE_ACTIVE(config)) { + rc = export_write_device(fd, dev, config_active, + first_ptr); + if (rc) + return rc; + } + if (SCOPE_PERSISTENT(config)) { + rc = export_write_device(fd, dev, config_persistent, + first_ptr); + if (rc) + return rc; + } + if (SCOPE_AUTOCONF(config)) { + rc = export_write_device(fd, dev, config_autoconf, + first_ptr); + if (rc) + return rc; + } + return EXIT_OK; } if (config == config_active) { @@ -185,10 +198,14 @@ exit_code_t export_write_device(FILE *fd, struct device *dev, config_t config, !dev->subtype->support_definable) return EXIT_OK; settings = dev->active.settings; - } else { + } else if (config == config_persistent) { if (!dev->persistent.exists) return EXIT_OK; settings = dev->persistent.settings; + } else { + if (!dev->autoconf.exists) + return EXIT_OK; + settings = dev->autoconf.settings; } write_header(fd, config, dev->subtype->name, dev->id, first_ptr); @@ -204,12 +221,21 @@ exit_code_t export_write_devtype(FILE *fd, struct devtype *dt, config_t config, exit_code_t rc; struct setting_list *settings; - if (config == config_all) { - rc = export_write_devtype(fd, dt, config_active, first_ptr); - if (rc) - return rc; - return export_write_devtype(fd, dt, config_persistent, - first_ptr); + if (!SCOPE_SINGLE(config)) { + if (SCOPE_ACTIVE(config)) { + rc = export_write_devtype(fd, dt, config_active, + first_ptr); + if (rc) + return rc; + } + if (SCOPE_PERSISTENT(config)) { + rc = export_write_devtype(fd, dt, config_persistent, + first_ptr); + if (rc) + return rc; + } + /* Scope autoconf not supported for devtype */ + return EXIT_OK; } if (config == config_active) @@ -379,6 +405,10 @@ static exit_code_t handle_header(const char *filename, int lineno, setting_list_clear(dev->persistent.settings); dev->persistent.exists = 1; } + if (SCOPE_AUTOCONF(hdr->config)) { + setting_list_clear(dev->autoconf.settings); + dev->autoconf.exists = 1; + } } out: @@ -397,13 +427,26 @@ static exit_code_t handle_setting(const char *filename, int lineno, struct attrib **attribs, *a; struct setting_list *list; - if (config == config_all) { - rc = handle_setting(filename, lineno, key, value, dt, dev, - config_active); - if (rc) - return rc; - return handle_setting(filename, lineno, key, value, dt, dev, - config_persistent); + if (!SCOPE_SINGLE(config)) { + if (SCOPE_ACTIVE(config)) { + rc = handle_setting(filename, lineno, key, value, dt, + dev, config_active); + if (rc) + return rc; + } + if (SCOPE_PERSISTENT(config)) { + rc = handle_setting(filename, lineno, key, value, dt, + dev, config_persistent); + if (rc) + return rc; + } + if (SCOPE_AUTOCONF(config)) { + rc = handle_setting(filename, lineno, key, value, dt, + dev, config_autoconf); + if (rc) + return rc; + } + return EXIT_OK; } if (dt) { @@ -452,7 +495,8 @@ static bool empty_device(struct device *dev) if (dev->subtype->support_definable) return false; if (util_list_is_empty(&dev->active.settings->list) && - util_list_is_empty(&dev->persistent.settings->list)) + util_list_is_empty(&dev->persistent.settings->list) && + util_list_is_empty(&dev->autoconf.settings->list)) return true; return false; } diff --git a/zdev/src/firmware.c b/zdev/src/firmware.c index 7179e63b..cac55fbc 100644 --- a/zdev/src/firmware.c +++ b/zdev/src/firmware.c @@ -360,6 +360,8 @@ static void add_setting(const char *filename, struct device *dev, _add_setting(filename, dev, config_active, key, value); if (SCOPE_PERSISTENT(config)) _add_setting(filename, dev, config_persistent, key, value); + if (SCOPE_AUTOCONF(config)) + _add_setting(filename, dev, config_autoconf, key, value); } /* Parse a single device setting in firmware format and apply it to the @@ -477,6 +479,10 @@ static struct device *add_device(struct fw_file *f, struct subtype *st, setting_list_clear(dev->persistent.settings); dev->persistent.exists = 1; } + if (SCOPE_AUTOCONF(config)) { + setting_list_clear(dev->autoconf.settings); + dev->autoconf.exists = 1; + } return dev; } diff --git a/zdev/src/lszdev.c b/zdev/src/lszdev.c index 9dab2022..0e19408a 100644 --- a/zdev/src/lszdev.c +++ b/zdev/src/lszdev.c @@ -59,6 +59,7 @@ struct options { config_t config; unsigned int active:1; unsigned int persistent:1; + unsigned int auto_conf:1; struct util_list *columns; /* List of struct strlist_node */ unsigned int no_headings:1; struct util_list *base; /* List of struct strlist_node */ @@ -98,6 +99,7 @@ enum { OPT_VERBOSE = 'V', OPT_QUIET = 'q', OPT_PAIRS = 'P', + OPT_AUTO_CONF = (OPT_ANONYMOUS_BASE+__COUNTER__), }; static struct opts_conflict conflict_list[] = { @@ -150,6 +152,7 @@ static const struct option opt_list[] = { /* Options. */ { "active", no_argument, NULL, OPT_ACTIVE }, { "persistent", no_argument, NULL, OPT_PERSISTENT }, + { "auto-conf", no_argument, NULL, OPT_AUTO_CONF }, { "columns", required_argument, NULL, OPT_COLUMNS }, { "no-headings", no_argument, NULL, OPT_NO_HEADINGS }, { "base", required_argument, NULL, OPT_BASE }, @@ -623,6 +626,11 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[]) opts->persistent = 1; break; + case OPT_AUTO_CONF: + /* --auto-conf */ + opts->auto_conf = 1; + break; + case OPT_COLUMNS: /* --columns COLUMN */ strlist_add_multi(opts->columns, optarg, ",", 0); @@ -685,7 +693,15 @@ static exit_code_t parse_options(struct options *opts, int argc, char *argv[]) goto out; /* Determine configuration set. */ - opts->config = get_config(opts->active, opts->persistent); + if (!opts->active && !opts->persistent && !opts->auto_conf) { + /* Default display targets are active + persistent - note that + * autoconf data is still shown when available to make users + * aware of this type of data. */ + opts->config = config_active | config_persistent; + } else { + opts->config = get_config(opts->active, opts->persistent, + opts->auto_conf); + } /* Handle positional parameters. */ rc = parse_positional(opts, argc, argv, optind); @@ -725,6 +741,7 @@ enum dev_table_id { dev_netdevs, dev_exists, dev_pers, + dev_auto, dev_online, dev_failed, dev_modules, @@ -744,6 +761,8 @@ static struct column *dev_table = COLUMN_ARRAY( "Device exists in the active configuration"), COLUMN("PERS", align_left, dev_pers, 1, "Device is configured persistently"), + COLUMN("AUTO", align_left, dev_auto, 0, + "Auto-configuration exists for device"), COLUMN("FAILED", align_left, dev_failed, 0, "Device is in error"), COLUMN("NAMES", align_left, dev_names, 1, @@ -762,21 +781,34 @@ static struct column *dev_table = COLUMN_ARRAY( "Path to specific attribute in active configuration") ); -static char *merge_str(const char *act, const char *pers) +static char *merge_str(const char *act, const char *pers, const char *ac, + config_t config) { char *str; + size_t len; - if (act && pers) { - if (strcmp(act, pers) == 0) - str = misc_strdup(act); - else - str = misc_asprintf("%s/%s", act, pers); - } else if (act) - str = misc_strdup(act); - else if (pers) - str = misc_strdup(pers); - else - str = misc_strdup("-"); + act = act ? act : "-"; + pers = pers ? pers : "-"; + ac = ac ? ac : "-"; + + if (strcmp(act, pers) == 0 && strcmp(act, ac) == 0) + return misc_strdup(act); + + len = strlen(act) + strlen(pers) + strlen(ac) + /* 3 * / + NUL */ 4; + str = misc_malloc(len); + + if (SCOPE_ACTIVE(config)) + strcat(str, act); + if (SCOPE_PERSISTENT(config)) { + if (*str) + strcat(str, "/"); + strcat(str, pers); + } + if (SCOPE_AUTOCONF(config)) { + if (*str) + strcat(str, "/"); + strcat(str, ac); + } return str; } @@ -821,10 +853,9 @@ static char *get_attr(struct device *dev, const char *name, config_t config) struct setting_list *list; struct setting *s; - if (config == config_active) - list = dev->active.settings; - else - list = dev->persistent.settings; + list = device_get_setting_list(dev, config); + if (!list) + return NULL; s = setting_list_find(list, name); if (!s) { if (config == config_active) { @@ -841,7 +872,7 @@ static char *get_attr(struct device *dev, const char *name, config_t config) static char *dev_table_get_attr(struct device *dev, const char *attr, config_t config) { - char *act = NULL, *pers = NULL, *str; + char *act = NULL, *pers = NULL, *ac = NULL, *str; const char *name; name = strchr(attr, ':'); @@ -853,10 +884,13 @@ static char *dev_table_get_attr(struct device *dev, const char *attr, act = get_attr(dev, name, config_active); if (SCOPE_PERSISTENT(config)) pers = get_attr(dev, name, config_persistent); + if (SCOPE_AUTOCONF(config)) + ac = get_attr(dev, name, config_autoconf); - str = merge_str(act, pers); + str = merge_str(act, pers, ac, config); free(act); free(pers); + free(ac); return str; } @@ -904,7 +938,11 @@ static char *dev_table_get_value(void *item, int id, const char *heading, return misc_strdup(YESNO(dev->active.exists || dev->active.definable)); case dev_pers: + if (!dev->persistent.exists && dev->autoconf.exists) + return misc_strdup("auto"); return misc_strdup(YESNO(dev->persistent.exists)); + case dev_auto: + return misc_strdup(YESNO(dev->autoconf.exists)); case dev_online: return dev_table_get_online(dev, config_active); case dev_failed: @@ -942,6 +980,7 @@ static read_scope_t get_scope(struct options *opts) case dev_netdevs: case dev_exists: case dev_pers: + case dev_auto: case dev_online: case dev_modules: continue; @@ -960,14 +999,21 @@ static struct util_list *dev_table_build(struct options *opts, struct util_list *selected, *devices = NULL; struct selected_dev_node *sel; struct device *dev; - int active, persistent; + int active, persistent, autoconf; read_scope_t scope; exit_code_t rc; + config_t config = opts->config; scope = get_scope(opts); selected = selected_dev_list_new(); + + /* Read auto-config data when no configuration set was specified to + * make user aware of auto-config data. */ + if (!opts->active && !opts->persistent && !opts->auto_conf) + config |= config_autoconf; + rc = select_devices(opts->select, selected, 1, 0, opts->pairs, - opts->config, scope, err_print); + config, scope, err_print); if (rc) goto out; devices = ptrlist_new(); @@ -987,7 +1033,8 @@ static struct util_list *dev_table_build(struct options *opts, /* Only process existing devices. */ active = dev->active.exists || dev->active.definable; persistent = dev->persistent.exists; - if (!active && !persistent) + autoconf = dev->autoconf.exists; + if (!active && !persistent && !autoconf) continue; ptrlist_add(devices, dev); @@ -1025,9 +1072,11 @@ static exit_code_t do_list_devices(struct options *opts) if (!items) return EXIT_EMPTY_SELECTION; - /* Adjust columns visible depending on --active and --persistent. */ + /* Adjust columns visible depending on selected config set. */ table_set_default(dev_table, dev_online, SCOPE_ACTIVE(opts->config)); table_set_default(dev_table, dev_pers, SCOPE_PERSISTENT(opts->config)); + table_set_default(dev_table, dev_auto, SCOPE_AUTOCONF(opts->config) && + !SCOPE_PERSISTENT(opts->config)); table_set_default(dev_table, dev_names, SCOPE_ACTIVE(opts->config)); /* Display table. */ @@ -1057,17 +1106,20 @@ enum settings_table_id { settings_readonly, settings_active, settings_persistent, + settings_autoconf, }; static struct column *settings_table = COLUMN_ARRAY( COLUMN("ATTRIBUTE", align_left, settings_attribute, 1, ""), COLUMN("READONLY", align_left, settings_readonly, 1, ""), COLUMN("ACTIVE", align_left, settings_active, 1, ""), - COLUMN("PERSISTENT", align_left, settings_persistent, 1, "") + COLUMN("PERSISTENT", align_left, settings_persistent, 1, ""), + COLUMN("AUTOCONF", align_left, settings_autoconf, 0, "") ); static struct util_list *settings_table_build(struct setting_list *active, struct setting_list *persistent, + struct setting_list *autoconf, bool readonly) { struct util_list *names, *items; @@ -1088,6 +1140,10 @@ static struct util_list *settings_table_build(struct setting_list *active, util_list_iterate(&persistent->list, s) strlist_add(names, s->name); } + if (autoconf && !readonly) { + util_list_iterate(&autoconf->list, s) + strlist_add(names, s->name); + } strlist_sort_unique(names, str_cmp); /* Convert strlist to ptrlist. */ @@ -1102,6 +1158,7 @@ static struct util_list *settings_table_build(struct setting_list *active, struct settings_table_data { struct setting_list *active; struct setting_list *persistent; + struct setting_list *autoconf; int pairs; bool readonly; }; @@ -1124,12 +1181,17 @@ static char *settings_table_get_value(void *item, int id, const char *heading, case settings_persistent: list = stdata->persistent; break; + case settings_autoconf: + list = stdata->autoconf; + break; default: break; } if (list) { s = setting_list_find(list, name); - if (s && !(id == settings_persistent && s->derived)) { + if (s && + !((id == settings_persistent || id == settings_autoconf) && + s->derived)) { if (stdata->pairs) return misc_strdup(s->value); else @@ -1145,6 +1207,7 @@ static char *settings_table_get_value(void *item, int id, const char *heading, static void settings_table_print(struct setting_list *active, struct setting_list *persistent, + struct setting_list *autoconf, struct options *opts, int ind, bool readonly, bool neednl) { @@ -1154,7 +1217,7 @@ static void settings_table_print(struct setting_list *active, items = settings_table_build( SCOPE_ACTIVE(opts->config) ? active : NULL, SCOPE_PERSISTENT(opts->config) ? persistent : NULL, - readonly); + autoconf, readonly); if (util_list_is_empty(items)) { if (!opts->pairs && !readonly) indent(ind, "%sNo settings found\n", @@ -1170,8 +1233,12 @@ static void settings_table_print(struct setting_list *active, SCOPE_ACTIVE(opts->config)); table_set_default(settings_table, settings_persistent, SCOPE_PERSISTENT(opts->config) && !readonly ? 1 : 0); + table_set_default(settings_table, settings_autoconf, + (SCOPE_AUTOCONF(opts->config) || autoconf) && + !readonly ? 1 : 0); data.active = active; data.persistent = persistent; + data.autoconf = autoconf; data.pairs = opts->pairs; table_print(settings_table, settings_table_get_value, &data, items, NULL, 1, opts->pairs, ind, 0); @@ -1253,7 +1320,7 @@ static exit_code_t do_info_type(struct options *opts) } } else { settings_table_print(dt->active_settings, - dt->persistent_settings, opts, + dt->persistent_settings, NULL, opts, INFO_INDENT, false, false); } @@ -1280,7 +1347,7 @@ static void do_info_one_device(struct device *dev, struct options *opts) { struct subtype *st = dev->subtype; char *names, *bdevs, *cdevs, *ndevs, *modules, *online, *path, *key; - const char *id, *type, *exists, *persist, *prefix; + const char *id, *type, *exists, *persist, *ac, *prefix; struct util_list *resources, *errors; struct strlist_node *s; bool first; @@ -1299,6 +1366,7 @@ static void do_info_one_device(struct device *dev, struct options *opts) errors = subtype_get_errors(dev->subtype, dev->id); exists = YESNO(dev->active.exists || dev->active.definable); persist = YESNO(dev->persistent.exists); + ac = YESNO(dev->autoconf.exists); /* Print information. */ if (opts->pairs) { @@ -1316,6 +1384,8 @@ static void do_info_one_device(struct device *dev, struct options *opts) print_pair("ONLINE", online); print_pair("EXISTS", exists); print_pair("PERSISTENT", persist); + if (SCOPE_AUTOCONF(opts->config) || dev->autoconf.exists) + print_pair("AUTOCONF", ac); if (errors) { util_list_iterate(errors, s) print_pair("ERROR", s->str); @@ -1341,6 +1411,8 @@ static void do_info_one_device(struct device *dev, struct options *opts) print_info("Online", online); print_info("Exists", exists); print_info("Persistent", persist); + if (SCOPE_AUTOCONF(opts->config) || dev->autoconf.exists) + print_info("Auto-configured", ac); if (errors) { first = true; util_list_iterate(errors, s) { @@ -1382,11 +1454,17 @@ static void do_info_one_device(struct device *dev, struct options *opts) settings_table_print(dev->active.exists ? dev->active.settings : NULL, dev->persistent.exists ? dev->persistent.settings : - NULL, opts, INFO_INDENT, false, !opts->pairs); + NULL, + dev->autoconf.exists ? dev->autoconf.settings : + NULL, + opts, INFO_INDENT, false, !opts->pairs); settings_table_print(dev->active.exists ? dev->active.settings : NULL, dev->persistent.exists ? dev->persistent.settings : - NULL, opts, INFO_INDENT, true, !opts->pairs); + NULL, + dev->autoconf.exists ? dev->autoconf.settings : + NULL, + opts, INFO_INDENT, true, !opts->pairs); strlist_free(errors); free(online); @@ -1404,9 +1482,10 @@ static exit_code_t do_info_devices(struct options *opts) struct util_list *selected; struct selected_dev_node *sel; struct device *dev; - int found, active, persistent; + int found, active, persistent, autoconf; exit_code_t rc, drc = EXIT_OK; read_scope_t scope; + config_t config = opts->config; if (opts->info > 1) scope = scope_all; @@ -1415,7 +1494,13 @@ static exit_code_t do_info_devices(struct options *opts) /* Get list of selected devices. */ selected = selected_dev_list_new(); - select_devices(opts->select, selected, 1, 0, opts->pairs, opts->config, + + /* Read auto-config data when no configuration set was specified to + * make user aware of auto-config data. */ + if (!opts->active && !opts->persistent && !opts->auto_conf) + config |= config_autoconf; + + select_devices(opts->select, selected, 1, 0, opts->pairs, config, scope, err_print); /* Process selected devices. */ @@ -1434,9 +1519,8 @@ static exit_code_t do_info_devices(struct options *opts) /* Only process existing devices. */ active = dev->active.exists || dev->active.definable; persistent = dev->persistent.exists; - if ((opts->config == config_active && !active) || - (opts->config == config_persistent && !persistent) || - (opts->config == config_all && !active && !persistent)) + autoconf = dev->autoconf.exists; + if (!active && !persistent && !autoconf) continue; if (found > 0) printf("\n"); diff --git a/zdev/src/lszdev_usage.txt b/zdev/src/lszdev_usage.txt index 9a451899..a1553674 100644 --- a/zdev/src/lszdev_usage.txt +++ b/zdev/src/lszdev_usage.txt @@ -41,5 +41,6 @@ OPTIONS -n, --no-headings Do not print column headings --base PATH Use PATH as base for accessing files --pairs Produce output in KEY="VALUE" format + --auto-conf Only show auto-configuration data -V, --verbose Print additional run-time information -q, --quiet Print only minimal run-time information diff --git a/zdev/src/misc.c b/zdev/src/misc.c index 940e610b..cbc4ae37 100644 --- a/zdev/src/misc.c +++ b/zdev/src/misc.c @@ -1107,14 +1107,18 @@ char *misc_readlink(const char *path) } /* Determine configuration set. */ -config_t get_config(int active, int persistent) +config_t get_config(int active, int persistent, int autoconf) { - if ((!active && !persistent) || (active && persistent)) - return config_all; - else if (active) - return config_active; - else - return config_persistent; + config_t config = 0; + + if (active) + config |= config_active; + if (persistent) + config |= config_persistent; + if (autoconf) + config |= config_autoconf; + + return config; } /* Determine if program is running under z/VM. */ @@ -1248,11 +1252,12 @@ const char *config_to_str(config_t config) return "active"; case config_persistent: return "persistent"; + case config_autoconf: + return "autoconf"; case config_all: return "all"; } - /* Should not happen. */ - return ""; + return "multiple"; } /* Convert textual config representation to config_t. */ @@ -1262,6 +1267,8 @@ bool str_to_config(const char *str, config_t *config_ptr) *config_ptr = config_active; else if (strcasecmp(str, "persistent") == 0) *config_ptr = config_persistent; + else if (strcasecmp(str, "autoconf") == 0) + *config_ptr = config_autoconf; else if (strcasecmp(str, "all") == 0) *config_ptr = config_all; else diff --git a/zdev/src/path.c b/zdev/src/path.c index 9d8a9bd3..f9f2c751 100644 --- a/zdev/src/path.c +++ b/zdev/src/path.c @@ -297,21 +297,25 @@ char *path_get_ccwgroup_devices(const char *drv) } /* Return path to udev rule. */ -char *path_get_udev_rule(const char *type, const char *id) +char *path_get_udev_rule(const char *type, const char *id, bool vol) { + const char *path = vol ? PATH_UDEV_RULES_VOLATILE : PATH_UDEV_RULES; + if (id) { - return path_get("%s/%s-%s-%s%s", PATH_UDEV_RULES, + return path_get("%s/%s-%s-%s%s", path, UDEV_PREFIX, type, id, UDEV_SUFFIX); } - return path_get("%s/%s-%s%s", PATH_UDEV_RULES, + return path_get("%s/%s-%s%s", path, UDEV_PREFIX, type, UDEV_SUFFIX); } /* Return path to directory containing all udev rules. */ -char *path_get_udev_rules(void) +char *path_get_udev_rules(bool vol) { - return path_get("%s", PATH_UDEV_RULES); + const char *path = vol ? PATH_UDEV_RULES_VOLATILE : PATH_UDEV_RULES; + + return path_get("%s", path); } /* Return path to the specified file in the proc file system. */ diff --git a/zdev/src/qeth.c b/zdev/src/qeth.c index f0235c3a..07b8d8e9 100644 --- a/zdev/src/qeth.c +++ b/zdev/src/qeth.c @@ -1207,7 +1207,7 @@ static exit_code_t check_layer2(struct device *dev, config_t config) { struct setting *l; int layer2_detected, layer2_active = -1, layer2_persistent = -1, - layer2_modified = 0; + layer2_autoconf = -1, layer2_modified = 0; exit_code_t rc = EXIT_OK; layer2_detected = detect_layer2(dev); @@ -1231,13 +1231,25 @@ static exit_code_t check_layer2(struct device *dev, config_t config) if (rc) goto out; } + l = setting_list_find(dev->autoconf.settings, qeth_attr_layer2.name); + if (l) { + layer2_autoconf = atoi(l->value); + layer2_modified |= l->modified; + } else if (SCOPE_AUTOCONF(config)) { + rc = generate_layer2("autoconf", dev->autoconf.settings, + &layer2_autoconf, &layer2_modified); + if (rc) + goto out; + } /* Check correct layer2 setting. */ if (layer2_detected != -1) { if ((SCOPE_ACTIVE(config) && layer2_active != -1 && layer2_active != layer2_detected) || (SCOPE_PERSISTENT(config) && layer2_persistent != -1 && - layer2_persistent != layer2_detected)) { + layer2_persistent != layer2_detected) || + (SCOPE_AUTOCONF(config) && layer2_autoconf != -1 && + layer2_autoconf != layer2_detected)) { rc = layer2_mismatch(layer2_detected, layer2_modified); if (rc) goto out; @@ -1256,14 +1268,25 @@ static exit_code_t check_layer2(struct device *dev, config_t config) if (rc) goto out; } + if (SCOPE_AUTOCONF(config)) { + rc = check_ineffective_settings(dev->autoconf.settings, + layer2_autoconf); + if (rc) + goto out; + } /* check for conflicting layer2 attribute groups */ if (SCOPE_ACTIVE(config)) { rc = check_conflicting_settings(dev->active.settings); if (rc) goto out; } - if (SCOPE_PERSISTENT(config)) + if (SCOPE_PERSISTENT(config)) { rc = check_conflicting_settings(dev->persistent.settings); + if (rc) + goto out; + } + if (SCOPE_AUTOCONF(config)) + rc = check_conflicting_settings(dev->autoconf.settings); out: return rc; @@ -1277,7 +1300,8 @@ static exit_code_t qeth_st_check_pre_configure(struct subtype *st, /* No need to check if device is deconfigured. */ if ((SCOPE_ACTIVE(config) && dev->active.deconfigured) || - (SCOPE_PERSISTENT(config) && dev->persistent.deconfigured)) + (SCOPE_PERSISTENT(config) && dev->persistent.deconfigured) || + (SCOPE_AUTOCONF(config) && dev->autoconf.deconfigured)) return EXIT_OK; rc = check_layer2(dev, config); diff --git a/zdev/src/select.c b/zdev/src/select.c index 3fe3b3d8..adb7bfb5 100644 --- a/zdev/src/select.c +++ b/zdev/src/select.c @@ -248,12 +248,13 @@ static void unblacklist_devices(struct select_opts *select) bool select_match_state(struct device *dev, struct select_opts *select) { struct subtype *st = dev->subtype; - int exists, configured, online; + int exists, configured, autoconf, online; struct util_list *errors; exists = dev->active.exists || dev->active.definable; configured = dev->persistent.exists; - if (select->all && !(exists || configured)) + autoconf = dev->autoconf.exists; + if (select->all && !(exists || configured || autoconf)) return false; if (select->existing && !exists) return false; @@ -862,7 +863,8 @@ static exit_code_t select_nocreate(struct select_opts *select, select->offline || select->online || SCOPE_ACTIVE(config), select->configured || select->all || - SCOPE_PERSISTENT(config)); + SCOPE_PERSISTENT(config), + select->all || SCOPE_AUTOCONF(config)); longrun_total = 0; if (quiet) @@ -870,7 +872,7 @@ static exit_code_t select_nocreate(struct select_opts *select, /* Count devices. */ verb("Scanning for devices in %s configuration%s:\n", - config_to_str(id_config), id_config == config_all ? "s" : ""); + config_to_str(id_config), !SCOPE_SINGLE(id_config) ? "s" : ""); for (i = 0; (dt = devtypes[i]); i++) { if (select->devtype && dt != select->devtype) continue; @@ -1128,6 +1130,13 @@ static exit_code_t by_attr_cb(struct subtype *st, const char *id, /* Check for attribute value in persistent configuration. */ s = setting_list_find(dev->persistent.settings, cb_data->key); + if (s) { + match = setting_match_value(s, cb_data->value); + if (match) + goto out; + } + /* Check for attribute value in autoconf configuration. */ + s = setting_list_find(dev->autoconf.settings, cb_data->key); if (s) match = setting_match_value(s, cb_data->value); diff --git a/zdev/src/setting.c b/zdev/src/setting.c index 1cdd3dd0..965b9289 100644 --- a/zdev/src/setting.c +++ b/zdev/src/setting.c @@ -646,7 +646,8 @@ static void add_changes(struct util_list *list, struct setting *s) /* Return a newly allocated string containing the setting changes found * in PERS and ACT or NULL if no change was found. */ -char *setting_get_changes(struct setting_list *act, struct setting_list *pers) +char *setting_get_changes(struct setting_list *act, struct setting_list *pers, + struct setting_list *ac) { struct util_list *out; struct util_list *processed; @@ -668,6 +669,17 @@ char *setting_get_changes(struct setting_list *act, struct setting_list *pers) strlist_add(processed, s->name); } } + if (ac) { + util_list_iterate(&ac->list, s) { + if (s->removed) + strlist_add(out, "-%s", s->name); + else if (s->modified) + add_changes(out, s); + else + continue; + strlist_add(processed, s->name); + } + } if (act) { util_list_iterate(&act->list, s) { if (!s->modified && !s->removed) diff --git a/zdev/src/subtype.c b/zdev/src/subtype.c index 4bddd3ec..4acdf2ff 100644 --- a/zdev/src/subtype.c +++ b/zdev/src/subtype.c @@ -195,6 +195,13 @@ bool subtype_device_exists_persistent(struct subtype *st, const char *id) return super->exists_persistent(st, id); } +bool subtype_device_exists_autoconf(struct subtype *st, const char *id) +{ + struct subtype *super = super_get(st, exists_autoconf, 1); + + return super->exists_autoconf(st, id); +} + void subtype_add_active_ids(struct subtype *st, struct util_list *ids) { struct subtype *super = super_get(st, add_active_ids, 1); @@ -209,6 +216,13 @@ void subtype_add_persistent_ids(struct subtype *st, struct util_list *ids) super->add_persistent_ids(st, ids); } +void subtype_add_autoconf_ids(struct subtype *st, struct util_list *ids) +{ + struct subtype *super = super_get(st, add_autoconf_ids, 1); + + super->add_autoconf_ids(st, ids); +} + exit_code_t subtype_device_read_active(struct subtype *st, struct device *dev, read_scope_t scope) { @@ -226,6 +240,15 @@ exit_code_t subtype_device_read_persistent(struct subtype *st, return super->read_persistent(st, dev, scope); } +exit_code_t subtype_device_read_autoconf(struct subtype *st, + struct device *dev, + read_scope_t scope) +{ + struct subtype *super = super_get(st, read_autoconf, 1); + + return super->read_autoconf(st, dev, scope); +} + exit_code_t subtype_device_configure_active(struct subtype *st, struct device *dev) { @@ -242,6 +265,14 @@ exit_code_t subtype_device_configure_persistent(struct subtype *st, return super->configure_persistent(st, dev); } +exit_code_t subtype_device_configure_autoconf(struct subtype *st, + struct device *dev) +{ + struct subtype *super = super_get(st, configure_autoconf, 1); + + return super->configure_autoconf(st, dev); +} + exit_code_t subtype_device_deconfigure_active(struct subtype *st, struct device *dev) { @@ -258,6 +289,14 @@ exit_code_t subtype_device_deconfigure_persistent(struct subtype *st, return super->deconfigure_persistent(st, dev); } +exit_code_t subtype_device_deconfigure_autoconf(struct subtype *st, + struct device *dev) +{ + struct subtype *super = super_get(st, deconfigure_autoconf, 1); + + return super->deconfigure_autoconf(st, dev); +} + exit_code_t subtype_check_pre_configure(struct subtype *st, struct device *dev, int prereq, config_t config) { @@ -299,7 +338,7 @@ void subtype_online_set(struct subtype *st, struct device *dev, int online, int subtype_online_get(struct subtype *st, struct device *dev, config_t config) { struct subtype *super = super_get(st, online_get, 0); - int act_online = 1, pers_online = 1; + int act_online = 1, pers_online = 1, auto_online = 1; if (super) return super->online_get(st, dev, config); @@ -310,8 +349,10 @@ int subtype_online_get(struct subtype *st, struct device *dev, config_t config) act_online = dev->active.exists; if (SCOPE_PERSISTENT(config)) pers_online = dev->persistent.exists; + if (SCOPE_AUTOCONF(config)) + auto_online = dev->autoconf.exists; - return MIN(act_online, pers_online); + return MIN(MIN(act_online, pers_online), auto_online); } bool subtype_online_specified(struct subtype *st, struct device *dev, @@ -495,6 +536,10 @@ bool subtype_device_exists(struct subtype *st, const char *id, config_t config) if (!subtype_device_exists_persistent(st, id)) return false; } + if (SCOPE_AUTOCONF(config)) { + if (!subtype_device_exists_autoconf(st, id)) + return false; + } return true; } @@ -512,6 +557,8 @@ static struct util_list *get_ids(struct subtype *st, config_t config) } if (SCOPE_PERSISTENT(config)) subtype_add_persistent_ids(st, ids); + if (SCOPE_AUTOCONF(config)) + subtype_add_autoconf_ids(st, ids); /* Provide a sorted view. */ strlist_sort_unique(ids, st->namespace->qsort_cmp); @@ -683,6 +730,19 @@ static exit_code_t read_device(struct subtype *st, const char *id, goto out; } + if (SCOPE_AUTOCONF(config)) { + if (subtype_device_exists_autoconf(st, id)) + rc = subtype_device_read_autoconf(st, dev, scope); + else if (defined) { + /* Need to copy detected settings to autoconf + * config. */ + setting_list_merge(dev->autoconf.settings, + dev->active.settings, false, false); + } + if (rc) + goto out; + } + if (add) device_list_add(st->devices, dev); @@ -756,6 +816,25 @@ exit_code_t subtype_write_device(struct subtype *st, struct device *dev, if (!rc) namespace_set_modified(dev->subtype->namespace); } + if (SCOPE_AUTOCONF(config)) { + if (dev->autoconf.deconfigured) { + /* Deconfigure device. */ + if (dev->autoconf.exists) { + rc = subtype_device_deconfigure_autoconf(st, + dev); + if (rc) + return rc; + } + } else if (dev->autoconf.exists) { + /* Configure device. */ + rc = subtype_device_configure_autoconf(st, dev); + if (rc) + return rc; + } + if (!rc) + namespace_set_modified(dev->subtype->namespace); + } + return EXIT_OK; } diff --git a/zdev/src/udev.c b/zdev/src/udev.c index 8733ee45..42c7f09a 100644 --- a/zdev/src/udev.c +++ b/zdev/src/udev.c @@ -360,7 +360,8 @@ static bool get_ids_cb(const char *filename, void *data) /* Add the IDs for all devices of the specified subtype name for which a * udev rule exists to strlist LIST. */ -void udev_get_device_ids(const char *type, struct util_list *list) +void udev_get_device_ids(const char *type, struct util_list *list, + bool autoconf) { char *path, *prefix; struct util_list *files; @@ -369,7 +370,7 @@ void udev_get_device_ids(const char *type, struct util_list *list) prefix = misc_asprintf("%s-%s-", UDEV_PREFIX, type); plen = strlen(prefix); - path = path_get_udev_rules(); + path = path_get_udev_rules(autoconf); files = strlist_new(); if (!misc_read_dir(path, files, get_ids_cb, prefix)) goto out; @@ -388,12 +389,12 @@ out: } /* Remove UDEV rule for device. */ -exit_code_t udev_remove_rule(const char *type, const char *id) +exit_code_t udev_remove_rule(const char *type, const char *id, bool autoconf) { char *path; exit_code_t rc = EXIT_OK; - path = path_get_udev_rule(type, id); + path = path_get_udev_rule(type, id, autoconf); if (util_path_is_reg_file(path)) rc = remove_file(path); free(path); diff --git a/zdev/src/udev_ccw.c b/zdev/src/udev_ccw.c index 2aedf825..af00fc4b 100644 --- a/zdev/src/udev_ccw.c +++ b/zdev/src/udev_ccw.c @@ -25,7 +25,7 @@ #include "udev_ccw.h" /* Check if a udev rule for the specified ccw device exists. */ -bool udev_ccw_exists(const char *type, const char *id) +bool udev_ccw_exists(const char *type, const char *id, bool autoconf) { char *path, *normid; bool rc; @@ -34,7 +34,7 @@ bool udev_ccw_exists(const char *type, const char *id) if (!normid) return false; - path = path_get_udev_rule(type, normid); + path = path_get_udev_rule(type, normid, autoconf); rc = util_path_is_reg_file(path); free(path); free(normid); @@ -88,15 +88,16 @@ static void udev_file_get_settings(struct udev_file *file, } /* Read the persistent configuration of a CCW device from a udev rule. */ -exit_code_t udev_ccw_read_device(struct device *dev) +exit_code_t udev_ccw_read_device(struct device *dev, bool autoconf) { struct subtype *st = dev->subtype; - struct device_state *state = &dev->persistent; + struct device_state *state = autoconf ? &dev->autoconf : + &dev->persistent; struct udev_file *file = NULL; exit_code_t rc; char *path; - path = path_get_udev_rule(st->name, dev->id); + path = path_get_udev_rule(st->name, dev->id, autoconf); rc = udev_read_file(path, &file); if (rc) goto out; @@ -128,12 +129,13 @@ static char *get_label_id(const char *prefix, const char *type, } /* Write the persistent configuration of a CCW device to a udev rule. */ -exit_code_t udev_ccw_write_device(struct device *dev) +exit_code_t udev_ccw_write_device(struct device *dev, bool autoconf) { struct subtype *st = dev->subtype; struct ccw_subtype_data *data = st->data; const char *type = st->name, *drv = data->ccwdrv, *id = dev->id; - struct device_state *state = &dev->persistent; + struct device_state *state = autoconf ? &dev->autoconf : + &dev->persistent; char *path, *cfg_label = NULL, *end_label = NULL; struct util_list *list; struct ptrlist_node *p; @@ -142,7 +144,7 @@ exit_code_t udev_ccw_write_device(struct device *dev) FILE *fd; if (!state->exists) - return udev_remove_rule(type, id); + return udev_remove_rule(type, id, autoconf); cfg_label = get_label_id("cfg", type, id); end_label = get_label_id("end", type, id); @@ -150,7 +152,7 @@ exit_code_t udev_ccw_write_device(struct device *dev) /* Apply attributes in correct order. */ list = setting_list_get_sorted(state->settings); - path = path_get_udev_rule(type, id); + path = path_get_udev_rule(type, id, autoconf); debug("Writing %s udev rule file %s\n", type, path); if (!util_path_exists(path)) { rc = path_create(path); @@ -234,14 +236,18 @@ out: } /* Write a udev rule to free devices from the cio-ignore blacklist. */ -exit_code_t udev_ccw_write_cio_ignore(const char *id_list) +exit_code_t udev_ccw_write_cio_ignore(const char *id_list, bool autoconf) { - char *path, *curr = NULL; + char *path, *prefix, *curr = NULL; FILE *fd; exit_code_t rc = EXIT_OK; + /* Ensure that autoconf version of cio-ignore is not masked + * by normal one. */ + prefix = autoconf ? "cio-ignore-autoconf" : "cio-ignore"; + /* Create file. */ - path = path_get_udev_rule("cio-ignore", NULL); + path = path_get_udev_rule(prefix, NULL, autoconf); if (!*id_list) { /* Empty id_list string - remove file. */ diff --git a/zdev/src/udev_ccwgroup.c b/zdev/src/udev_ccwgroup.c index 7b433e7b..fa84f5f7 100644 --- a/zdev/src/udev_ccwgroup.c +++ b/zdev/src/udev_ccwgroup.c @@ -25,34 +25,34 @@ #include "udev_ccwgroup.h" static char *get_rule_path_by_devid(const char *type, - struct ccwgroup_devid *devid) + struct ccwgroup_devid *devid, bool autoconf) { char *ccw_id, *path; ccw_id = ccw_devid_to_str(&devid->devid[0]); - path = path_get_udev_rule(type, ccw_id); + path = path_get_udev_rule(type, ccw_id, autoconf); free(ccw_id); return path; } -static char *get_rule_path(const char *type, const char *id) +static char *get_rule_path(const char *type, const char *id, bool autoconf) { struct ccwgroup_devid devid; if (ccwgroup_parse_devid(&devid, id, err_ignore) != EXIT_OK) return NULL; - return get_rule_path_by_devid(type, &devid); + return get_rule_path_by_devid(type, &devid, autoconf); } /* Check if a udev rule for the specified CCWGROUP device exists. */ -bool udev_ccwgroup_exists(const char *type, const char *id) +bool udev_ccwgroup_exists(const char *type, const char *id, bool autoconf) { char *path; bool rc; - path = get_rule_path(type, id); + path = get_rule_path(type, id, autoconf); if (!path) return false; rc = util_path_is_reg_file(path); @@ -143,15 +143,16 @@ static void expand_id(struct device *dev, struct udev_file *file) } /* Read the persistent configuration of a CCWGROUP device from a udev rule. */ -exit_code_t udev_ccwgroup_read_device(struct device *dev) +exit_code_t udev_ccwgroup_read_device(struct device *dev, bool autoconf) { struct subtype *st = dev->subtype; - struct device_state *state = &dev->persistent; + struct device_state *state = autoconf ? &dev->autoconf : + &dev->persistent; struct udev_file *file = NULL; exit_code_t rc; char *path; - path = get_rule_path_by_devid(st->name, dev->devid); + path = get_rule_path_by_devid(st->name, dev->devid, autoconf); rc = udev_read_file(path, &file); if (rc) goto out; @@ -184,9 +185,11 @@ static char *get_label_id(const char *prefix, const char *type, } /* Write the persistent configuration of a CCWGROUP device to a udev rule. */ -exit_code_t udev_ccwgroup_write_device(struct device *dev) +exit_code_t udev_ccwgroup_write_device(struct device *dev, bool autoconf) { struct subtype *st = dev->subtype; + struct device_state *state = autoconf ? &dev->autoconf : + &dev->persistent; struct ccwgroup_subtype_data *data = st->data; const char *type = st->name, *drv = data->ccwgroupdrv, *id = dev->id; struct ccwgroup_devid devid; @@ -200,21 +203,21 @@ exit_code_t udev_ccwgroup_write_device(struct device *dev) FILE *fd; unsigned int i; - if (!dev->persistent.exists) - return udev_ccwgroup_remove_rule(type, id); + if (!state->exists) + return udev_ccwgroup_remove_rule(type, id, autoconf); if (ccwgroup_parse_devid(&devid, id, err_ignore) != EXIT_OK) return EXIT_INVALID_ID; ccw_id = ccw_devid_to_str(&devid.devid[0]); - path = get_rule_path(type, ccw_id); + path = get_rule_path(type, ccw_id, autoconf); group_label = get_label_id("group", type, ccw_id); cfg_label = get_label_id("cfg", type, ccw_id); end_label = get_label_id("end", type, ccw_id); /* Apply attributes in correct order. */ - list = setting_list_get_sorted(dev->persistent.settings); + list = setting_list_get_sorted(state->settings); debug("Writing %s udev rule file %s\n", type, path); if (!util_path_exists(path)) { @@ -357,12 +360,13 @@ static exit_code_t get_ids_cb(const char *path, const char *filename, /* Add the IDs for all devices of the specified subtype name for which a * udev rule exists to strlist LIST. */ -void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list) +void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list, + bool autoconf) { struct get_ids_cb_data cb_data; char *path; - path = path_get_udev_rules(); + path = path_get_udev_rules(autoconf); cb_data.prefix = misc_asprintf("%s-%s-", UDEV_PREFIX, type); cb_data.ids = list; @@ -374,7 +378,8 @@ void udev_ccwgroup_add_device_ids(const char *type, struct util_list *list) } /* Remove UDEV rule for CCWGROUP device. */ -exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id) +exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id, + bool autoconf) { char *partial_id, *path; exit_code_t rc = EXIT_OK; @@ -383,7 +388,7 @@ exit_code_t udev_ccwgroup_remove_rule(const char *type, const char *id) if (!partial_id) return EXIT_INVALID_ID; - path = path_get_udev_rule(type, partial_id); + path = path_get_udev_rule(type, partial_id, autoconf); if (util_path_is_reg_file(path)) rc = remove_file(path); free(path); diff --git a/zdev/src/udev_zfcp_lun.c b/zdev/src/udev_zfcp_lun.c index 5ab16c3b..69181ed8 100644 --- a/zdev/src/udev_zfcp_lun.c +++ b/zdev/src/udev_zfcp_lun.c @@ -369,14 +369,14 @@ static exit_code_t lun_cb(const char *path, const char *name, void *data) /* Add the IDs for all zfcp lun devices for which a configuration exists to * LIST. */ -void udev_zfcp_lun_add_device_ids(struct util_list *list) +void udev_zfcp_lun_add_device_ids(struct util_list *list, bool autoconf) { struct lun_cb_data cb_data; char *path; cb_data.prefix = misc_asprintf("%s-%s-", UDEV_PREFIX, ZFCP_LUN_NAME); cb_data.list = list; - path = path_get_udev_rules(); + path = path_get_udev_rules(autoconf); if (util_path_is_dir(path)) path_for_each(path, lun_cb, &cb_data); @@ -387,7 +387,7 @@ void udev_zfcp_lun_add_device_ids(struct util_list *list) /* Return path to zfcp lun udev rule file containing configuration data for * all LUNs of a zfcp device. */ -static char *get_zfcp_lun_path(const char *id) +static char *get_zfcp_lun_path(const char *id, bool autoconf) { char *copy, *e, *path; @@ -395,7 +395,7 @@ static char *get_zfcp_lun_path(const char *id) e = strchr(copy, ':'); if (e) *e = 0; - path = path_get_udev_rule(ZFCP_LUN_NAME, copy); + path = path_get_udev_rule(ZFCP_LUN_NAME, copy, autoconf); free(copy); return path; @@ -403,9 +403,9 @@ static char *get_zfcp_lun_path(const char *id) /* Return path to zfcp lun udev rule file containing configuration data for * a single LUN. */ -static char *get_single_zfcp_lun_path(const char *id) +static char *get_single_zfcp_lun_path(const char *id, bool autoconf) { - return path_get_udev_rule(ZFCP_LUN_NAME, id); + return path_get_udev_rule(ZFCP_LUN_NAME, id, autoconf); } /* Apply the settings found in NODE to STATE. */ @@ -437,20 +437,21 @@ static void zfcp_lun_node_to_state(struct zfcp_lun_node *node, } /* Read the persistent configuration of a zfcp lun from a udev rule. */ -exit_code_t udev_zfcp_lun_read_device(struct device *dev) +exit_code_t udev_zfcp_lun_read_device(struct device *dev, bool autoconf) { struct subtype *st = dev->subtype; - struct device_state *state = &dev->persistent; + struct device_state *state = autoconf ? &dev->autoconf : + &dev->persistent; struct util_list *luns; struct zfcp_lun_node *node; exit_code_t rc = EXIT_OK; char *path; /* Check for single lun file first then try multi lun file. */ - path = get_single_zfcp_lun_path(dev->id); + path = get_single_zfcp_lun_path(dev->id, autoconf); if (!util_path_exists(path)) { free(path); - path = get_zfcp_lun_path(dev->id); + path = get_zfcp_lun_path(dev->id, autoconf); } /* Get previous rule data. */ @@ -616,7 +617,7 @@ out: * applies the corresponding parameters. If @single is set, update a single * lun rule file, otherwise update a multi lun rule file. */ static exit_code_t update_lun_rule(const char *id, struct device_state *state, - bool single) + bool single, bool autoconf) { struct zfcp_lun_devid devid; struct util_list *luns; @@ -628,7 +629,8 @@ static exit_code_t update_lun_rule(const char *id, struct device_state *state, rc = zfcp_lun_parse_devid(&devid, id, err_delayed_print); if (rc) return rc; - path = single ? get_single_zfcp_lun_path(id) : get_zfcp_lun_path(id); + path = single ? get_single_zfcp_lun_path(id, autoconf) : + get_zfcp_lun_path(id, autoconf); /* Get previous rule data. */ luns = zfcp_lun_node_list_new(); @@ -664,26 +666,28 @@ static exit_code_t update_lun_rule(const char *id, struct device_state *state, /* Write a udev-rule to configure the specified zfcp lun and associated * device state. */ -exit_code_t udev_zfcp_lun_write_device(struct device *dev) +exit_code_t udev_zfcp_lun_write_device(struct device *dev, bool autoconf) { exit_code_t rc; + struct device_state *state = autoconf ? &dev->autoconf : + &dev->persistent; - rc = update_lun_rule(dev->id, &dev->persistent, true); + rc = update_lun_rule(dev->id, state, true, autoconf); /* We only want single lun rule files so remove any remaining * references in multi lun rule files. */ - update_lun_rule(dev->id, NULL, false); + update_lun_rule(dev->id, NULL, false, autoconf); return rc; } /* Remove the UDEV rule used to configure the zfcp lun with the specified ID. */ -exit_code_t udev_zfcp_lun_remove_rule(const char *id) +exit_code_t udev_zfcp_lun_remove_rule(const char *id, bool autoconf) { exit_code_t rc, rc2; - rc = update_lun_rule(id, NULL, true); - rc2 = update_lun_rule(id, NULL, false); + rc = update_lun_rule(id, NULL, true, autoconf); + rc2 = update_lun_rule(id, NULL, false, autoconf); if (rc) return rc; @@ -692,7 +696,7 @@ exit_code_t udev_zfcp_lun_remove_rule(const char *id) } /* Determine if a udev rule exists for configuring the specified zfcp lun. */ -bool udev_zfcp_lun_exists(const char *id) +bool udev_zfcp_lun_exists(const char *id, bool autoconf) { struct zfcp_lun_devid devid; char *path, *rule = NULL, *pattern = NULL; @@ -702,7 +706,7 @@ bool udev_zfcp_lun_exists(const char *id) return false; /* Check for single lun rule file first. */ - path = get_single_zfcp_lun_path(id); + path = get_single_zfcp_lun_path(id, autoconf); if (util_path_exists(path)) { rc = true; goto out; @@ -710,7 +714,7 @@ bool udev_zfcp_lun_exists(const char *id) free(path); /* Check multi lun rule file next. */ - path = get_zfcp_lun_path(id); + path = get_zfcp_lun_path(id, autoconf); rule = misc_read_text_file(path, 1, err_ignore); if (!rule) goto out; diff --git a/zdev/src/zfcp_lun.c b/zdev/src/zfcp_lun.c index 0c266821..d5a148e6 100644 --- a/zdev/src/zfcp_lun.c +++ b/zdev/src/zfcp_lun.c @@ -467,7 +467,14 @@ static exit_code_t zfcp_lun_st_read_persistent(struct subtype *st, struct device *dev, read_scope_t scope) { - return udev_zfcp_lun_read_device(dev); + return udev_zfcp_lun_read_device(dev, false); +} + +static exit_code_t zfcp_lun_st_read_autoconf(struct subtype *st, + struct device *dev, + read_scope_t scope) +{ + return udev_zfcp_lun_read_device(dev, true); } static exit_code_t zfcp_lun_add(struct device *dev) @@ -564,7 +571,13 @@ static exit_code_t zfcp_lun_st_configure_active(struct subtype *st, static exit_code_t zfcp_lun_st_configure_persistent(struct subtype *st, struct device *dev) { - return udev_zfcp_lun_write_device(dev); + return udev_zfcp_lun_write_device(dev, false); +} + +static exit_code_t zfcp_lun_st_configure_autoconf(struct subtype *st, + struct device *dev) +{ + return udev_zfcp_lun_write_device(dev, true); } static exit_code_t zfcp_lun_st_deconfigure_active(struct subtype *st, @@ -578,7 +591,13 @@ static exit_code_t zfcp_lun_st_deconfigure_active(struct subtype *st, static exit_code_t zfcp_lun_st_deconfigure_persistent(struct subtype *st, struct device *dev) { - return udev_zfcp_lun_remove_rule(dev->id); + return udev_zfcp_lun_remove_rule(dev->id, false); +} + +static exit_code_t zfcp_lun_st_deconfigure_autoconf(struct subtype *st, + struct device *dev) +{ + return udev_zfcp_lun_remove_rule(dev->id, true); } static exit_code_t check_npiv(struct subtype *st, struct device *dev, @@ -606,7 +625,8 @@ static exit_code_t check_npiv(struct subtype *st, struct device *dev, if (!allow_lun_scan) goto out; - if (!(dev->active.deconfigured || dev->persistent.deconfigured)) { + if (!(dev->active.deconfigured || dev->persistent.deconfigured || + dev->autoconf.deconfigured)) { delayed_info("Note: Auto LUN scan enabled - manual LUN " "configuration is redundant for %s %s\n", zfcp_host_subtype.devname, fcp_dev_id); @@ -643,7 +663,8 @@ static exit_code_t zfcp_lun_st_check_post_configure(struct subtype *st, /* Don't show note when an attribute was modified. */ if (setting_list_modified(dev->active.settings) || - setting_list_modified(dev->persistent.settings)) + setting_list_modified(dev->persistent.settings) || + setting_list_modified(dev->autoconf.settings)) return EXIT_OK; /* Check for NPIV but don't route exit code to caller - we only @@ -795,7 +816,12 @@ static bool zfcp_lun_st_exists_active(struct subtype *st, const char *id) static bool zfcp_lun_st_exists_persistent(struct subtype *st, const char *id) { - return udev_zfcp_lun_exists(id); + return udev_zfcp_lun_exists(id, false); +} + +static bool zfcp_lun_st_exists_autoconf(struct subtype *st, const char *id) +{ + return udev_zfcp_lun_exists(id, true); } static exit_code_t zfcp_lun_st_is_definable(struct subtype *st, const char *id, @@ -889,7 +915,13 @@ static void zfcp_lun_st_add_active_ids(struct subtype *st, static void zfcp_lun_st_add_persistent_ids(struct subtype *st, struct util_list *ids) { - udev_zfcp_lun_add_device_ids(ids); + udev_zfcp_lun_add_device_ids(ids, false); +} + +static void zfcp_lun_st_add_autoconf_ids(struct subtype *st, + struct util_list *ids) +{ + udev_zfcp_lun_add_device_ids(ids, true); } static exit_code_t add_sg_cb(const char *path, const char *filename, void *data) @@ -1072,18 +1104,23 @@ struct subtype zfcp_lun_subtype = { .exists_active = &zfcp_lun_st_exists_active, .exists_persistent = &zfcp_lun_st_exists_persistent, + .exists_autoconf = &zfcp_lun_st_exists_autoconf, .add_active_ids = &zfcp_lun_st_add_active_ids, .add_persistent_ids = &zfcp_lun_st_add_persistent_ids, + .add_autoconf_ids = &zfcp_lun_st_add_autoconf_ids, .read_active = &zfcp_lun_st_read_active, .read_persistent = &zfcp_lun_st_read_persistent, + .read_autoconf = &zfcp_lun_st_read_autoconf, .configure_active = &zfcp_lun_st_configure_active, .configure_persistent = &zfcp_lun_st_configure_persistent, + .configure_autoconf = &zfcp_lun_st_configure_autoconf, .deconfigure_active = &zfcp_lun_st_deconfigure_active, .deconfigure_persistent = &zfcp_lun_st_deconfigure_persistent, + .deconfigure_autoconf = &zfcp_lun_st_deconfigure_autoconf, .check_pre_configure = &zfcp_lun_st_check_pre_configure, .check_post_configure = &zfcp_lun_st_check_post_configure,