From 7673ee7d1ce6786a5471ead15513d62027c9756a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Ter=C3=A4s?= Date: Wed, 23 Nov 2016 15:01:15 +0200 Subject: nlplug-findfs: speed up and simplify boot media finding --- nlplug-findfs.c | 221 +++++++++++++++++++++++++++----------------------------- 1 file changed, 105 insertions(+), 116 deletions(-) diff --git a/nlplug-findfs.c b/nlplug-findfs.c index 9dd572a..7907389 100644 --- a/nlplug-findfs.c +++ b/nlplug-findfs.c @@ -1,4 +1,3 @@ - /* * Copy me if you can. * by 20h @@ -14,9 +13,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -619,71 +618,85 @@ static int is_mounted(const char *devnode) { } struct recurse_opts { - const char *searchname; - int matchdirs, matchdepth; + size_t pathlen; + char path[PATH_MAX], *filename; + int is_dir; + int matchdepth; int curdepth, maxdepth; - void (*callback)(char *pathbuf, size_t pathlen, void *userdata); + void (*callback)(struct recurse_opts *opts, void *userdata); void *userdata; }; -/* pathbuf needs hold PATH_MAX chars */ -static void do_recurse_dir(char *pathbuf, struct recurse_opts *opts) +static int recurse_push(struct recurse_opts *opts, size_t *oldlen, const char *path) +{ + size_t pathlen = strlen(path); + if (opts->pathlen + 1 + pathlen + 1 >= sizeof opts->path) + return 0; + *oldlen = opts->pathlen; + opts->path[opts->pathlen++] = '/'; + strcpy(&opts->path[opts->pathlen], path); + opts->pathlen += strlen(path); + return 1; +} + +static void recurse_pop(struct recurse_opts *opts, size_t len) +{ + opts->pathlen = len; + opts->path[len] = 0; +} + +static void do_recurse_dir(struct recurse_opts *opts) { - size_t pathlen, namelen; + size_t oldlen; struct dirent *entry; DIR *d; int is_dir; - d = opendir(pathbuf); + d = opendir(opts->path); if (!d) return; - pathlen = strlen(pathbuf); while ((entry = readdir(d)) != NULL) { if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; - namelen = strlen(entry->d_name); - if (pathlen + 2 + namelen > PATH_MAX) { - dbg("path length overflow"); + if (!recurse_push(opts, &oldlen, entry->d_name)) continue; - } - - pathbuf[pathlen] = '/'; - strcpy(&pathbuf[pathlen+1], entry->d_name); if (entry->d_type == DT_UNKNOWN) { /* some filesystems like iso9660 does not support the d_type so we use lstat */ struct stat st; - if (lstat(pathbuf, &st) < 0) { - dbg("%s: %s", pathbuf, strerror(errno)); + if (lstat(opts->path, &st) < 0) { + dbg("%s: %s", opts->path, strerror(errno)); goto next; } is_dir = S_ISDIR(st.st_mode); } else is_dir = entry->d_type & DT_DIR; - if ((opts->matchdirs || !is_dir) && - (opts->matchdepth == 0 || opts->matchdepth == opts->curdepth) && - (!opts->searchname || strcmp(entry->d_name, opts->searchname) == 0)) - opts->callback(pathbuf, pathlen+1+namelen, opts->userdata); + if (opts->matchdepth == 0 || opts->matchdepth == opts->curdepth) { + opts->filename = &opts->path[oldlen+1]; + opts->is_dir = is_dir; + opts->callback(opts, opts->userdata); + } if (is_dir && opts->curdepth < opts->maxdepth) { opts->curdepth++; - do_recurse_dir(pathbuf, opts); + do_recurse_dir(opts); opts->curdepth--; } next: - pathbuf[pathlen] = '\0'; + recurse_pop(opts, oldlen); } closedir(d); } -static void recurse_dir(char *pathbuf, struct recurse_opts *opts) +static void recurse_dir(struct recurse_opts *opts) { + opts->pathlen = strlen(opts->path); opts->curdepth = 1; - do_recurse_dir(pathbuf, opts); + do_recurse_dir(opts); } struct trigger_entry { @@ -692,22 +705,20 @@ struct trigger_entry { char pathname[]; }; -static void trigger_uevent_cb(char *path, size_t pathlen, void *data) +static void trigger_uevent_cb(struct recurse_opts *opts, void *data) { + size_t oldlen; int fd; - if (pathlen + 1 + strlen("/uevent") > PATH_MAX) { - dbg("path length overflow"); + if (!recurse_push(opts, &oldlen, "uevent")) return; - } - strcpy(&path[pathlen], "/uevent"); - fd = open(path, O_WRONLY); + fd = open(opts->path, O_WRONLY); if (fd >= 0) { write(fd, "add", 3); close(fd); } - path[pathlen] = 0; + recurse_pop(opts, oldlen); } static void trigger_path(struct ueventconf *conf, char *path, char *subdir, int max_depth) @@ -735,8 +746,6 @@ static void *trigger_thread(void *data) struct ueventconf *conf = data; struct recurse_opts opts; struct trigger_entry *entry = NULL; - char path[PATH_MAX] = "/sys"; - size_t prefixlen = strlen(path); while (1) { pthread_mutex_lock(&conf->trigger_mutex); @@ -752,88 +761,74 @@ static void *trigger_thread(void *data) } pthread_mutex_unlock(&conf->trigger_mutex); - /* scan list */ - strcpy(&path[prefixlen], entry->pathname); - dbg("trigger_thread: scanning %s", path); - opts = (struct recurse_opts) { .callback = trigger_uevent_cb, - .matchdirs = 1, .userdata = entry, .maxdepth = entry->max_depth, .matchdepth = entry->max_depth, }; - recurse_dir(path, &opts); + snprintf(opts.path, sizeof opts.path, "/sys%s", entry->pathname); + dbg("trigger_thread: scanning %s", opts.path); + + recurse_dir(&opts); } return NULL; } -struct bootrepos { - char *outfile; - int count; -}; - -static void bootrepo_cb(char *path, size_t pathlen, void *data) +static void append_line(const char *outfile, const char *data) { - struct bootrepos *repos = data; - - int fd = open(repos->outfile, O_WRONLY | O_CREAT | O_APPEND); + int fd; + if (outfile == 0) return; + fd = open(outfile, O_WRONLY | O_CREAT | O_APPEND); if (fd == -1) - err(1, "%s", repos->outfile); - - write(fd, path, strlen(path) - strlen("/.boot_repository")); + err(1, "%s", outfile); + write(fd, data, strlen(data)); write(fd, "\n", 1); close(fd); - dbg("added boot repository %s to %s\n", path, repos->outfile); - repos->count++; } -static int find_apkovl(const char *dir, const char *outfile) -{ - char pattern[PATH_MAX]; - glob_t gl; - int r, fd; - - if (outfile == NULL) - return 0; - - snprintf(pattern, sizeof(pattern), "%s/*.apkovl.tar.gz*", dir); - - r = glob(pattern, 0, NULL, &gl); - if (r != 0) - return 0; - - fd = open(outfile, O_WRONLY | O_CREAT | O_APPEND); - if (fd == -1) - err(1, "%s", outfile); +struct scandevctx { + struct ueventconf *conf; + int found; +}; - for (r = 0; r < gl.gl_pathc; r++) { - dbg("Found apkovl: %s", gl.gl_pathv[r]); - write(fd, gl.gl_pathv[r], strlen(gl.gl_pathv[r])); - write(fd, "\n", 1); +static void scandev_cb(struct recurse_opts *opts, void *data) +{ + struct scandevctx *ctx = data; + struct ueventconf *conf = ctx->conf; + + if (opts->is_dir) { + size_t oldlen; + int ok = 0; + if (recurse_push(opts, &oldlen, ".boot_repository")) { + ok = access(opts->path, F_OK) == 0; + recurse_pop(opts, oldlen); + } + if (ok) { + dbg("added boot repository %s to %s", opts->path, conf->bootrepos); + append_line(conf->bootrepos, opts->path); + ctx->found |= FOUND_BOOTREPO; + } + } else if (fnmatch("*.apkovl.tar.gz*", opts->filename, 0) == 0) { + dbg("found apkovl %s", opts->path); + append_line(conf->apkovls, opts->path); + ctx->found |= FOUND_APKOVL; } - close(fd); - globfree(&gl); - return FOUND_APKOVL; } -static int find_bootrepos(const char *devnode, const char *type, - char *bootrepos, const char *apkovls) +static int scandev(struct ueventconf *conf, const char *devnode, const char *type) { - char mountdir[PATH_MAX] = ""; - char *devname; - int r, rc = 0; - struct bootrepos repos = { - .outfile = bootrepos, - .count = 0, + struct scandevctx ctx = { + .conf = conf, }; struct recurse_opts opts = { - .maxdepth = 2, - .searchname = ".boot_repository", - .callback = bootrepo_cb, - .userdata = &repos, + .maxdepth = 1, + .callback = scandev_cb, + .userdata = &ctx, }; + char *devname; + int r; /* skip already mounted devices */ if (is_mounted(devnode)) { @@ -841,31 +836,26 @@ static int find_bootrepos(const char *devnode, const char *type, return 0; } devname = strrchr(devnode, '/'); + if (!devname) + return 0; - if (devname) - snprintf(mountdir, sizeof(mountdir), "/media%s", devname); - - dbg("mounting %s on %s. (%s)", devnode, mountdir, type); - mkdir(mountdir, 0755); + snprintf(opts.path, sizeof opts.path, "/media%s", devname); + dbg("mounting %s on %s (%s)", devnode, opts.path, type); + mkdir(opts.path, 0755); - r = mount(devnode, mountdir, type, MS_RDONLY, NULL); + r = mount(devnode, opts.path, type, MS_RDONLY, NULL); if (r < 0) { dbg("Failed to mount %s on %s: %s", - devnode, mountdir, strerror(errno)); + devnode, opts.path, strerror(errno)); return 0; } - recurse_dir(mountdir, &opts); - if (repos.count > 0) - rc |= FOUND_BOOTREPO; + recurse_dir(&opts); - if (find_apkovl(mountdir, apkovls)) - rc |= FOUND_APKOVL; + if (ctx.found == 0) + umount(opts.path); - if (rc == 0) - umount(mountdir); - - return rc; + return ctx.found; } static int is_same_device(const struct uevent *ev, const char *nodepath) @@ -904,14 +894,13 @@ static void founddev(struct ueventconf *conf, int found) } } -static int searchdev(struct uevent *ev, const char *searchdev, char *bootrepos, - const char *apkovls) +static int searchdev(struct uevent *ev, const char *searchdev, int scanbootmedia) { struct ueventconf *conf = ev->conf; char *type = NULL, *label = NULL, *uuid = NULL; int rc = 0; - if (searchdev == NULL && bootrepos == NULL && apkovls == NULL) + if (searchdev == NULL && !scanbootmedia) return 0; if (searchdev && (strcmp(ev->devname, searchdev) == 0 @@ -945,8 +934,8 @@ static int searchdev(struct uevent *ev, const char *searchdev, char *bootrepos, start_mdadm(ev->devnode); } else if (strcmp("LVM2_member", type) == 0) { start_lvm2(ev->devnode); - } else if (bootrepos) { - rc = find_bootrepos(ev->devnode, type, bootrepos, apkovls); + } else if (scanbootmedia) { + rc = scandev(conf, ev->devnode, type); } } @@ -974,12 +963,12 @@ static void uevent_handle(struct uevent *ev) snprintf(ev->devnode, sizeof(ev->devnode), "/dev/%s", ev->devname); pthread_mutex_lock(&conf->cryptsetup_mutex); - found = searchdev(ev, conf->search_device, conf->bootrepos, conf->apkovls); + found = searchdev(ev, conf->search_device, 1); pthread_mutex_unlock(&conf->cryptsetup_mutex); if (found) { founddev(conf, found); } else if (conf->crypt.devnode[0] == '\0' && - searchdev(ev, conf->crypt.device, NULL, NULL)) { + searchdev(ev, conf->crypt.device, 0)) { strncpy(conf->crypt.devnode, conf->crypt.device[0] == '/' ? conf->crypt.device : ev->devnode, sizeof(conf->crypt.devnode)); -- cgit v1.2.3