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.