forked from pool/s390-tools
5500b3a5bc
- Added the following patches for Fate#326825 (bsc#1113329) I/O device pre-configuration * s390-tools-sles15sp1-01-zdev-use-libutil-provided-path-functions.patch * s390-tools-sles15sp1-02-zdev-Prepare-for-firmware-configuration-file-support.patch * s390-tools-sles15sp1-03-zdev-Add-support-for-reading-firmware-configuration-.patch * s390-tools-sles15sp1-04-zdev-Implement-no-settle.patch * s390-tools-sles15sp1-05-zdev-Write-zfcp-lun-udev-rules-to-separate-files.patch * s390-tools-sles15sp1-06-zdev-Add-support-for-handling-auto-configuration-dat.patch * s390-tools-sles15sp1-07-zdev-Integrate-firmware-auto-configuration-with-drac.patch * s390-tools-sles15sp1-08-zdev-Integrate-firmware-auto-configuration-with-init.patch * s390-tools-sles15sp1-09-zdev-Implement-internal-device-attributes.patch * s390-tools-sles15sp1-10-zdev-Implement-support-for-early-device-configuratio.patch * s390-tools-sles15sp1-11-zdev-Do-not-call-zipl-on-initrd-update.patch - Removed the obsolete customize-zdev-root-update-script.patch - Replaced s390-tools-sles15-zdev-fix-qeth-BridgePort-and-VNICC-conflict-checking.patch with s390-tools-sles15sp1-zdev-fix-qeth-BridgePort-and-VNICC-conflict-checking.patch to fit the current version. OBS-URL: https://build.opensuse.org/request/show/655900 OBS-URL: https://build.opensuse.org/package/show/Base:System/s390-tools?expand=0&rev=61
3041 lines
99 KiB
Diff
3041 lines
99 KiB
Diff
Subject: zdev: Add support for handling auto-configuration data
|
|
From: Peter Oberparleiter <oberpar@linux.ibm.com>
|
|
|
|
Summary: zdev: Add support for handling I/O configuration data
|
|
Description: LPARs that are running in IBM Dynamic Partition Manager (DPM) mode
|
|
can access a firmware-generated I/O configuration data file that
|
|
contains s390-specific information about available I/O devices
|
|
such as qeth device numbers and parameters, and FCP device IDs.
|
|
|
|
This data file is intended to remove the need for users to
|
|
manually enter the corresponding device data during installation.
|
|
|
|
Linux kernels with the corresponding support make the I/O
|
|
configuration data available at the following location:
|
|
|
|
/sys/firmware/sclp_sd/config/data
|
|
|
|
This patch set adds support for handling this data file using the
|
|
chzdev and lszdev tools:
|
|
|
|
- I/O configuration data can be applied using chzdev's --import
|
|
option
|
|
- Initial RAM-Disk scripts automatically apply the
|
|
I/O configuration data to the system configuration
|
|
- lszdev can be used to display the applied auto-configuration
|
|
data
|
|
- chzdev can be used to manually override the
|
|
auto-configuration data
|
|
|
|
Upstream-ID: fe68ec513dc1c73c1961f4e15b83d51291df20eb
|
|
Problem-ID: LS1604
|
|
|
|
Upstream-Description:
|
|
|
|
zdev: Add support for handling auto-configuration data
|
|
|
|
Auto-configuration is the name of a new configuration target that is
|
|
supported by chzdev and lszdev besides the existing active and
|
|
persistent configuration targets. Directives created in this new
|
|
configuration are stored as udev rules in the /run/udev/rules.d
|
|
directory.
|
|
|
|
Auto-configuration directives are only in effect if there are no
|
|
directives for the same device in the user-provided persistent
|
|
configuration. This allows users to override auto-configuration
|
|
directives if necessary.
|
|
|
|
Due to the volatile nature of the /run directory, auto-configuration
|
|
directives are cleared on reboot. Therefore mechanisms that generate
|
|
auto-configuration directives must recreate them on every boot.
|
|
|
|
The lszdev tool displays auto-configuration data both in list view
|
|
as well as in detail view. Users can specify the new option --auto-conf
|
|
to only show data from this configuration target.
|
|
|
|
Mechanisms that generate automated configuration directives can use
|
|
chzdev together with the --auto-conf option to create the corresponding
|
|
udev rules.
|
|
|
|
Note: This change does not include a mechanism that generates
|
|
auto-configuration directives.
|
|
|
|
Signed-off-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
|
|
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
|
|
|
|
|
|
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
|
|
---
|
|
zdev/include/device.h | 4
|
|
zdev/include/misc.h | 28 +++---
|
|
zdev/include/path.h | 5 -
|
|
zdev/include/setting.h | 3
|
|
zdev/include/subtype.h | 22 ++++
|
|
zdev/include/udev.h | 5 -
|
|
zdev/include/udev_ccw.h | 8 -
|
|
zdev/include/udev_ccwgroup.h | 12 +-
|
|
zdev/include/udev_zfcp_lun.h | 10 +-
|
|
zdev/man/chzdev.8 | 16 +++
|
|
zdev/man/lszdev.8 | 22 +++-
|
|
zdev/src/ccw.c | 99 ++++++++++++++++++---
|
|
zdev/src/ccwgroup.c | 76 ++++++++++++++--
|
|
zdev/src/chzdev.c | 162 +++++++++++++++++++++++------------
|
|
zdev/src/chzdev_usage.txt | 1
|
|
zdev/src/dasd.c | 48 +++++-----
|
|
zdev/src/device.c | 55 +++++++++++
|
|
zdev/src/export.c | 96 +++++++++++++++-----
|
|
zdev/src/firmware.c | 6 +
|
|
zdev/src/lszdev.c | 154 +++++++++++++++++++++++++--------
|
|
zdev/src/lszdev_usage.txt | 1
|
|
zdev/src/misc.c | 25 +++--
|
|
zdev/src/path.c | 14 +--
|
|
zdev/src/qeth.c | 32 ++++++
|
|
zdev/src/select.c | 17 ++-
|
|
zdev/src/setting.c | 14 ++-
|
|
zdev/src/subtype.c | 83 +++++++++++++++++
|
|
zdev/src/udev.c | 9 +
|
|
zdev/src/udev_ccw.c | 30 +++---
|
|
zdev/src/udev_ccwgroup.c | 41 ++++----
|
|
zdev/src/udev_zfcp_lun.c | 46 +++++----
|
|
zdev/src/zfcp_lun.c | 51 +++++++++--
|
|
32 files changed, 910 insertions(+), 285 deletions(-)
|
|
|
|
--- 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_lis
|
|
struct setting_list *device_get_setting_list(struct device *dev,
|
|
config_t config);
|
|
|
|
+config_t device_get_config(struct device *dev);
|
|
+
|
|
#endif /* DEVICE_H */
|
|
--- 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 c
|
|
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);
|
|
--- 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 *,
|
|
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 *);
|
|
--- a/zdev/include/setting.h
|
|
+++ b/zdev/include/setting.h
|
|
@@ -94,7 +94,8 @@ void setting_list_map_values(struct sett
|
|
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 */
|
|
--- a/zdev/include/subtype.h
|
|
+++ b/zdev/include/subtype.h
|
|
@@ -67,17 +67,22 @@ typedef exit_code_t (*subtype_cb_t)(stru
|
|
*
|
|
* @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);
|
|
--- a/zdev/include/udev.h
|
|
+++ b/zdev/include/udev.h
|
|
@@ -40,8 +40,9 @@ exit_code_t udev_read_file(const char *,
|
|
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);
|
|
|
|
--- 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 */
|
|
--- 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 */
|
|
--- 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 */
|
|
--- a/zdev/man/chzdev.8
|
|
+++ b/zdev/man/chzdev.8
|
|
@@ -428,8 +428,8 @@ using the \-\-import action like in the
|
|
.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 unav
|
|
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.
|
|
|
|
--- a/zdev/man/lszdev.8
|
|
+++ b/zdev/man/lszdev.8
|
|
@@ -69,12 +69,13 @@ With no further options specified, the o
|
|
.
|
|
.
|
|
.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
|
|
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.
|
|
|
|
--- a/zdev/src/ccw.c
|
|
+++ b/zdev/src/ccw.c
|
|
@@ -892,12 +892,13 @@ static exit_code_t collect_group_cb(stru
|
|
}
|
|
|
|
/* 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 *
|
|
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 = 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_
|
|
}
|
|
|
|
/* 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
|
|
/* 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
|
|
* 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_persisten
|
|
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_acti
|
|
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_ac
|
|
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 sub
|
|
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 sub
|
|
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(stru
|
|
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,
|
|
|
|
--- a/zdev/src/ccwgroup.c
|
|
+++ b/zdev/src/ccwgroup.c
|
|
@@ -426,6 +426,8 @@ static void ccwgroup_st_online_set(struc
|
|
}
|
|
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_lis
|
|
}
|
|
|
|
/* 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
|
|
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_pers
|
|
|
|
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
|
|
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
|
|
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_deconfigu
|
|
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(st
|
|
|
|
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(s
|
|
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,
|
|
--- 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_lis
|
|
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
|
|
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
|
|
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 s
|
|
/* 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(str
|
|
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_setting
|
|
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
|
|
|
|
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(str
|
|
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 devi
|
|
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
|
|
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
|
|
|
|
/* 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
|
|
|
|
/* 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 subt
|
|
*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 subt
|
|
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 sub
|
|
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 sub
|
|
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 sub
|
|
&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(s
|
|
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 su
|
|
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(str
|
|
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(str
|
|
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_devic
|
|
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_devic
|
|
* 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_devic
|
|
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(struc
|
|
|
|
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,
|
|
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
|
|
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
|
|
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(struc
|
|
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)
|
|
--- 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
|
|
--- a/zdev/src/dasd.c
|
|
+++ b/zdev/src/dasd.c
|
|
@@ -316,34 +316,34 @@ static struct attrib dasd_attr_safe_offl
|
|
* DASD subtype methods.
|
|
*/
|
|
|
|
-/* Check if use_diag setting can be correctly applied. */
|
|
-static exit_code_t check_use_diag(struct device *dev, config_t config)
|
|
+static bool _check_use_diag(struct setting_list *list)
|
|
{
|
|
struct setting *u;
|
|
- int zvm = is_zvm();
|
|
|
|
- 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;
|
|
- }
|
|
+ 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)
|
|
+{
|
|
+ if (is_zvm())
|
|
+ return EXIT_OK;
|
|
+
|
|
+ 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 s
|
|
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);
|
|
--- a/zdev/src/device.c
|
|
+++ b/zdev/src/device.c
|
|
@@ -40,6 +40,7 @@ struct device *device_new(struct subtype
|
|
|
|
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, in
|
|
setting_list_print(dev->persistent.settings, level + 8);
|
|
else
|
|
printf("%*s<none>\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<none>\n", level + 8, "");
|
|
}
|
|
|
|
static const void *device_hash_get_id(void *dev_ptr)
|
|
@@ -182,6 +193,10 @@ bool device_needs_writing(struct device
|
|
(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
|
|
/* 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
|
|
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, co
|
|
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
|
|
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_
|
|
|
|
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;
|
|
+}
|
|
--- a/zdev/src/export.c
|
|
+++ b/zdev/src/export.c
|
|
@@ -83,7 +83,7 @@ static bool is_exportable(struct setting
|
|
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 devic
|
|
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
|
|
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
|
|
!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 *f
|
|
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 c
|
|
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
|
|
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 *
|
|
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;
|
|
}
|
|
--- a/zdev/src/firmware.c
|
|
+++ b/zdev/src/firmware.c
|
|
@@ -360,6 +360,8 @@ static void add_setting(const char *file
|
|
_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
|
|
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;
|
|
}
|
|
--- 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
|
|
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
|
|
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
|
|
"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
|
|
"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
|
|
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
|
|
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 d
|
|
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 *i
|
|
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 opt
|
|
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 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
|
|
/* 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(struc
|
|
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_
|
|
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_
|
|
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(vo
|
|
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(vo
|
|
|
|
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
|
|
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
|
|
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 o
|
|
}
|
|
} 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 de
|
|
{
|
|
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 de
|
|
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 de
|
|
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 de
|
|
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 de
|
|
|
|
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(struc
|
|
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(struc
|
|
|
|
/* 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(struc
|
|
/* 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");
|
|
--- 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
|
|
--- 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 confi
|
|
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, conf
|
|
*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
|
|
--- a/zdev/src/path.c
|
|
+++ b/zdev/src/path.c
|
|
@@ -297,21 +297,25 @@ char *path_get_ccwgroup_devices(const ch
|
|
}
|
|
|
|
/* 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. */
|
|
--- a/zdev/src/qeth.c
|
|
+++ b/zdev/src/qeth.c
|
|
@@ -1207,7 +1207,7 @@ static exit_code_t check_layer2(struct d
|
|
{
|
|
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 d
|
|
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 d
|
|
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_con
|
|
|
|
/* 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);
|
|
--- a/zdev/src/select.c
|
|
+++ b/zdev/src/select.c
|
|
@@ -248,12 +248,13 @@ static void unblacklist_devices(struct s
|
|
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(struc
|
|
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(struc
|
|
|
|
/* 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 sub
|
|
|
|
/* 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);
|
|
|
|
--- a/zdev/src/setting.c
|
|
+++ b/zdev/src/setting.c
|
|
@@ -646,7 +646,8 @@ static void add_changes(struct util_list
|
|
|
|
/* 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;
|
|
@@ -662,6 +663,17 @@ char *setting_get_changes(struct setting
|
|
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 (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;
|
|
--- a/zdev/src/subtype.c
|
|
+++ b/zdev/src/subtype.c
|
|
@@ -195,6 +195,13 @@ bool subtype_device_exists_persistent(st
|
|
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 s
|
|
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_persiste
|
|
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_per
|
|
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_p
|
|
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 *
|
|
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 *s
|
|
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 subtyp
|
|
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
|
|
}
|
|
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 su
|
|
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
|
|
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;
|
|
}
|
|
--- a/zdev/src/udev.c
|
|
+++ b/zdev/src/udev.c
|
|
@@ -360,7 +360,8 @@ static bool get_ids_cb(const char *filen
|
|
|
|
/* 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 *typ
|
|
|
|
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);
|
|
--- 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, c
|
|
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(struc
|
|
}
|
|
|
|
/* 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 *pr
|
|
}
|
|
|
|
/* 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
|
|
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
|
|
/* 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. */
|
|
--- 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
|
|
}
|
|
|
|
/* 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 *pr
|
|
}
|
|
|
|
/* 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(s
|
|
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
|
|
|
|
/* 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
|
|
}
|
|
|
|
/* 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(co
|
|
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);
|
|
--- 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 *pa
|
|
|
|
/* 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
|
|
|
|
/* 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 cha
|
|
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 cha
|
|
|
|
/* 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(struc
|
|
}
|
|
|
|
/* 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
|
|
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
|
|
|
|
/* 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(co
|
|
}
|
|
|
|
/* 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;
|
|
--- a/zdev/src/zfcp_lun.c
|
|
+++ b/zdev/src/zfcp_lun.c
|
|
@@ -467,7 +467,14 @@ static exit_code_t zfcp_lun_st_read_pers
|
|
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
|
|
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_deconfigu
|
|
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 sub
|
|
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_pos
|
|
|
|
/* 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(st
|
|
|
|
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(s
|
|
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,
|