SVN: rc-scripts/trunk: Makefile.am configure.ac man/Makefile.am man/run-parts.8 run-parts run-parts....
glen
glen at pld-linux.org
Fri Oct 18 18:32:33 CEST 2013
Author: glen
Date: Fri Oct 18 18:32:33 2013
New Revision: 12724
Added:
rc-scripts/trunk/man/run-parts.8
rc-scripts/trunk/run-parts.sh
- copied unchanged from rev 12723, rc-scripts/trunk/run-parts
rc-scripts/trunk/src/run-parts.c
Removed:
rc-scripts/trunk/run-parts
Modified:
rc-scripts/trunk/Makefile.am
rc-scripts/trunk/configure.ac
rc-scripts/trunk/man/Makefile.am
rc-scripts/trunk/src/Makefile.am
Log:
add run-parts from debianutils 4.4
switch to debian one, it's more complete and at least maintained
basic usage without args works without modifications.
old script preserved as run-parts.sh in case need quickly to revert to previous script
Modified: rc-scripts/trunk/Makefile.am
==============================================================================
--- rc-scripts/trunk/Makefile.am (original)
+++ rc-scripts/trunk/Makefile.am Fri Oct 18 18:32:33 2013
@@ -20,7 +20,7 @@
lang.sh \
lang.csh
-bin_SCRIPTS = run-parts
+bin_SCRIPTS = run-parts.sh
sbin_SCRIPTS = \
setsysfont \
hwprofile \
Modified: rc-scripts/trunk/configure.ac
==============================================================================
--- rc-scripts/trunk/configure.ac (original)
+++ rc-scripts/trunk/configure.ac Fri Oct 18 18:32:33 2013
@@ -92,7 +92,7 @@
DPKG_C_GCC_ATTRIBUTE(format...,format,[char *y, ...],[format(printf,1,2)],PRINTFFORMAT,[Define if printf-format argument lists a la GCC are available.]))
AC_CHECK_TYPE(ptrdiff_t,int)
-AC_CHECK_HEADERS([stddef.h sys/capability.h])
+AC_CHECK_HEADERS([stddef.h sys/capability.h getopt.h])
dnl Output
AC_SUBST(BASHSCRIPTS)
Modified: rc-scripts/trunk/man/Makefile.am
==============================================================================
--- rc-scripts/trunk/man/Makefile.am (original)
+++ rc-scripts/trunk/man/Makefile.am Fri Oct 18 18:32:33 2013
@@ -12,6 +12,7 @@
netreport.1 \
ppp-watch.8 \
usernetctl.8 \
+ run-parts.8 \
usleep.1 \
crypttab.5 \
start-stop-daemon.8
Added: rc-scripts/trunk/man/run-parts.8
==============================================================================
--- (empty file)
+++ rc-scripts/trunk/man/run-parts.8 Fri Oct 18 18:32:33 2013
@@ -0,0 +1,130 @@
+.\" Hey, Emacs! This is an -*- nroff -*- source file.
+.\" Build-from-directory and this manpage are Copyright 1994 by Ian Jackson.
+.\" Changes to this manpage are Copyright 1996 by Jeff Noxon.
+.\" More
+.\"
+.\" This is free software; see the GNU General Public Licence version 2
+.\" or later for copying conditions. There is NO warranty.
+.TH RUN\-PARTS 8 "27 Jun 2012" "Debian"
+.SH NAME
+run\-parts \- run scripts or programs in a directory
+.SH SYNOPSIS
+.PP
+.B run\-parts
+[\-\-test] [\-\-verbose] [\-\-report] [\-\-lsbsysinit] [\-\-regex=RE]
+[\-\-umask=umask] [\-\-arg=argument] [\-\-exit\-on\-error] [\-\-help]
+[\-\-version] [\-\-list] [\-\-reverse] [\-\-] DIRECTORY
+.PP
+.B run\-parts
+\-V
+.SH DESCRIPTION
+.PP
+.B run\-parts
+runs all the executable files named within constraints described below, found
+in directory
+.IR directory .
+Other files and directories are silently ignored.
+
+If neither the \-\-lsbsysinit option nor the \-\-regex option is given
+then the names must consist entirely of ASCII upper- and lower-case
+letters, ASCII digits, ASCII underscores, and ASCII minus-hyphens.
+
+If the \-\-lsbsysinit option is given, then the names must not end
+in .dpkg\-old or .dpkg\-dist or .dpkg\-new or .dpkg\-tmp, and must
+belong to one or more of the following namespaces: the
+LANANA-assigned namespace (^[a\-z0\-9]+$); the LSB hierarchical and
+reserved namespaces (^_?([a\-z0\-9_.]+\-)+[a\-z0\-9]+$);
+and the Debian cron script namespace (^[a\-zA-Z0\-9_\-]+$).
+
+If the \-\-regex option is given, the names must match the custom
+extended regular expression specified as that option's argument.
+
+Files are run in the lexical sort order (according to the C/POSIX
+locale character collation rules) of their names unless the
+\-\-reverse option is given, in which case they are run in the
+opposite order.
+
+.SH OPTIONS
+.TP
+.B \-\-test
+print the names of the scripts which would be run, but don't actually run
+them.
+.TP
+.B \-\-list
+print the names of the all matching files (not limited to executables),
+but don't actually run them. This option cannot be used with --test.
+.TP
+.B \-v, \-\-verbose
+print the name of each script to stderr before running.
+.TP
+.B \-\-report
+similar to
+.BR \-\-verbose ,
+but only prints the name of scripts which produce output. The script's name is printed to whichever of stdout or stderr the script first produces output on.
+.TP
+.B \-\-reverse
+reverse the scripts' execution order.
+.TP
+.B \-\-exit\-on\-error
+exit as soon as a script returns with a non-zero exit code.
+.TP
+.B \-\-lsbsysinit
+use LSB namespaces instead of classical behavior.
+.TP
+.B \-\-new\-session
+run each script in a separate process session. If you use this option,
+killing run-parts will not kill the currently running script, it will
+run until completion.
+.TP
+.BI \-\-regex= RE
+validate filenames against custom extended regular expression
+.IR RE .
+See the EXAMPLES section for an example.
+.TP
+.BI "\-u, \-\-umask=" umask
+sets the umask to
+.I umask
+before running the scripts.
+.I umask
+should be specified in octal. By default the umask is set to 022.
+.TP
+.BI "\-a, \-\-arg=" argument
+pass
+.I argument
+to the scripts. Use
+.B --arg
+once for each argument you want passed.
+.TP
+.B "\-\-"
+specifies that this is the end of the options. Any filename after
+.B "\-\-"
+will be not be interpreted as an option even if it starts with a
+hyphen.
+.TP
+.B \-h, \-\-help
+display usage information and exit.
+.TP
+.B \-V, \-\-version
+display version and copyright and exit.
+
+.SH EXAMPLES
+.P
+Print the names of all files in /etc that start with `p' and end with `d':
+.P
+run-parts \-\-list \-\-regex \[aq]^p.*d$\[aq] /etc
+
+.SH COPYRIGHT
+.P
+Copyright (C) 1994 Ian Jackson.
+.P
+Copyright (C) 1996 Jeff Noxon.
+.P
+Copyright (C) 1996, 1997, 1998 Guy Maor
+.P
+Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Clint Adams
+
+.B run\-parts
+is free software; see the GNU General Public License version 2 or
+later for copying conditions. There is
+.I no
+warranty.
Modified: rc-scripts/trunk/src/Makefile.am
==============================================================================
--- rc-scripts/trunk/src/Makefile.am (original)
+++ rc-scripts/trunk/src/Makefile.am Fri Oct 18 18:32:33 2013
@@ -9,6 +9,7 @@
doexec \
ipcalc \
usleep \
+ run-parts \
resolvesymlink
sbin_PROGRAMS = \
@@ -64,3 +65,5 @@
start_stop_daemon_LDADD = -lcap
setuidgid_SOURCES = setuidgid.c
+
+run_parts_CPPFLAGS = -include config.h
Added: rc-scripts/trunk/src/run-parts.c
==============================================================================
--- (empty file)
+++ rc-scripts/trunk/src/run-parts.c Fri Oct 18 18:32:33 2013
@@ -0,0 +1,647 @@
+/* run-parts: run a bunch of scripts in a directory
+ *
+ * Debian run-parts program
+ * Copyright (C) 1996 Jeff Noxon <jeff at router.patch.net>,
+ * Copyright (C) 1996-1999 Guy Maor <maor at debian.org>
+ * Copyright (C) 2002-2012 Clint Adams <clint at debian.org>
+ *
+ * This is free software; see the GNU General Public License version 2
+ * or later for copying conditions. There is NO warranty.
+ *
+ * Based on run-parts.pl version 0.2, Copyright (C) 1994 Ian Jackson.
+ *
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#endif /* HAVE_GETOPT_H */
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <regex.h>
+
+#define RUNPARTS_NORMAL 0
+#define RUNPARTS_ERE 1
+#define RUNPARTS_LSBSYSINIT 100
+
+int test_mode = 0;
+int list_mode = 0;
+int verbose_mode = 0;
+int report_mode = 0;
+int reverse_mode = 0;
+int exitstatus = 0;
+int regex_mode = 0;
+int exit_on_error_mode = 0;
+int new_session_mode = 0;
+
+int argcount = 0, argsize = 0;
+char **args = 0;
+
+char *custom_ere;
+regex_t hierre, tradre, excsre, classicalre, customre;
+
+static void catch_signals();
+static void restore_signals();
+
+static char* regex_get_error(int errcode, regex_t *compiled);
+static void regex_compile_pattern(void);
+static void regex_clean(void);
+
+void error(char *format, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "run-parts: ");
+
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+
+ fprintf(stderr, "\n");
+}
+
+
+void version()
+{
+ fprintf(stderr, "Debian run-parts program, version " PACKAGE_VERSION
+ "\nCopyright (C) 1994 Ian Jackson, Copyright (C) 1996 Jeff Noxon.\n"
+ "Copyright (C) 1996,1997,1998,1999 Guy Maor\n"
+ "Copyright (C) 2002-2012 Clint Adams\n"
+ "This is free software; see the GNU General Public License version 2\n"
+ "or later for copying conditions. There is NO warranty.\n");
+ exit(0);
+}
+
+
+void usage()
+{
+ fprintf(stderr, "Usage: run-parts [OPTION]... DIRECTORY\n"
+ " --test print script names which would run, but don't run them.\n"
+ " --list print names of all valid files (can not be used with\n"
+ " --test)\n"
+ " -v, --verbose print script names before running them.\n"
+ " --report print script names if they produce output.\n"
+ " --reverse reverse execution order of scripts.\n"
+ " --exit-on-error exit as soon as a script returns with a non-zero exit\n"
+ " code.\n"
+ " --lsbsysinit validate filenames based on LSB sysinit specs.\n"
+ " --new-session run each script in a separate process session\n"
+ " --regex=PATTERN validate filenames based on POSIX ERE pattern PATTERN.\n"
+ " -u, --umask=UMASK sets umask to UMASK (octal), default is 022.\n"
+ " -a, --arg=ARGUMENT pass ARGUMENT to scripts, use once for each argument.\n"
+ " -V, --version output version information and exit.\n"
+ " -h, --help display this help and exit.\n");
+ exit(0);
+}
+
+
+/* The octal conversion in libc is not foolproof; it will take the 8 and 9
+ * digits under some circumstances. We'll just have to live with it.
+ */
+void set_umask()
+{
+ int mask, result;
+
+ result = sscanf(optarg, "%o", &mask);
+ if ((result != 1) || (mask > 07777) || (mask < 0)) {
+ error("bad umask value");
+ exit(1);
+ }
+
+ umask(mask);
+}
+
+/* Add an argument to the commands that we will call. Called once for
+ every argument. */
+void add_argument(char *newarg)
+{
+ if (argcount + 1 >= argsize) {
+ argsize = argsize ? argsize * 2 : 4;
+ args = realloc(args, argsize * (sizeof(char *)));
+ if (!args) {
+ error("failed to reallocate memory for arguments: %s", strerror(errno));
+ exit(1);
+ }
+ }
+ args[argcount++] = newarg;
+ args[argcount] = 0;
+}
+
+/* True or false? Is this a valid filename? */
+int valid_name(const struct dirent *d)
+{
+ char *s;
+ unsigned int retval;
+
+ s = (char *)&(d->d_name);
+
+ if (regex_mode == RUNPARTS_ERE)
+ retval = !regexec(&customre, s, 0, NULL, 0);
+
+ else if (regex_mode == RUNPARTS_LSBSYSINIT) {
+
+ if (!regexec(&hierre, s, 0, NULL, 0))
+ retval = regexec(&excsre, s, 0, NULL, 0);
+
+ else
+ retval = !regexec(&tradre, s, 0, NULL, 0);
+
+ } else
+ retval = !regexec(&classicalre, s, 0, NULL, 0);
+
+ return retval;
+}
+
+/* Execute a file */
+void run_part(char *progname)
+{
+ int result, waited;
+ int pid, r;
+ int pout[2], perr[2];
+
+ waited = 0;
+
+ if (report_mode && (pipe(pout) || pipe(perr))) {
+ error("pipe: %s", strerror(errno));
+ exit(1);
+ }
+ if ((pid = fork()) < 0) {
+ error("failed to fork: %s", strerror(errno));
+ exit(1);
+ }
+ else if (!pid) {
+ restore_signals();
+ if (new_session_mode)
+ setsid();
+ if (report_mode) {
+ if (dup2(pout[1], STDOUT_FILENO) == -1 ||
+ dup2(perr[1], STDERR_FILENO) == -1) {
+ error("dup2: %s", strerror(errno));
+ exit(1);
+ }
+ close(pout[0]);
+ close(perr[0]);
+ close(pout[1]);
+ close(perr[1]);
+ }
+ args[0] = progname;
+ execv(progname, args);
+ error("failed to exec %s: %s", progname, strerror(errno));
+ exit(1);
+ }
+
+ if (report_mode) {
+ fd_set set;
+ sigset_t tempmask;
+ struct timespec zero_timeout;
+ struct timespec *the_timeout;
+ int max, printflag;
+ ssize_t c;
+ char buf[4096];
+
+ sigemptyset(&tempmask);
+ sigprocmask(0, NULL, &tempmask);
+ sigdelset(&tempmask, SIGCHLD);
+
+ memset(&zero_timeout, 0, sizeof(zero_timeout));
+ the_timeout = NULL;
+
+ close(pout[1]);
+ close(perr[1]);
+ max = pout[0] > perr[0] ? pout[0] + 1 : perr[0] + 1;
+ printflag = 0;
+
+ while (pout[0] >= 0 || perr[0] >= 0) {
+ if (!waited) {
+ r = waitpid(pid, &result, WNOHANG);
+ if (r == -1) {
+ error("waitpid: %s", strerror(errno));
+ exit(1);
+ }
+ if (r != 0 && (WIFEXITED(result) || WIFSIGNALED(result))) {
+ /* If the process dies, set a zero timeout. Rarely, some processes
+ * leak file descriptors (e.g., by starting a naughty daemon).
+ * select() would wait forever since the pipes wouldn't close.
+ * We loop, with a zero timeout, until there's no data left, then
+ * give up. This shouldn't affect non-leaky processes. */
+ waited = 1;
+ the_timeout = &zero_timeout;
+ }
+ }
+
+ FD_ZERO(&set);
+ if (pout[0] >= 0)
+ FD_SET(pout[0], &set);
+ if (perr[0] >= 0)
+ FD_SET(perr[0], &set);
+ r = pselect(max, &set, 0, 0, the_timeout, &tempmask);
+
+ if (r < 0) {
+ if (errno == EINTR)
+ continue;
+
+ error("select: %s", strerror(errno));
+ exit(1);
+ }
+ else if (r > 0) {
+ /* If STDOUT or STDERR get closed / full, we still run to completion
+ * (and just ignore that we can't output process output any more).
+ * Perhaps we should instead kill the child process we are running
+ * if that happens.
+ * For now partial writes are not retried to complete - that can
+ * and should be done, but needs care to ensure that we don't hang
+ * if the fd doesn't accept more data ever - or we need to decide that
+ * waiting is the appropriate thing to do.
+ */
+ int ignored;
+ if (pout[0] >= 0 && FD_ISSET(pout[0], &set)) {
+ c = read(pout[0], buf, sizeof(buf));
+ if (c > 0) {
+ if (!printflag) {
+ printf("%s:\n", progname);
+ fflush(stdout);
+ printflag = 1;
+ }
+ ignored = write(STDOUT_FILENO, buf, c);
+ }
+ else if (c == 0) {
+ close(pout[0]);
+ pout[0] = -1;
+ }
+ else if (c < 0) {
+ close(pout[0]);
+ pout[0] = -1;
+ error("failed to read from stdout pipe: %s", strerror (errno));
+ }
+ }
+ if (perr[0] >= 0 && FD_ISSET(perr[0], &set)) {
+ c = read(perr[0], buf, sizeof(buf));
+ if (c > 0) {
+ if (!printflag) {
+ fprintf(stderr, "%s:\n", progname);
+ fflush(stderr);
+ printflag = 1;
+ }
+ ignored = write(STDERR_FILENO, buf, c);
+ }
+ else if (c == 0) {
+ close(perr[0]);
+ perr[0] = -1;
+ }
+ else if (c < 0) {
+ close(perr[0]);
+ perr[0] = -1;
+ error("failed to read from error pipe: %s", strerror (errno));
+ }
+ }
+ }
+ else if (r == 0 && waited) {
+ /* Zero timeout, no data left. */
+ close(perr[0]);
+ perr[0] = -1;
+ close(pout[0]);
+ pout[0] = -1;
+ }
+ else {
+ /* assert(FALSE): select was called with infinite timeout, so
+ it either returns successfully or is interrupted */
+ } /*if */
+ } /*while */
+ }
+
+ if (!waited) {
+ r = waitpid(pid, &result, 0);
+
+ if (r == -1) {
+ error("waitpid: %s", strerror(errno));
+ exit(1);
+ }
+ }
+
+ if (WIFEXITED(result) && WEXITSTATUS(result)) {
+ error("%s exited with return code %d", progname, WEXITSTATUS(result));
+ exitstatus = 1;
+ }
+ else if (WIFSIGNALED(result)) {
+ error("%s exited because of uncaught signal %d", progname,
+ WTERMSIG(result));
+ exitstatus = 1;
+ }
+}
+
+static void handle_signal(int s)
+{
+ /* Do nothing */
+}
+
+/* Catch SIGCHLD with an empty function to interrupt select() */
+static void catch_signals()
+{
+ struct sigaction act;
+ sigset_t set;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = handle_signal;
+ act.sa_flags = SA_NOCLDSTOP;
+ sigaction(SIGCHLD, &act, NULL);
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &set, NULL);
+}
+
+/* Unblock signals before execing a child */
+static void restore_signals()
+{
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, SIGCHLD);
+ sigprocmask(SIG_UNBLOCK, &set, NULL);
+}
+
+/* Find the parts to run & call run_part() */
+void run_parts(char *dirname)
+{
+ struct dirent **namelist;
+ char *filename;
+ size_t filename_length, dirname_length;
+ int entries, i, result;
+ struct stat st;
+
+ /* dirname + "/" */
+ dirname_length = strlen(dirname) + 1;
+ /* dirname + "/" + ".." + "\0" (This will save one realloc.) */
+ filename_length = dirname_length + 2 + 1;
+ if (!(filename = malloc(filename_length))) {
+ error("failed to allocate memory for path: %s", strerror(errno));
+ exit(1);
+ }
+ strcpy(filename, dirname);
+ strcat(filename, "/");
+
+ /* scandir() isn't POSIX, but it makes things easy. */
+ entries = scandir(dirname, &namelist, valid_name, alphasort);
+ if (entries < 0) {
+ error("failed to open directory %s: %s", dirname, strerror(errno));
+ exit(1);
+ }
+
+ i = reverse_mode ? 0 : entries;
+ for (i = reverse_mode ? (entries - 1) : 0;
+ reverse_mode ? (i >= 0) : (i < entries); reverse_mode ? i-- : i++) {
+ if (filename_length < dirname_length + strlen(namelist[i]->d_name) + 1) {
+ filename_length = dirname_length + strlen(namelist[i]->d_name) + 1;
+ if (!(filename = realloc(filename, filename_length))) {
+ error("failed to reallocate memory for path: %s", strerror(errno));
+ exit(1);
+ }
+ }
+ strcpy(filename + dirname_length, namelist[i]->d_name);
+
+ strcpy(filename, dirname);
+ strcat(filename, "/");
+ strcat(filename, namelist[i]->d_name);
+
+ result = stat(filename, &st);
+ if (result < 0) {
+ error("failed to stat component %s: %s", filename, strerror(errno));
+ if (exit_on_error_mode) {
+ exit(1);
+ }
+ else
+ continue;
+ }
+
+ if (S_ISREG(st.st_mode)) {
+ if (!access(filename, X_OK)) {
+ if (test_mode) {
+ printf("%s\n", filename);
+ }
+ else if (list_mode) {
+ if (!access(filename, R_OK))
+ printf("%s\n", filename);
+ }
+ else {
+ if (verbose_mode)
+ if (argcount) {
+ char **a = args;
+
+ fprintf(stderr, "run-parts: executing %s", filename);
+ while(*(++a))
+ fprintf(stderr, " %s", *a);
+ fprintf(stderr, "\n");
+ } else {
+ fprintf(stderr, "run-parts: executing %s\n", filename);
+ }
+ run_part(filename);
+ if (exitstatus != 0 && exit_on_error_mode) return;
+ }
+ }
+ else if (!access(filename, R_OK)) {
+ if (list_mode) {
+ printf("%s\n", filename);
+ }
+ }
+ else if (S_ISLNK(st.st_mode)) {
+ if (!list_mode) {
+ error("run-parts: component %s is a broken symbolic link\n",filename);
+ exitstatus = 1;
+ }
+ }
+ }
+ else if (!S_ISDIR(st.st_mode)) {
+ if (!list_mode) {
+ error("run-parts: component %s is not an executable plain file\n",
+ filename);
+ exitstatus = 1;
+ }
+ }
+
+ free(namelist[i]);
+ }
+ free(namelist);
+ free(filename);
+}
+
+/* Process options */
+int main(int argc, char *argv[])
+{
+ custom_ere = NULL;
+ umask(022);
+ add_argument(0);
+
+ for (;;) {
+ int c;
+ int option_index = 0;
+
+ static struct option long_options[] = {
+ {"test", 0, &test_mode, 1},
+ {"list", 0, &list_mode, 1},
+ {"verbose", 0, 0, 'v'},
+ {"report", 0, &report_mode, 1},
+ {"reverse", 0, &reverse_mode, 1},
+ {"umask", 1, 0, 'u'},
+ {"arg", 1, 0, 'a'},
+ {"help", 0, 0, 'h'},
+ {"version", 0, 0, 'V'},
+ {"lsbsysinit", 0, ®ex_mode, RUNPARTS_LSBSYSINIT},
+ {"regex", 1, ®ex_mode, RUNPARTS_ERE},
<<diff output has been trimmed to 500 lines, 148 line(s) remained.>>
More information about the pld-cvs-commit
mailing list