From c8ad5f57d0fc83315ee4bbdf22b97ee86d81797d Mon Sep 17 00:00:00 2001 From: Vineeth Vijayan Date: Thu, 18 Aug 2022 07:12:03 +0200 Subject: [PATCH] zdev: modify zdev_id to read the site_id from loadparm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The currently active site can be found from the loadparm attribute which is located at /sys/firmware/ipl/loadparm. Read the value of loadparm and extract the site_id. The loadparm is an 8 byte alphanumerical IPL parameter. The content of loadparm can be of different forms to indicate different boot menu options, which are used by Linux for selecting the respective boot menu entries. To indicate the site-id, loadparm adds a 'S' character. Where, the following character after 'S' indicates either the site-id or indivcation to derive the site-id from SSID. For example, If the loadparm value is Sn,'n' is the integer which could be one of the valid site_ids from 0 to 9; i.e when booted on site-1, loadparm value will be S1. If loadparm value is "SS", zdev_id extracts the site_id from the SSID of the current ipl device. For ccw and zfcp devices, the current ipl device-id can be found at /sys/firmware/ipl/device. In any case, if the loadparm contains invalid value, or empty, the site_id will be default to the common-site. After the first invocation of the zdev_id from udev-rule, the site-id information is stored in /run/zdev_id.env file. This will reduce the number of further invocation of zdev_id from within udev-rules. Reviewed-by: Peter Oberparleiter Signed-off-by: Vineeth Vijayan Signed-off-by: Jan Höppner --- zdev/include/zdev_id.h | 15 +++++ zdev/src/zdev_id.c | 134 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 zdev/include/zdev_id.h diff --git a/zdev/include/zdev_id.h b/zdev/include/zdev_id.h new file mode 100644 index 00000000..20f70718 --- /dev/null +++ b/zdev/include/zdev_id.h @@ -0,0 +1,15 @@ +/* + * zdev - Modify and display the persistent configuration of devices + * + * Copyright IBM Corp. 2022 + * + * s390-tools is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef ZDEV_ID_H +#define ZDEV_ID_H + +#define ZDEV_SITE_ID_FILE "/run/zdev_id.env" + +#endif /* ZDEV_ID_H */ diff --git a/zdev/src/zdev_id.c b/zdev/src/zdev_id.c index 84c7ff1c..c341d31c 100644 --- a/zdev/src/zdev_id.c +++ b/zdev/src/zdev_id.c @@ -11,9 +11,17 @@ #include #include #include +#include + +#include "zdev_id.h" #define SYSINFO "/proc/sysinfo" #define CMDLINE "/proc/cmdline" +#define LOADPARM "/sys/firmware/ipl/loadparm" +#define IPL_DEV_ID "/sys/firmware/ipl/device" +#define IPL_DEV_TYPE "/sys/firmware/ipl/ipl_type" +#define SITE_FALLBACK 10 + #define WHITESPACE " \t\n" static void array_add(char ***array_p, int *num_p, const char *str) @@ -140,15 +148,139 @@ out: printf("ZDEV_NO_AUTO=%d\n", no_auto); } +/* + * If the erraneous loadparm provides a site_id which is not valid, + * default it to the common-site id. + */ +static int validate_site(int site_id) +{ + if (site_id < SITE_FALLBACK) + return site_id; + return SITE_FALLBACK; +} + +/* get the ipl device and extract the SSID */ +static int get_site_id(void) +{ + FILE *fd; + char *line; + size_t n; + int site_id = SITE_FALLBACK, ssid; + + fd = fopen(IPL_DEV_ID, "r"); + if (!fd) + goto fail_safe; + + if (getline(&line, &n, fd) == -1) + goto out; + + if (sscanf(line, "%*d.%d.%*d", &ssid) == 1) + site_id = validate_site(ssid); + +out: + free(line); + fclose(fd); +fail_safe: + return site_id; +} + +/* + * Find the ipl type and see if it belongs to ccw or zfcp, if different, + * default it to common-site. + */ +static int read_ssid(void) +{ + FILE *fd; + char *line = NULL; + size_t n; + int site_id = SITE_FALLBACK; + + fd = fopen(IPL_DEV_TYPE, "r"); + if (!fd) + goto out; + + if (getline(&line, &n, fd) != -1) { + if (strcmp(line, "ccw") == 0 || strcmp(line, "zfcp")) + site_id = get_site_id(); + } + + free(line); + fclose(fd); +out: + return site_id; +} + +static void write_zdev_site_id(int site_id) +{ + FILE *fd; + + fd = fopen(ZDEV_SITE_ID_FILE, "w"); + if (!fd) + err(1, "Could not write to zdev_site_id file"); + if (site_id == SITE_FALLBACK) + fprintf(fd, "ZDEV_SITE_ID=\n"); + else + fprintf(fd, "ZDEV_SITE_ID=%d\n", site_id); + + fclose(fd); +} + +/* Read the loadparm and extract the current site_id. + * loadparm can contains either Sn or "Ss". Sn indicate the site_id, where + * 'n' is the integer which could be one of the valid site_ids from 0 to 9. + * When loadparm value is "Ss", zdev_id extracts the site_id from the SSID + * of the current ipl device. For ccw and zfcp devices, the current ipl + * device-id can be found at /sys/firmware/ipl/device. + * For all other invalid cases, set ZDEV_SITE_ID to NULL. + */ + +static void process_loadparm(const char *filename) +{ + size_t n; + FILE *fd; + char *line = NULL, *substr; + int site_id = SITE_FALLBACK; + + fd = fopen(filename, "r"); + if (!fd) + goto out; + + /* + * We expect the value here to be either SX, where X is the site-id + * or SS,in which case, the site-id will be derived from the SSID + */ + if ((getline(&line, &n, fd)) != -1) { + substr = strchr(line, 'S'); + if (!substr) + goto out; + + if (isdigit(substr[1])) + site_id = validate_site(atoi(&substr[1])); + else if (substr[1] == 'S') + site_id = read_ssid(); + } + + free(line); + fclose(fd); +out: + write_zdev_site_id(site_id); + if (site_id == SITE_FALLBACK) + printf("ZDEV_SITE_ID=\n"); + else + printf("ZDEV_SITE_ID=%d\n", site_id); +} + int main(int argc, char *argv[]) { - char *sysinfo, *cmdline; + char *sysinfo, *cmdline, *loadparm; sysinfo = argc < 2 ? SYSINFO : argv[1]; cmdline = argc < 3 ? CMDLINE : argv[2]; + loadparm = argc < 4 ? LOADPARM : argv[3]; process_sysinfo(sysinfo); process_cmdline(cmdline); + process_loadparm(loadparm); return 0; }