Date: Sun, 13 Aug 1995 18:17:21 +0200 From: Wolfram Schneider <wosch@cs.tu-berlin.de> To: FreeBSD-gnats-submit@freebsd.org Cc: Paul Vixie <paul@vix.com>, wosch@cs.tu-berlin.de Subject: bin/683: cron(8) Message-ID: <199508131617.SAA13412@localhost> Resent-Message-ID: <199508140810.BAA04270@freefall.FreeBSD.org>
index | next in thread | raw e-mail
>Number: 683
>Category: bin
>Synopsis: cron(8)
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Mon Aug 14 01:10:01 PDT 1995
>Last-Modified:
>Originator: Wolfram Schneider
>Organization:
>Release: FreeBSD 2.0-ALPHA i386
>Environment:
>Description:
- cron(8) does not show or explain debug flags
- debug flag 'test' cause endless loop
- cron start ever a shell. Use exec if there are no meta chars.
>How-To-Repeat:
>Fix:
--- 1.1 1995/08/13 14:32:09
+++ cron.c 1995/08/13 14:32:21
@@ -46,7 +46,16 @@
static void
usage() {
+ char **dflags;
+
fprintf(stderr, "usage: %s [-x debugflag[,...]]\n", ProgramName);
+ fprintf(stderr, "\ndebugflags: ");
+
+ for(dflags = DebugFlagNames; *dflags; dflags++) {
+ fprintf(stderr, "%s ", *dflags);
+ }
+ fprintf(stderr, "\n");
+
exit(ERROR_EXIT);
}
@@ -116,7 +125,7 @@
cron_sync();
while (TRUE) {
# if DEBUGGING
- if (!(DebugFlags & DTEST))
+ /* if (!(DebugFlags & DTEST)) */
# endif /*DEBUGGING*/
cron_sleep();
@@ -288,8 +297,10 @@
{
int argch;
- while (EOF != (argch = getopt(argc, argv, "x:"))) {
+ while (EOF != (argch = getopt(argc, argv, "h?x:"))) {
switch (argch) {
+ case '?':
+ case 'h':
default:
usage();
case 'x':
--- 1.1 1995/08/13 10:08:46
+++ do_command.c 1995/08/13 15:23:53
@@ -33,6 +33,22 @@
static void child_process __P((entry *, user *)),
do_univ __P((user *));
+void do_exec __P((entry *));
+
+#if !defined(__FreeBSD__) && !defined(EXEC_SHELL)
+# warning "Only tested for FreeBSD."
+# warning "Use #define EXEC_SHELL if you have some"
+# warning "trouble with theses changes."
+#endif
+
+# if !defined(EXEC_SHELL)
+char **brk_string(char *, int *);
+char *emalloc(u_int);
+void enomem();
+int exectp(const char *file, char *const argv[], char *envp[]);
+
+#include <sys/errno.h>
+# endif /* EXEC_SHELL */
void
do_command(e, u)
@@ -215,23 +231,9 @@
/* exec the command.
*/
- {
- char *shell = env_get("SHELL", e->envp);
-# if DEBUGGING
- if (DebugFlags & DTEST) {
- fprintf(stderr,
- "debug DTEST is on, not exec'ing command.\n");
- fprintf(stderr,
- "\tcmd='%s' shell='%s'\n", e->cmd, shell);
- _exit(OK_EXIT);
- }
-# endif /*DEBUGGING*/
- execle(shell, shell, "-c", e->cmd, (char *)0, e->envp);
- fprintf(stderr, "execl: couldn't exec `%s'\n", shell);
- perror("execl");
- _exit(ERROR_EXIT);
- }
+ do_exec(e);
+
break;
default:
/* parent process */
@@ -499,3 +501,381 @@
(void) universe(U_ATT);
#endif
}
+
+
+/* exec the command.
+ */
+
+void
+do_exec(e)
+ entry *e;
+{
+
+ char *shell = env_get("SHELL", e->envp);
+
+
+ /* use ever shell -c for executing programs */
+# if defined(EXEC_SHELL)
+
+# if DEBUGGING
+ if (DebugFlags & DTEST) {
+ fprintf(stderr,
+ "debug DTEST is on, not exec'ing command.\n");
+ fprintf(stderr,
+ "\tcmd='%s' shell='%s'\n", e->cmd, shell);
+ _exit(OK_EXIT);
+ }
+# endif /*DEBUGGING*/
+ execle(shell, shell, "-c", e->cmd, (char *)0, e->envp);
+ fprintf(stderr, "execl: couldn't exec `%s'\n", shell);
+ perror("execl");
+ _exit(ERROR_EXIT);
+
+
+
+# else
+ /* try exec if there are no meta chars,
+ * otherweise use sh -c for executing programs
+ *
+ * code borrowed from 4.4BSD make(1)
+ */
+
+ static char meta[256];
+ char *cp; /* Pointer to string of shell meta-characters */
+ char **av; /* Argument vector for thing to exec */
+ int argc; /* Number of arguments in av or 0 if not
+ * dynamically allocated */
+ int i;
+ char **a;
+
+ for(i = 0; i < 256; i++)
+ meta[i] = 0;
+
+ for (cp = "#=|^(){};&<>*?[]:$`\\\n"; *cp != '\0';
+ cp++) {
+ meta[(unsigned char) *cp] = 1;
+ }
+
+ /*
+ * The null character serves as a sentinel in the string.
+ */
+ meta[0] = 1;
+
+ /*
+ * Search for meta characters in the command. If there are no meta
+ * characters, there's no need to execute a shell to execute the
+ * command.
+ */
+ for (cp = e->cmd; !meta[(unsigned char)*cp]; cp++) {
+ continue;
+ }
+
+ /*
+ * If *cp isn't the null character, we hit a "meta" character
+ * or command ist not a absolute path and need to pass the
+ * command off to the shell.
+ */
+
+ if (*cp != '\0') {
+
+# if DEBUGGING
+ if (DebugFlags & DTEST) {
+ fprintf(stderr,
+ "debug DTEST is on, not exec'ing command.\n");
+ fprintf(stderr, "Meta char: `%s' `%s'\n", cp, e->cmd);
+ _exit(OK_EXIT);
+ }
+# endif /*DEBUGGING*/
+ execle(shell, shell, "-c", e->cmd, (char *)0, e->envp);
+ fprintf(stderr, "execle: couldn't exec `%s'\n", shell);
+ perror("execle");
+ _exit(ERROR_EXIT);
+ }
+
+ else {
+ /*
+ * No meta-characters, so no need to exec a shell. Break the command
+ * into words to form an argument vector we can execute.
+ * brk_string sticks our name in av[0], so we have to
+ * skip over it...
+ */
+
+ av = brk_string(e->cmd, &argc);
+ a = av;
+
+# if DEBUGGING
+ if (DebugFlags & DTEST) {
+ fprintf(stderr,
+ "debug DTEST is on, not exec'ing command.\n");
+
+ fprintf(stderr, "No meta chars: `%s'\n", e->cmd);
+ fprintf(stderr, "exect(\"%s\"", *av);
+
+ for(a = av; *a; a++) {
+ fprintf(stderr, ", \"%s\"", *a);
+ }
+ fprintf(stderr, ", e->envp);\nargc: %d\n", argc);
+
+ _exit(OK_EXIT);
+ }
+# endif /*DEBUGGING*/
+
+ /* exectp
+ *
+ * searching for an executable file if the specified file
+ * name does not contain a slash ``/'' character.
+ * The search path is the path specified in the environment
+ * by ``PATH'' variable. If this variable isn't
+ * specified, the default path ``/bin:/usr/bin:'' is used
+ */
+
+ (void)exectp(av[0], av, e->envp);
+
+ fprintf(stderr, "exectp: couldn't exec `%s'\n", av[0]);
+ perror("exectp");
+ _exit(ERROR_EXIT);
+
+ }
+}
+#endif /* EXEC_SHELL */
+
+# if !defined(EXEC_SHELL)
+/* following code borrowed from 4.4BSD make(1) */
+
+/*-
+ * brk_string --
+ * Fracture a string into an array of words (as delineated by tabs or
+ * spaces) taking quotation marks into account. Leading tabs/spaces
+ * are ignored.
+ *
+ * returns --
+ * Pointer to the array of pointers to the words. To make life easier,
+ * the first word is always the value of the .MAKE variable.
+ */
+char **
+brk_string(str, store_argc)
+ register char *str;
+ int *store_argc;
+{
+ static int argmax, curlen;
+ static char **argv, *buf;
+ register int argc, ch;
+ register char inquote, *p, *start, *t;
+ int len;
+
+ if (!argv) {
+ argv = (char **)emalloc((argmax = 50) * sizeof(char *));
+ }
+
+ /* skip leading space chars. */
+ for (; *str == ' ' || *str == '\t'; ++str)
+ continue;
+
+ /* allocate room for a copy of the string */
+ if ((len = strlen(str) + 1) > curlen)
+ buf = emalloc(curlen = len);
+
+ /*
+ * copy the string; at the same time, parse backslashes,
+ * quotes and build the argument list.
+ */
+ argc = 0;
+ inquote = '\0';
+
+ for (p = str, start = t = buf;; ++p) {
+ switch(ch = *p) {
+ case '"':
+ case '\'':
+ if (inquote) {
+ if (inquote == ch)
+ inquote = '\0';
+ else
+ break;
+ } else {
+ inquote = (char) ch;
+ start = t;
+ continue;
+ }
+ /* FALLTHROUGH */
+ case ' ':
+ case '\t':
+ if (inquote)
+ break;
+ if (!start)
+ continue;
+ /* FALLTHROUGH */
+ case '\n':
+ case '\0':
+ /*
+ * end of a token -- make sure there's enough argv
+ * space and save off a pointer.
+ */
+ *t++ = '\0';
+ if (argc == argmax) {
+ argmax *= 2; /* ramp up fast */
+ if (!(argv = (char **)realloc(argv,
+ argmax * sizeof(char *))))
+ enomem();
+ }
+ argv[argc++] = start;
+ start = (char *)NULL;
+ if (ch == '\n' || ch == '\0')
+ goto done;
+ continue;
+ case '\\':
+ switch (ch = *++p) {
+ case '\0':
+ case '\n':
+ /* hmmm; fix it up as best we can */
+ ch = '\\';
+ --p;
+ break;
+ case 'b':
+ ch = '\b';
+ break;
+ case 'f':
+ ch = '\f';
+ break;
+ case 'n':
+ ch = '\n';
+ break;
+ case 'r':
+ ch = '\r';
+ break;
+ case 't':
+ ch = '\t';
+ break;
+ }
+ break;
+ }
+ if (!start)
+ start = t;
+ *t++ = (char) ch;
+ }
+done: argv[argc] = (char *)NULL;
+ *store_argc = argc;
+ return(argv);
+}
+
+/*
+ * emalloc --
+ * malloc, but die on error.
+ */
+char *
+emalloc(len)
+ u_int len;
+{
+ char *p;
+
+ if (!(p = malloc(len)))
+ enomem();
+ return(p);
+}
+
+/*
+ * enomem --
+ * die when out of memory.
+ */
+void
+enomem()
+{
+ (void)fprintf(stderr, "cron: %s.\n", strerror(errno));
+ exit(2);
+}
+
+
+/* code borrowed from 4.4BSD libc exec(3) */
+int
+exectp(name, argv, envp)
+ const char *name;
+ char * const *argv;
+ char **envp;
+{
+ static int memsize;
+ static char **memp;
+ register int cnt, lp, ln;
+ register char *p;
+ int eacces, etxtbsy;
+ char *bp, *cur, *path, buf[MAXPATHLEN];
+
+ /* If it's an absolute or relative path name, it's easy. */
+ if (index(name, '/')) {
+ bp = (char *)name;
+ cur = path = NULL;
+ goto retry;
+ }
+ bp = buf;
+
+ /* Get the path we're searching. */
+ if (!(path = env_get("PATH", envp)))
+ path = _PATH_DEFPATH;
+ cur = path = strdup(path);
+
+ eacces = etxtbsy = 0;
+ while (p = strsep(&cur, ":")) {
+ /*
+ * It's a SHELL path -- double, leading and trailing colons
+ * mean the current directory.
+ */
+ if (!*p) {
+ p = ".";
+ lp = 1;
+ } else
+ lp = strlen(p);
+ ln = strlen(name);
+
+ /*
+ * If the path is too long complain. This is a possible
+ * security issue; given a way to make the path too long
+ * the user may execute the wrong program.
+ */
+ if (lp + ln + 2 > sizeof(buf)) {
+ (void)write(STDERR_FILENO, "exectp: ", 8);
+ (void)write(STDERR_FILENO, p, lp);
+ (void)write(STDERR_FILENO, ": path too long\n", 16);
+ continue;
+ }
+ bcopy(p, buf, lp);
+ buf[lp] = '/';
+ bcopy(name, buf + lp + 1, ln);
+ buf[lp + ln + 1] = '\0';
+
+retry: (void)execve(bp, argv, envp);
+ switch(errno) {
+ case EACCES:
+ eacces = 1;
+ break;
+ case ENOENT:
+ break;
+ case ENOEXEC:
+ for (cnt = 0; argv[cnt]; ++cnt);
+ if ((cnt + 2) * sizeof(char *) > memsize) {
+ memsize = (cnt + 2) * sizeof(char *);
+ if ((memp = realloc(memp, memsize)) == NULL) {
+ memsize = 0;
+ goto done;
+ }
+ }
+ memp[0] = "sh";
+ memp[1] = bp;
+ bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
+ (void)execve(_PATH_BSHELL, memp, envp);
+ goto done;
+ case ETXTBSY:
+ if (etxtbsy < 3)
+ (void)sleep(++etxtbsy);
+ goto retry;
+ default:
+ goto done;
+ }
+ }
+ if (eacces)
+ errno = EACCES;
+ else if (!errno)
+ errno = ENOENT;
+done: if (path)
+ free(path);
+ return (-1);
+}
+
+#endif
>Audit-Trail:
>Unformatted:
help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199508131617.SAA13412>
