diff --git a/config-parser.h b/config-parser.h index ea29acc..b486ef1 100644 --- a/config-parser.h +++ b/config-parser.h @@ -14,6 +14,10 @@ static inline int conf_construct(conf* c) { c->fs.scoped = (str*)calloc(1, sizeof(str)); c->fstype.val = (str*)calloc(1, sizeof(str)); c->fstype.scoped = (str*)calloc(1, sizeof(str)); +#ifdef SCSI_PROBE + c->scsi_dev.val = (str*)calloc(1, sizeof(str)); + c->scsi_dev.scoped = (str*)calloc(1, sizeof(str)); +#endif return !c->bootfs.val || !c->bootfs.scoped || !c->bootfs_hint.val || !c->bootfs_hint.scoped || !c->bootfstype.val || !c->bootfstype.scoped || !c->fs.val || !c->fs.scoped || @@ -41,6 +45,9 @@ static inline void conf_set_pick(conf* c, str** line) { .len = sizeof("bootfstype") - 1}; const str fs_str = {.c_str = "fs", .len = sizeof("fs") - 1}; const str fstype_str = {.c_str = "fstype", .len = sizeof("fstype") - 1}; +#ifdef SCSI_PROBE + const str devtoscan_str = {.c_str = SCSI_ADDR_BOOT_ARG, .len = sizeof(SCSI_ADDR_BOOT_ARG) - 1}; +#endif if (is_line_key(*line, &bootfs_str)) set_conf(&c->bootfs, line, bootfs_str.len); @@ -52,6 +59,12 @@ static inline void conf_set_pick(conf* c, str** line) { set_conf(&c->fs, line, fs_str.len); else if (is_line_key(*line, &fstype_str)) set_conf(&c->fstype, line, fstype_str.len); +#ifdef SCSI_PROBE + else if (is_line_key(*line, &devtoscan_str)){ + (*line)->c_str[devtoscan_str.len]='='; + set_conf(&c->scsi_dev, line, devtoscan_str.len); + } +#endif } static inline conf* conf_print(conf* c) { @@ -59,11 +72,19 @@ static inline conf* conf_print(conf* c) { printd( "bootfs: {\"%s\", \"%s\"}, bootfs_hint: {\"%s\", \"%s\"}, bootfstype: " "{\"%s\", \"%s\"}, fs: {\"%s\", " - "\"%s\"}, fstype: {\"%s\", \"%s\"}\n", + "\"%s\"}, fstype: {\"%s\", \"%s\"}" +#ifdef SCSI_PROBE + ", scsi_dev: {\"%s\", \"%s\"}" +#endif + "\n", c->bootfs.val->c_str, c->bootfs.scoped->c_str, c->bootfs_hint.val->c_str, c->bootfs_hint.scoped->c_str, c->bootfstype.val->c_str, c->bootfstype.scoped->c_str, c->fs.val->c_str, c->fs.scoped->c_str, - c->fstype.val->c_str, c->fstype.scoped->c_str); + c->fstype.val->c_str, c->fstype.scoped->c_str +#ifdef SCSI_PROBE + , c->scsi_dev.val->c_str, c->scsi_dev.scoped->c_str +#endif + ); #endif return c; } diff --git a/initoverlayfs.c b/initoverlayfs.c index bc2db75..40dc218 100644 --- a/initoverlayfs.c +++ b/initoverlayfs.c @@ -21,6 +21,14 @@ #include #include #include + +#ifdef SCSI_PROBE +#define CMDLINE "/proc/cmdline" +#define SCSI_SYS_TMPL "/sys/class/scsi_host/host%d/scan" +#define SCSI_SYS_TMPL_SZ 40 +#include "scsi_probe/scsi_probe.h" +#include +#endif #include "config-parser.h" #define fork_execl_no_wait(pid, exe, ...) \ @@ -518,7 +526,7 @@ static int switchroot(const char* newroot) { } static int mount_proc_sys_dev(void) { - if (false) { + if (true) { if (mount("proc", "/proc", "proc", MS_NOSUID | MS_NOEXEC | MS_NODEV, NULL)) { print( @@ -599,6 +607,24 @@ int main(int argc, char* argv[]) { return 0; conf_read(&conf, "/etc/initoverlayfs.conf"); +#ifdef SCSI_PROBE + struct args ba; + char cmdline[50]; + FILE *file; + + file = fopen(CMDLINE, "r"); + if (file != NULL) { + if (fgets(cmdline, sizeof(cmdline), file)) { + char *kcmdline = fetch_kernel_cmdline(CMDLINE); + conf_print(&conf); + parse_kernel_cmdline(kcmdline, &ba); + update_scsi_args(conf.scsi_dev.scoped->c_str, &ba); + trigger_scan(&ba, SCSI_SYS_TMPL, SCSI_SYS_TMPL_SZ); + } + fclose(file); + } +#endif + const bool do_bootfs = convert_bootfs(&conf, systemd); convert_fs(&conf); if (systemd) diff --git a/initoverlayfs.h b/initoverlayfs.h index 7b73c42..fbcdde2 100644 --- a/initoverlayfs.h +++ b/initoverlayfs.h @@ -64,6 +64,9 @@ typedef struct conf { pair bootfstype; pair fs; pair fstype; +#ifdef SCSI_PROBE + pair scsi_dev; +#endif } conf; static inline void cleanup_free_conf(conf* p) { @@ -77,7 +80,12 @@ static inline void cleanup_free_conf(conf* p) { free(p->fs.scoped->c_str); if (p->fstype.scoped) free(p->fstype.scoped->c_str); - +#ifdef SCSI_PROBE + if (p->scsi_dev.scoped) + free(p->scsi_dev.scoped->c_str); + free(p->scsi_dev.scoped); + free(p->scsi_dev.val); +#endif free(p->bootfs.scoped); free(p->bootfs_hint.scoped); free(p->bootfstype.scoped); diff --git a/initoverlayfs.spec.in b/initoverlayfs.spec.in index 8f8f3d5..ffc1d4e 100644 --- a/initoverlayfs.spec.in +++ b/initoverlayfs.spec.in @@ -23,7 +23,7 @@ Requires: dracut %build RPM_OPT_FLAGS="${RPM_OPT_FLAGS/-flto=auto /}" -gcc ${RPM_OPT_FLAGS} -lblkid initoverlayfs.c -o initoverlayfs +gcc ${RPM_OPT_FLAGS} -lblkid initoverlayfs.c scsi_probe/scsi_probe.c -o initoverlayfs %install install -D -m755 bin/initoverlayfs-install ${RPM_BUILD_ROOT}/%{_bindir}/initoverlayfs-install diff --git a/scsi_probe/Makefile b/scsi_probe/Makefile new file mode 100644 index 0000000..5f89508 --- /dev/null +++ b/scsi_probe/Makefile @@ -0,0 +1,54 @@ +CC=gcc +CFLAGS= -g +#QUIET = &>/dev/null +VALGRIND_FLAGS= --error-exitcode=1 --leak-check=full -s + +tests: tests_res/parse_kernel_cmdline.exec.log tests_res/parse_kernel_cmdline.valgrind.log tests_res/fetch_kernel_cmdline.exec.log tests_res/fetch_kernel_cmdline.valgrind.log tests_res/trigger_scan.valgrind.log tests_res/trigger_scan.exec.log + +################################################################ +tests_res/parse_kernel_cmdline.exec.log: tests/parse_kernel_cmdline + @echo "======================= Testing... " $< " exec" + @$< > $@ + +tests_res/parse_kernel_cmdline.valgrind.log: tests/parse_kernel_cmdline + @echo "======================= Testing... " $< "valgrind" + @valgrind $(VALGRIND_FLAGS) $< >$@ 2>&1 + +tests/parse_kernel_cmdline: tests/parse_kernel_cmdline.c scsi_probe.o + @echo "======================= Build... " $< + @$(CC) $(CFLAGS) $^ -o $@ + +########################################################################### +tests_res/fetch_kernel_cmdline.exec.log: tests/fetch_kernel_cmdline + @echo "======================= Testing... " $< " exec" + @$< > $@ + +tests_res/fetch_kernel_cmdline.valgrind.log: tests/fetch_kernel_cmdline + @echo "======================= Testing... " $< "valgrind" + @valgrind $(VALGRIND_FLAGS) $< >$@ 2>&1 + +tests/fetch_kernel_cmdline: tests/fetch_kernel_cmdline.c scsi_probe.o + @echo "======================= Build... " $< + @$(CC) $(CFLAGS) $^ -o $@ + +########################################################################### +tests_res/trigger_scan.exec.log: tests/trigger_scan + @echo "======================= Testing... " $< " exec" + @$< > $@ + +tests_res/trigger_scan.valgrind.log: tests/trigger_scan + @echo "======================= Testing... " $< "valgrind" + @valgrind $(VALGRIND_FLAGS) $< >$@ 2>&1 + +tests/trigger_scan: tests/trigger_scan.c scsi_probe.o + @echo "======================= Build... " $< + @$(CC) $(CFLAGS) $^ -o $@ + +########################################################################### +scsi_probe.o: scsi_probe.c scsi_probe.h + @echo "======================= Build... " $< + @$(CC) $(CFLAGS) -c $< -o $@ + +clean: + @echo "======================= CLEAN... " + @rm -f scsi_probe.o tests/parse_kernel_cmdline tests_res/*.log diff --git a/scsi_probe/scsi_probe.c b/scsi_probe/scsi_probe.c new file mode 100644 index 0000000..e649a48 --- /dev/null +++ b/scsi_probe/scsi_probe.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include "scsi_probe.h" + +static int c2i(char *str){ + char *endptr; + int num; + + errno = 0; + num = strtol(str, &endptr, 10); + if ((errno != 0 && num == 0) || (num > 99)) return -1; + if (endptr == str) return -1; + return num; +} + +inline int update_scsi_args(const char *ba_str, struct args *ba){ + char *token; + char *ba_str2; + char *tmp1, *tmp2; + + if (!ba_str) return 0; + if ((ba_str2 = strdup(ba_str)) == NULL) return 0; + token = strtok(ba_str2, " "); + while (token != NULL) { + if (strncmp(token, SCSI_ADDR_BOOT_ARG, strlen(SCSI_ADDR_BOOT_ARG)) == 0) { + tmp1 = strchr(token, '='); + if (tmp1 != NULL) { + tmp2 = tmp1 + 1; + sscanf(tmp2, "%d:%d:%d:%d", &ba->scsi_host, &ba->scsi_channel, &ba->scsi_id, &ba->scsi_lun); + } + } + token = strtok(NULL, " "); + } + free(ba_str2); + return 1; +} + + +int parse_kernel_cmdline(const char *ba_str, struct args *ba){ + memset(ba, 0, sizeof(struct args)); + ba->scsi_manual=strstr(ba_str, "scsi_mod.scan=manual")?1:0; + return update_scsi_args(ba_str, ba); +} + +char *fetch_kernel_cmdline(const char *cmdline_fn){ + FILE *file; + char *cmdline; + + file = fopen(cmdline_fn, "r"); + if (file == NULL) return NULL; + cmdline = (char *) malloc(MAX_BUF); + if (! fgets(cmdline, MAX_BUF, file)) { + free(cmdline); + return NULL; + } + fclose(file); + return cmdline; +} + + +int trigger_scan(struct args *ba, const char *scsi_sys_tmpl, const int scsi_sys_tmpl_sz) { + FILE *file; + char buf[128]; + int n; + + if (ba->scsi_manual==0) return 0; + snprintf(buf, scsi_sys_tmpl_sz, scsi_sys_tmpl, ba->scsi_host); + file = fopen(buf, "w"); + if (file == NULL) return 0; + n = snprintf(buf, MAX_BUF, SCSI_SYS_SCAN_STR, ba->scsi_channel, ba->scsi_id, ba->scsi_lun); + fwrite(buf, n, 1, file); + fclose(file); + return 1; +} diff --git a/scsi_probe/scsi_probe.h b/scsi_probe/scsi_probe.h new file mode 100644 index 0000000..04a0f49 --- /dev/null +++ b/scsi_probe/scsi_probe.h @@ -0,0 +1,19 @@ +#define MAX_ARGS 100 +#define MAX_BUF 128 + +#define SCSI_SYS_SCAN_STR "%d %d %d\n" + +#define SCSI_ADDR_BOOT_ARG "scsi.addr" + +struct args { + int scsi_manual; + int scsi_host; + int scsi_channel; + int scsi_id; + int scsi_lun; +}; + +int update_scsi_args(const char *, struct args *); +int parse_kernel_cmdline(const char *, struct args *); +char *fetch_kernel_cmdline(const char *); +int trigger_scan(struct args *, const char *, const int); diff --git a/scsi_probe/testfiles/cmd1 b/scsi_probe/testfiles/cmd1 new file mode 100644 index 0000000..b7faf75 --- /dev/null +++ b/scsi_probe/testfiles/cmd1 @@ -0,0 +1 @@ +pippo=1 pluto=2 paperino=3 diff --git a/scsi_probe/testfiles/cmd2 b/scsi_probe/testfiles/cmd2 new file mode 100644 index 0000000..0240069 --- /dev/null +++ b/scsi_probe/testfiles/cmd2 @@ -0,0 +1,2 @@ +pippo=1 pluto=2 paperino=3 +pippo=z pluto=x paperino=c diff --git a/scsi_probe/testfiles/host0scan b/scsi_probe/testfiles/host0scan new file mode 100644 index 0000000..b85905e --- /dev/null +++ b/scsi_probe/testfiles/host0scan @@ -0,0 +1 @@ +1 2 3 diff --git a/scsi_probe/testfiles/host2scan b/scsi_probe/testfiles/host2scan new file mode 100644 index 0000000..02c7bd2 --- /dev/null +++ b/scsi_probe/testfiles/host2scan @@ -0,0 +1 @@ +3 4 5 diff --git a/scsi_probe/tests/fetch_kernel_cmdline.c b/scsi_probe/tests/fetch_kernel_cmdline.c new file mode 100644 index 0000000..806cffb --- /dev/null +++ b/scsi_probe/tests/fetch_kernel_cmdline.c @@ -0,0 +1,39 @@ +#include +#include +#include +#include "../scsi_probe.h" + +#define TEST_BUFF_SIZE 200 + +char *results[] = { + "pippo=1 pluto=2 paperino=3\n", + "pippo=1 pluto=2 paperino=3\n", + NULL +}; + +char *test_patterns[] = { + "testfiles/cmd1", + "testfiles/cmd2", + "testfiles/cmd3", +}; + +int main(){ + int i; + char *res; + + for (i=0; i< sizeof(test_patterns)/sizeof(char *); i++) { + res = fetch_kernel_cmdline(test_patterns[i]); + printf( "Test pattern='%s', expected result='%s' Actual result ='%s' -> ", + test_patterns[i], results[i], res); + if (res && results[i]) { + if (strcmp(res, results[i])!=0) { + printf("Failed\n"); + free(res); + return -1; + } + } + printf("Success\n"); + free(res); + } + return 0; +} diff --git a/scsi_probe/tests/parse_kernel_cmdline.c b/scsi_probe/tests/parse_kernel_cmdline.c new file mode 100644 index 0000000..1e6c2d0 --- /dev/null +++ b/scsi_probe/tests/parse_kernel_cmdline.c @@ -0,0 +1,40 @@ +#include +#include +#include "../scsi_probe.h" + +#define TEST_BUFF_SIZE 200 + +char *results[] = { + "has manual=1 host=1 addr=2:3:45", + "has manual=1 host=1 addr=2:3:45", + "has manual=1 host=0 addr=0:0:0", + "has manual=0 host=0 addr=0:0:0" +}; + +char *test_patterns[] = { + "pippo=1 pluto=2 scsi_mod.scan=manual scsi.addr=1:2:3:45 paperino=peppe", + "pippo=1 pluto=2 scsi_mod.scan=manual posw scsi.addr=1:2:3:45 paperino=peppe", + "pippo=1 pluto=2 scsi_mod.scan=manual paperino=peppe", + "pippo=1 pluto=2 paperino=peppe", + +}; + +int main(){ + struct args ba; + int i; + char res[TEST_BUFF_SIZE]; + + for (i=0; i< sizeof(test_patterns)/sizeof(char *); i++) { + if (!parse_kernel_cmdline(test_patterns[i], &ba)) return -1; + sprintf(res, "has manual=%d host=%d addr=%d:%d:%d", ba.scsi_manual, ba.scsi_host, ba.scsi_channel, ba.scsi_id, ba.scsi_lun); + + printf( "Test pattern='%s', expected result='%s' Actual result ='%s' -> ", + test_patterns[i], results[i], res); + if (strcmp(res, results[i])) { + printf("Failed\n"); + return -1; + } + printf("Success\n"); + } + return 0; +} diff --git a/scsi_probe/tests/trigger_scan.c b/scsi_probe/tests/trigger_scan.c new file mode 100755 index 0000000..79f73e7 --- /dev/null +++ b/scsi_probe/tests/trigger_scan.c @@ -0,0 +1,69 @@ +#include +#include +#include "../scsi_probe.h" + +#define TEST_BUFF_SIZE 200 +#define CMDLINE "cmdline" +#define SCSI_SYS_TMPL "testfiles/host%dscan" +#define SCSI_SYS_TMPL_SZ 30 + +struct result { + int res; + char *fn; + char *addr; +}; + +struct result results[] = { + {1, "testfiles/host0scan", "1 2 3\n"}, + {1, "testfiles/host2scan", "3 4 5\n"}, + {0, "testfiles/host0scan", "0 0 0\n"}, +}; + +struct args test_patterns[] = { + {1, 0, 1, 2, 3}, + {1, 2, 3, 4, 5}, + {0, 0, 1, 2, 3}, +}; + +int verify(int res, struct args *test_pattern, struct result *r){ + char buf[100]; + int n; + FILE *file; + + if (res != r->res) return 1; + if (!res) return 0; + printf("trigger_scan ret code OK "); + n = sprintf(buf, SCSI_SYS_TMPL, test_pattern->scsi_host); + printf("comparefns: '%s' '%s' ", buf, r->fn); + if (strncmp(buf, r->fn, n)) return 1; + printf("file to read='%s' ", buf); + file = fopen(buf, "r"); + if (file == NULL) return 1; + n = fread(buf, 100, 1, file); + fclose(file); + + printf("Compare buf=%s expected=%s ", buf, r->addr); + if (strncmp(buf, r->addr, n)) return 1; + return 0; +} + + + + +int main(){ + struct args ba; + int i, r; + char res[TEST_BUFF_SIZE]; + + puts(SCSI_SYS_TMPL); + for (i=0; i< sizeof(test_patterns)/sizeof(struct args); i++) { + printf("%d - ", i); + r = trigger_scan(&test_patterns[i], SCSI_SYS_TMPL, SCSI_SYS_TMPL_SZ); + if (verify(r, &test_patterns[i], &results[i])) { + printf("Failed\n"); + return -1; + } + printf("Success\n"); + } + return 0; +} diff --git a/scsi_probe/tests_res/placeholder b/scsi_probe/tests_res/placeholder new file mode 100644 index 0000000..e69de29