Mike Waychison
2011-Aug-02 22:46 UTC
[klibc] [PATCH v2 0/4] Support drop directories directly from kinit
This patchset applies to klibc mainline. This patchset introduces the ability to kinit to execute scripts or executable files present in in the initramfs before switching over to the root filesystem. It is implemented by first implementing scandir() and alphasort() as present in POSIX.1-2008 in klibc itself, and then using that as the basis for iterating and executing files via a run_scripts() call. This patchset introduces two different drop directories, though this is of course subject to change and these are only presented in an effort to put an example forward. I currently only have a requirement to run stuff between the time we call do_mounts() and the time we call run_init(). These are the directories: /scripts/after-network: ipconfig is completed, but the root filesystem isn't yet mounted. /scripts/after-mount: the root filesystem has just been mounted at /root. I believe this would help both our use-case (where we'd like to do customization of the early-bootup sequence without having to hack kinit too much), and the use case for initramfs-tools, opening the door to replace all the "core" shell there kinit as a C implementation. Thanks, Mike Waychison Changelog ========v2 - Added __extern to alphasort declaration. - Split alphasort() out into alphasort.c and its own patch. Related discussions ================== - We recently had a discussion at: http://www.zytor.com/pipermail/klibc/2011-July/003014.html where I wanted to refactor bits of kinit out so that I could invoke them from a shell script. This patchset is an alternative solution that would allow users of kinit to add custom logic at the intermediate stages without having to have the whole init driven by a shell script. - v1 sendout: http://www.zytor.com/pipermail/klibc/2011-July/003032.html Patchset summary =============== klibc: Add scandir() and alphasort() support. kinit: Add run_scripts() kinit: Add callsites to execute files in drop-directories.
Add support for scandir() as defined in POSIX.1-2008. Signed-off-by: Mike Waychison <mikew at google.com> --- usr/include/dirent.h | 5 ++++ usr/klibc/Kbuild | 2 + usr/klibc/scandir.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletions(-) create mode 100644 usr/klibc/scandir.c diff --git a/usr/include/dirent.h b/usr/include/dirent.h index e324474..0bcf40b 100644 --- a/usr/include/dirent.h +++ b/usr/include/dirent.h @@ -30,4 +30,9 @@ static __inline__ int dirfd(DIR * __d) return __d->__fd; } +__extern int scandir(const char *, struct dirent ***, + int (*)(const struct dirent *), + int (*)(const struct dirent **, + const struct dirent **)); + #endif /* _DIRENT_H */ diff --git a/usr/klibc/Kbuild b/usr/klibc/Kbuild index af40367..40e61da 100644 --- a/usr/klibc/Kbuild +++ b/usr/klibc/Kbuild @@ -42,7 +42,7 @@ klib-y := vsnprintf.o snprintf.o vsprintf.o sprintf.o \ seteuid.o setegid.o \ getenv.o setenv.o putenv.o __put_env.o unsetenv.o \ clearenv.o nullenv.o \ - getopt.o getopt_long.o readdir.o remove.o \ + getopt.o getopt_long.o readdir.o scandir.o remove.o \ syslog.o closelog.o pty.o getpt.o posix_openpt.o isatty.o reboot.o \ time.o utime.o llseek.o nice.o getpriority.o \ qsort.o bsearch.o \ diff --git a/usr/klibc/scandir.c b/usr/klibc/scandir.c new file mode 100644 index 0000000..9b95980 --- /dev/null +++ b/usr/klibc/scandir.c @@ -0,0 +1,71 @@ +/* + * scandir.c: scandir + */ + +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <dirent.h> + +int scandir(const char *dirp, struct dirent ***namelist, + int (*filter)(const struct dirent *), + int (*compar)(const struct dirent **, const struct dirent **)) +{ + struct dirent **nl = NULL, **next_nl; + struct dirent *dirent; + size_t count = 0; + size_t allocated = 0; + DIR *dir; + + dir = opendir(dirp); + if (!dir) + return -1; + + while (1) { + dirent = readdir(dir); + if (!dirent) + break; + if (!filter || filter(dirent)) { + struct dirent *copy; + copy = malloc(sizeof(*copy)); + if (!copy) + goto cleanup_fail; + memcpy(copy, dirent, sizeof(*copy)); + + /* Extend the array if needed */ + if (count == allocated) { + if (allocated == 0) + allocated = 15; /* ~1 page worth */ + else + allocated *= 2; + next_nl = realloc(nl, allocated); + if (!next_nl) { + free(copy); + goto cleanup_fail; + } + nl = next_nl; + } + + nl[count++] = copy; + } + } + + qsort(nl, count, sizeof(struct dirent *), + (int (*)(const void *, const void *))compar); + + closedir(dir); + + *namelist = nl; + return count; + +cleanup_fail: + while (count) { + dirent = nl[--count]; + free(dirent); + } + free(nl); + closedir(dir); + errno = ENOMEM; + return -1; +}
Mike Waychison
2011-Aug-02 22:46 UTC
[klibc] [PATCH v2 2/4] klibc: Add alphasort() support.
Add support for alphasort() as defined in POSIX.1-2008. Signed-off-by: Mike Waychison <mikew at google.com> --- usr/include/dirent.h | 2 ++ usr/klibc/Kbuild | 2 +- usr/klibc/alphasort.c | 12 ++++++++++++ 3 files changed, 15 insertions(+), 1 deletions(-) create mode 100644 usr/klibc/alphasort.c diff --git a/usr/include/dirent.h b/usr/include/dirent.h index 0bcf40b..725452e 100644 --- a/usr/include/dirent.h +++ b/usr/include/dirent.h @@ -35,4 +35,6 @@ __extern int scandir(const char *, struct dirent ***, int (*)(const struct dirent **, const struct dirent **)); +__extern int alphasort(const struct dirent **, const struct dirent **); + #endif /* _DIRENT_H */ diff --git a/usr/klibc/Kbuild b/usr/klibc/Kbuild index 40e61da..c4f9ae2 100644 --- a/usr/klibc/Kbuild +++ b/usr/klibc/Kbuild @@ -42,7 +42,7 @@ klib-y := vsnprintf.o snprintf.o vsprintf.o sprintf.o \ seteuid.o setegid.o \ getenv.o setenv.o putenv.o __put_env.o unsetenv.o \ clearenv.o nullenv.o \ - getopt.o getopt_long.o readdir.o scandir.o remove.o \ + getopt.o getopt_long.o readdir.o scandir.o alphasort.o remove.o \ syslog.o closelog.o pty.o getpt.o posix_openpt.o isatty.o reboot.o \ time.o utime.o llseek.o nice.o getpriority.o \ qsort.o bsearch.o \ diff --git a/usr/klibc/alphasort.c b/usr/klibc/alphasort.c new file mode 100644 index 0000000..d420495 --- /dev/null +++ b/usr/klibc/alphasort.c @@ -0,0 +1,12 @@ +/* + * alphasort.c: alphasort + */ + +#include <string.h> + +#include <dirent.h> + +int alphasort(const struct dirent **a, const struct dirent **b) +{ + return strcmp((*a)->d_name, (*b)->d_name); +}
This patch implements support for executing files present in drop directories. This is implemented by a new function called run_scripts, which takes the name of the base drop-directory to search for scripts. It is implemented by simply doing a single-depth search for files present in the directory using scandir(). It then will synchronously execute each file in order. Failure to execute anything that looks like a file is treated as a fatal error, which should be easy to catch as these directories are essentially configuration directories and failure to execute should be immediately visible to developers. Execution is implemented as a simple fork/exec, passing all the command line flags in as the arguments to the executed script/binary. Signed-off-by: Mike Waychison <mikew at google.com> --- usr/kinit/Kbuild | 2 - usr/kinit/kinit.h | 2 + usr/kinit/run_scripts.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 1 deletions(-) create mode 100644 usr/kinit/run_scripts.c diff --git a/usr/kinit/Kbuild b/usr/kinit/Kbuild index ff1d449..b743b87 100644 --- a/usr/kinit/Kbuild +++ b/usr/kinit/Kbuild @@ -8,7 +8,7 @@ lib-y := name_to_dev.o devname.o getarg.o kinit-y := lib.a kinit-y += kinit.o do_mounts.o ramdisk_load.o initrd.o -kinit-y += getintfile.o readfile.o xpio.o +kinit-y += getintfile.o readfile.o xpio.o run_scripts.o kinit-y += do_mounts_md.o do_mounts_mtd.o nfsroot.o kinit-y += ipconfig/ diff --git a/usr/kinit/kinit.h b/usr/kinit/kinit.h index c2e67b7..808deee 100644 --- a/usr/kinit/kinit.h +++ b/usr/kinit/kinit.h @@ -65,4 +65,6 @@ static inline void dump_args(int argc, char *argv[]) } #endif +void run_scripts(const char *basepath, int cmdc, char **cmdv); + #endif /* KINIT_H */ diff --git a/usr/kinit/run_scripts.c b/usr/kinit/run_scripts.c new file mode 100644 index 0000000..4609b39 --- /dev/null +++ b/usr/kinit/run_scripts.c @@ -0,0 +1,110 @@ +#include <sys/types.h> +#include <sys/wait.h> +#include <dirent.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "kinit.h" + +static int is_file(const struct dirent *dirent) +{ + return (dirent->d_type == DT_REG); +} + +static void run_script(const char *basepath, const char *filename, + int cmdc, char **cmdv) +{ + char *fullpath; + char **args; + pid_t pid; + int status; + int ret; + int i; + + /* Figure out fullpath */ + fullpath = malloc(strlen(basepath) + strlen(filename) + 2); + if (!fullpath) { + fprintf(stderr, "Ran out of memory!\n"); + exit(1); + } + sprintf(fullpath, "%s/%s", basepath, filename); + + /* Prepare args for call */ + args = malloc(sizeof(*args) * (cmdc + 2)); /* NULL + ARGV[0} */ + if (!args) { + fprintf(stderr, "Ran out of memory!\n"); + free(fullpath); + exit(1); + } + args[0] = fullpath; + for (i = 0; i < cmdc; i++) + args[i + 1] = cmdv[i]; + args[cmdc + 1] = NULL; + + /* Run the child */ + pid = fork(); + if (pid == -1) { + fprintf(stderr, "Failed to fork in run_scripts(%s)\n", + basepath); + exit(1); + } + if (pid == 0) { + /* Child */ + execv(fullpath, args); + fprintf(stderr, "Failed to exec %s: %s\n", fullpath, + strerror(errno)); + exit(1); + } + + /* Parent */ + while (1) { + ret = waitpid(pid, &status, 0); + if (ret == pid) + break; + if (ret == -1 && errno == EINTR) + continue; + fprintf(stderr, "failed to wait on child: ret=%d errno=%d\n", + ret, errno); + exit(1); + } + + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) != 0) + fprintf(stderr, "%s exited with status: %d\n", + fullpath, WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) { + fprintf(stderr, "%s terminated by signal %d\n", + fullpath, WTERMSIG(status)); + } else { + fprintf(stderr, "Failed to understand status code 0x%x\n", + status); + } + + free(args); + free(fullpath); +} + +void run_scripts(const char *basepath, int cmdc, char **cmdv) +{ + struct dirent **namelist; + int i; + int count; + + count = scandir(basepath, &namelist, is_file, alphasort); + if (count < 0) { + if (errno == ENOENT) + return; + fprintf(stderr, "WARNING: could not run_scripts(%s): %s\n", + basepath, strerror(errno)); + return; + } + + for (i = 0; i < count; i++) { + run_script(basepath, namelist[i]->d_name, cmdc, cmdv); + free(namelist[i]); + } + free(namelist); +}
Mike Waychison
2011-Aug-02 22:47 UTC
[klibc] [PATCH v2 4/4] kinit: Add callsites to execute files in drop-directories.
This patch adds two callsites where kinit will go off and execute executable files in hard-coded drop-directories. We introduce a drop-directory at /scripts/after-network: ipconfig is completed, but the root filesystem isn't yet mounted. /scripts/after-mount: the root filesystem is mounted at /root. Signed-off-by: Mike Waychison <mikew at google.com> --- usr/kinit/kinit.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/usr/kinit/kinit.c b/usr/kinit/kinit.c index 4a1f40b..4e5ad24 100644 --- a/usr/kinit/kinit.c +++ b/usr/kinit/kinit.c @@ -285,9 +285,13 @@ int main(int argc, char *argv[]) /* Initialize networking, if applicable */ do_ipconfig(cmdc, cmdv); + run_scripts("/scripts/after-ipconfig", cmdc, cmdv); + check_path("/root"); do_mounts(cmdc, cmdv); + run_scripts("/scripts/after-mount", cmdc, cmdv); + if (mnt_procfs) { umount2("/proc", 0); mnt_procfs = 0;
maximilian attems
2011-Aug-03 08:35 UTC
[klibc] [PATCH v2 1/4] klibc: Add scandir() support.
On Tue, 02 Aug 2011, Mike Waychison wrote:> Add support for scandir() as defined in POSIX.1-2008. > > Signed-off-by: Mike Waychison <mikew at google.com> > --- > usr/include/dirent.h | 5 ++++ > usr/klibc/Kbuild | 2 + > usr/klibc/scandir.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 77 insertions(+), 1 deletions(-) > create mode 100644 usr/klibc/scandir.capplied and pushed, thank you.
maximilian attems
2011-Aug-03 08:36 UTC
[klibc] [PATCH v2 2/4] klibc: Add alphasort() support.
On Tue, 02 Aug 2011, Mike Waychison wrote:> Add support for alphasort() as defined in POSIX.1-2008. > > Signed-off-by: Mike Waychison <mikew at google.com> > --- > usr/include/dirent.h | 2 ++ > usr/klibc/Kbuild | 2 +- > usr/klibc/alphasort.c | 12 ++++++++++++ > 3 files changed, 15 insertions(+), 1 deletions(-) > create mode 100644 usr/klibc/alphasort.c >applied and pushed, thank you. (should appear shortly on kernel.org mirrors)