Mike Waychison
2011-Jul-29 21:36 UTC
[klibc] [PATCH 1/3] klibc: Add scandir() and alphasort() support.
Add support for scandir() and alphasort() as defined in POSIX.1-2008. Signed-off-by: Mike Waychison <mikew at google.com> --- usr/include/dirent.h | 7 +++++ usr/klibc/Kbuild | 2 + usr/klibc/scandir.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletions(-) create mode 100644 usr/klibc/scandir.c diff --git a/usr/include/dirent.h b/usr/include/dirent.h index e324474..3b1ff59 100644 --- a/usr/include/dirent.h +++ b/usr/include/dirent.h @@ -30,4 +30,11 @@ static __inline__ int dirfd(DIR * __d) return __d->__fd; } +__extern int scandir(const char *dirp, struct dirent ***namelist, + int (*filter)(const struct dirent *), + int (*compar)(const struct dirent **, + const struct dirent **)); + +int alphasort(const struct dirent **a, const struct dirent **b); + #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..1f58b15 --- /dev/null +++ b/usr/klibc/scandir.c @@ -0,0 +1,76 @@ +/* + * scandir.c: scandir/alphasort + */ + +#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; +} + +int alphasort(const struct dirent **a, const struct dirent **b) +{ + return strcmp((*a)->d_name, (*b)->d_name); +}
Mike Waychison
2011-Jul-29 21:37 UTC
[klibc] [PATCH 1/3] klibc: Add scandir() and alphasort() support.
Add support for scandir() and alphasort() as defined in POSIX.1-2008. Signed-off-by: Mike Waychison <mikew at google.com> --- usr/include/dirent.h | 7 +++++ usr/klibc/Kbuild | 2 + usr/klibc/scandir.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletions(-) create mode 100644 usr/klibc/scandir.c diff --git a/usr/include/dirent.h b/usr/include/dirent.h index e324474..3b1ff59 100644 --- a/usr/include/dirent.h +++ b/usr/include/dirent.h @@ -30,4 +30,11 @@ static __inline__ int dirfd(DIR * __d) return __d->__fd; } +__extern int scandir(const char *dirp, struct dirent ***namelist, + int (*filter)(const struct dirent *), + int (*compar)(const struct dirent **, + const struct dirent **)); + +int alphasort(const struct dirent **a, const struct dirent **b); + #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..1f58b15 --- /dev/null +++ b/usr/klibc/scandir.c @@ -0,0 +1,76 @@ +/* + * scandir.c: scandir/alphasort + */ + +#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; +} + +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); +}
maximilian attems
2011-Aug-02 21:07 UTC
[klibc] [PATCH 1/3] klibc: Add scandir() and alphasort() support.
On Fri, 29 Jul 2011, Mike Waychison wrote:> Add support for scandir() and alphasort() as defined in POSIX.1-2008. > > Signed-off-by: Mike Waychison <mikew at google.com> > --- > usr/include/dirent.h | 7 +++++ > usr/klibc/Kbuild | 2 + > usr/klibc/scandir.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 84 insertions(+), 1 deletions(-) > create mode 100644 usr/klibc/scandir.c > > diff --git a/usr/include/dirent.h b/usr/include/dirent.h > index e324474..3b1ff59 100644 > --- a/usr/include/dirent.h > +++ b/usr/include/dirent.h > @@ -30,4 +30,11 @@ static __inline__ int dirfd(DIR * __d) > return __d->__fd; > } > > +__extern int scandir(const char *dirp, struct dirent ***namelist, > + int (*filter)(const struct dirent *), > + int (*compar)(const struct dirent **, > + const struct dirent **)); > + > +int alphasort(const struct dirent **a, const struct dirent **b); > + > #endif /* _DIRENT_H */please no names in the header files, it breaks macros. ah and alphasort needs __extern too.> 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 \please put alphasort in separate file.> diff --git a/usr/klibc/scandir.c b/usr/klibc/scandir.c > new file mode 100644 > index 0000000..1f58b15 > --- /dev/null > +++ b/usr/klibc/scandir.c > @@ -0,0 +1,76 @@ > +/* > + * scandir.c: scandir/alphasort > + */ > + > +#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; > +} > + > +int alphasort(const struct dirent **a, const struct dirent **b) > +{ > + return strcmp((*a)->d_name, (*b)->d_name); > +}other then that looks good, thanks to hpa for quick review. -- maks P.S. need to fix the sys/capability.h too.