bc: convert all status codes, remove bc_err_msgs[], bc_vm_error(), bc_vm_posixError()
[oweals/busybox.git] / miscutils / crond.c
index 8a399446ca7134697e43ae8f627f6deb836aa285..f6580a9d41543427a0facecb0c169421bbfc1a13 100644 (file)
@@ -9,54 +9,54 @@
  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
 //config:config CROND
-//config:      bool "crond"
+//config:      bool "crond (13 kb)"
 //config:      default y
 //config:      select FEATURE_SYSLOG
 //config:      help
-//config:        Crond is a background daemon that parses individual crontab
-//config:        files and executes commands on behalf of the users in question.
-//config:        This is a port of dcron from slackware. It uses files of the
-//config:        format /var/spool/cron/crontabs/<username> files, for example:
-//config:            $ cat /var/spool/cron/crontabs/root
-//config:            # Run daily cron jobs at 4:40 every day:
-//config:            40 4 * * * /etc/cron/daily > /dev/null 2>&1
+//config:      Crond is a background daemon that parses individual crontab
+//config:      files and executes commands on behalf of the users in question.
+//config:      This is a port of dcron from slackware. It uses files of the
+//config:      format /var/spool/cron/crontabs/<username> files, for example:
+//config:              $ cat /var/spool/cron/crontabs/root
+//config:              # Run daily cron jobs at 4:40 every day:
+//config:              40 4 * * * /etc/cron/daily > /dev/null 2>&1
 //config:
 //config:config FEATURE_CROND_D
-//config:      bool "Support option -d to redirect output to stderr"
+//config:      bool "Support -d (redirect output to stderr)"
 //config:      depends on CROND
 //config:      default y
 //config:      help
-//config:        -d N sets loglevel (0:most verbose) and directs all output to stderr.
+//config:      -d N sets loglevel (0:most verbose) and directs all output to stderr.
 //config:
 //config:config FEATURE_CROND_CALL_SENDMAIL
 //config:      bool "Report command output via email (using sendmail)"
 //config:      default y
 //config:      depends on CROND
 //config:      help
-//config:        Command output will be sent to corresponding user via email.
+//config:      Command output will be sent to corresponding user via email.
 //config:
 //config:config FEATURE_CROND_SPECIAL_TIMES
 //config:      bool "Support special times (@reboot, @daily, etc) in crontabs"
 //config:      default y
 //config:      depends on CROND
 //config:      help
-//config:        string        meaning
-//config:        ------        -------
-//config:        @reboot       Run once, at startup
-//config:        @yearly       Run once a year:  "0 0 1 1 *"
-//config:        @annually     Same as @yearly:  "0 0 1 1 *"
-//config:        @monthly      Run once a month: "0 0 1 * *"
-//config:        @weekly       Run once a week:  "0 0 * * 0"
-//config:        @daily        Run once a day:   "0 0 * * *"
-//config:        @midnight     Same as @daily:   "0 0 * * *"
-//config:        @hourly       Run once an hour: "0 * * * *"
+//config:      string        meaning
+//config:      ------        -------
+//config:      @reboot       Run once, at startup
+//config:      @yearly       Run once a year:  "0 0 1 1 *"
+//config:      @annually     Same as @yearly:  "0 0 1 1 *"
+//config:      @monthly      Run once a month: "0 0 1 * *"
+//config:      @weekly       Run once a week:  "0 0 * * 0"
+//config:      @daily        Run once a day:   "0 0 * * *"
+//config:      @midnight     Same as @daily:   "0 0 * * *"
+//config:      @hourly       Run once an hour: "0 * * * *"
 //config:
 //config:config FEATURE_CROND_DIR
 //config:      string "crond spool directory"
 //config:      default "/var/spool/cron"
 //config:      depends on CROND || CRONTAB
 //config:      help
-//config:        Location of crond spool.
+//config:      Location of crond spool.
 
 //applet:IF_CROND(APPLET(crond, BB_DIR_USR_SBIN, BB_SUID_DROP))
 
@@ -79,9 +79,9 @@
 #include "common_bufsiz.h"
 #include <syslog.h>
 
-/* glibc frees previous setenv'ed value when we do next setenv()
- * of the same variable. uclibc does not do this! */
-#if (defined(__GLIBC__) && !defined(__UCLIBC__)) /* || OTHER_SAFE_LIBC... */
+#if 0
+/* If libc tracks and reuses setenv()-allocated memory, ok to set this to 0 */
+/* Neither glibc nor uclibc do that! */
 # define SETENV_LEAKS 0
 #else
 # define SETENV_LEAKS 1
@@ -153,6 +153,7 @@ struct globals {
        const char *log_filename;
        const char *crontab_dir_name; /* = CRONTABS; */
        CronFile *cron_files;
+       char *default_shell;
 #if SETENV_LEAKS
        char *env_var_user;
        char *env_var_home;
@@ -471,6 +472,19 @@ static void load_crontab(const char *fileName)
                                shell = xstrdup(&tokens[0][6]);
                                continue;
                        }
+//TODO: handle HOME= too? "man crontab" says:
+//name = value
+//
+//where the spaces around the equal-sign (=) are optional, and any subsequent
+//non-leading spaces in value will be part of the value assigned to name.
+//The value string may be placed in quotes (single or double, but matching)
+//to preserve leading or trailing blanks.
+//
+//Several environment variables are set up automatically by the cron(8) daemon.
+//SHELL is set to /bin/sh, and LOGNAME and HOME are set from the /etc/passwd
+//line of the crontab's owner. HOME and SHELL may be overridden by settings
+//in the crontab; LOGNAME may not.
+
 #if ENABLE_FEATURE_CROND_SPECIAL_TIMES
                        if (tokens[0][0] == '@') {
                                /*
@@ -499,13 +513,12 @@ static void load_crontab(const char *fileName)
                                        if (strcmp(e->name, tokens[0] + 1) == 0) {
                                                /*
                                                 * tokens[1] is only the first word of command,
+                                                * can'r use it.
                                                 * find the entire command in unmodified string:
                                                 */
-                                               tokens[5] = strstr(
-                                                       skip_non_whitespace(skip_whitespace(parser->data)),
-                                                       /* ^^^^ avoids mishandling e.g. "@daily aily PARAM" */
-                                                       tokens[1]
-                                               );
+                                               tokens[5] = skip_whitespace(
+                                                       skip_non_whitespace(
+                                                       skip_whitespace(parser->data)));
                                                if (e->tokens[0]) {
                                                        char *et = (char*)e->tokens;
                                                        /* minute is "0" for all specials */
@@ -524,19 +537,6 @@ static void load_crontab(const char *fileName)
                                continue; /* bad line (unrecognized '@foo') */
                        }
 #endif
-//TODO: handle HOME= too? "man crontab" says:
-//name = value
-//
-//where the spaces around the equal-sign (=) are optional, and any subsequent
-//non-leading spaces in value will be part of the value assigned to name.
-//The value string may be placed in quotes (single or double, but matching)
-//to preserve leading or trailing blanks.
-//
-//Several environment variables are set up automatically by the cron(8) daemon.
-//SHELL is set to /bin/sh, and LOGNAME and HOME are set from the /etc/passwd
-//line of the crontab's owner. HOME and SHELL may be overridden by settings
-//in the crontab; LOGNAME may not.
-
                        /* check if a minimum of tokens is specified */
                        if (n < 6)
                                continue;
@@ -701,7 +701,7 @@ fork_job(const char *user, int mailFd, CronLine *line, bool run_sendmail)
                goto err;
        }
 
-       shell = line->cl_shell ? line->cl_shell : DEFAULT_SHELL;
+       shell = line->cl_shell ? line->cl_shell : G.default_shell;
        prog = run_sendmail ? SENDMAIL : shell;
 
        set_env_vars(pas, shell);
@@ -847,7 +847,7 @@ static pid_t start_one_job(const char *user, CronLine *line)
        }
 
        /* Prepare things before vfork */
-       shell = line->cl_shell ? line->cl_shell : DEFAULT_SHELL;
+       shell = line->cl_shell ? line->cl_shell : G.default_shell;
        set_env_vars(pas, shell);
 
        /* Fork as the user in question and run program */
@@ -1021,13 +1021,17 @@ int crond_main(int argc UNUSED_PARAM, char **argv)
 
        INIT_G();
 
-       /* "-b after -f is ignored", and so on for every pair a-b */
-       opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l")
+       opts = getopt32(argv, "^"
+                       "l:L:fbSc:" IF_FEATURE_CROND_D("d:")
+                       "\0"
+                       /* "-b after -f is ignored", and so on for every pair a-b */
+                       "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l")
                        /* -l and -d have numeric param */
-                       ":l+" IF_FEATURE_CROND_D(":d+");
-       opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"),
+                       ":l+" IF_FEATURE_CROND_D(":d+")
+                       ,
                        &G.log_level, &G.log_filename, &G.crontab_dir_name
-                       IF_FEATURE_CROND_D(,&G.log_level));
+                       IF_FEATURE_CROND_D(,&G.log_level)
+       );
        /* both -d N and -l N set the same variable: G.log_level */
 
        if (!(opts & OPT_f)) {
@@ -1046,6 +1050,10 @@ int crond_main(int argc UNUSED_PARAM, char **argv)
 
        reopen_logfile_to_stderr();
        xchdir(G.crontab_dir_name);
+       /* $SHELL, or current UID's shell, or DEFAULT_SHELL */
+       /* Useful on Android where DEFAULT_SHELL /bin/sh may not exist */
+       G.default_shell = xstrdup(get_shell_name());
+
        log8("crond (busybox "BB_VER") started, log level %d", G.log_level);
        rescan_crontab_dir();
        write_pidfile(CONFIG_PID_FILE_PATH "/crond.pid");