I recently started using Alpine Linux, and ran into an issue where my
user could no longer use the @reboot cron feature to define its own
startup jobs.  Attached is a patch to add support for the named times
found here: https://linux.die.net/man/5/crontab.

size -A -d miscutils/crond.o change:
section                      original  patch
.rodata.str1.1                    693    775
.text.start_jobs                    0    382
.text.load_crontab                804   1031
.text.crond_main                 1535   1363
.rodata                             0     50
.rodata.SpecAry                     0    144
Total                            4953   5666

Jon
diff --git a/miscutils/crond.c b/miscutils/crond.c
index 88e7b47..c65ffd9 100644
--- a/miscutils/crond.c
+++ b/miscutils/crond.c
@@ -35,6 +35,22 @@
 //config:      help
 //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)
+//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)
+//config:        @hourly       Run once an hour, "0 * * * *"
+//config:
 //config:config FEATURE_CROND_DIR
 //config:      string "crond spool directory"
 //config:      default "/var/spool/cron"
@@ -74,6 +90,8 @@
 
 #define CRON_DIR        CONFIG_FEATURE_CROND_DIR
 #define CRONTABS        CONFIG_FEATURE_CROND_DIR "/crontabs"
+#define CRON_REBOOT     CONFIG_PID_FILE_PATH "/crond.reboot"
+#define DELIMS          "# \t"
 #ifndef SENDMAIL
 # define SENDMAIL       "sendmail"
 #endif
@@ -107,6 +125,9 @@ typedef struct CronLine {
 #endif
        char *cl_shell;
        /* ordered by size, not in natural order. makes code smaller: */
+#if ENABLE_FEATURE_CROND_SPECIAL_TIMES
+       char cl_Reboot;                 /* is reboot command */
+#endif
        char cl_Dow[7];                 /* 0-6, beginning sunday */
        char cl_Mons[12];               /* 0-11 */
        char cl_Hrs[24];                /* 0-23 */
@@ -114,6 +135,13 @@ typedef struct CronLine {
        char cl_Mins[60];               /* 0-59 */
 } CronLine;
 
+#if ENABLE_FEATURE_CROND_SPECIAL_TIMES
+typedef struct SpecialEntry {
+       const char *name;
+       const char *tokens;
+} SpecialEntry;
+#endif
+
 
 #define DAEMON_UID 0
 
@@ -200,6 +228,20 @@ static const char MonAry[] ALIGN1 =
        "jan""feb""mar""apr""may""jun""jul""aug""sep""oct""nov""dec"
 ;
 
+#if ENABLE_FEATURE_CROND_SPECIAL_TIMES
+static const SpecialEntry SpecAry[] = {
+       { "reboot",     NULL                        },
+       { "yearly",     "0\0" "0\0" "1\0" "1\0" "*" },
+       { "annually",   "0\0" "0\0" "1\0" "1\0" "*" },
+       { "monthly",    "0\0" "0\0" "1\0" "*\0" "*" },
+       { "weekly",     "0\0" "0\0" "*\0" "*\0" "0" },
+       { "daily",      "0\0" "0\0" "*\0" "*\0" "*" },
+       { "midnight",   "0\0" "0\0" "*\0" "*\0" "*" },
+       { "hourly",     "0\0" "*\0" "*\0" "*\0" "*" },
+       { NULL,         NULL                        }
+};
+#endif
+
 static void ParseField(char *user, char *ary, int modvalue, int off,
                                const char *names, char *ptr)
 /* 'names' is a pointer to a set of 3-char abbreviations */
@@ -433,7 +475,7 @@ static void load_crontab(const char *fileName)
                                break;
                        }
 
-                       n = config_read(parser, tokens, 6, 1, "# \t", 
PARSE_NORMAL | PARSE_KEEP_COPY);
+                       n = config_read(parser, tokens, 6, 1, DELIMS, 
PARSE_NORMAL | PARSE_KEEP_COPY);
                        if (!n)
                                break;
 
@@ -452,6 +494,27 @@ static void load_crontab(const char *fileName)
                                shell = xstrdup(&tokens[0][6]);
                                continue;
                        }
+#if ENABLE_FEATURE_CROND_SPECIAL_TIMES
+                       if (tokens[0][0] == '@') {
+                               if (n < 2)
+                                       continue;
+                               for (const SpecialEntry *e = SpecAry; e->name 
!= NULL; ++e) {
+                                       if (strcmp(e->name, tokens[0] + 1) == 
0) {
+                                               if (e->tokens != NULL) {
+                                                       for (int i = 0; i < 5; 
++i)
+                                                               tokens[i] = 
(char *)e->tokens + 2 * i;
+                                               } else {
+                                                       tokens[0] = NULL;
+                                               }
+                                               tokens[5] = parser->data + 
strspn(parser->data, DELIMS);
+                                               tokens[5] += strcspn(tokens[5], 
DELIMS);
+                                               tokens[5] += strspn(tokens[5], 
DELIMS);
+                                               n = 6;
+                                               break;
+                                       }
+                               }
+                       }
+#endif
 //TODO: handle HOME= too? "man crontab" says:
 //name = value
 //
@@ -469,6 +532,13 @@ static void load_crontab(const char *fileName)
                        if (n < 6)
                                continue;
                        *pline = line = xzalloc(sizeof(*line));
+#if ENABLE_FEATURE_CROND_SPECIAL_TIMES
+                       if (tokens[0] == NULL) {
+                               line->cl_Reboot = 1;
+                       }
+                       else
+#endif
+                       {
                                /* parse date ranges */
                                ParseField(file->cf_username, line->cl_Mins, 
60, 0, NULL, tokens[0]);
                                ParseField(file->cf_username, line->cl_Hrs, 24, 
0, NULL, tokens[1]);
@@ -480,6 +550,7 @@ static void load_crontab(const char *fileName)
                                 * is "*", the other is set to 0, and vise-versa
                                 */
                                FixDayDow(line);
+                       }
 #if ENABLE_FEATURE_CROND_CALL_SENDMAIL
                        /* copy mailto (can be NULL) */
                        line->cl_mailto = xstrdup(mailTo);
@@ -834,6 +905,44 @@ static void flag_starting_jobs(time_t t1, time_t t2)
        }
 }
 
+#if ENABLE_FEATURE_CROND_SPECIAL_TIMES
+static int touch_reboot_file(void)
+{
+       if (access(CRON_REBOOT, R_OK | W_OK) == -1) {
+               close(open(CRON_REBOOT, O_WRONLY | O_CREAT, 0000));
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+static void flag_reboot_jobs(void)
+{
+       CronFile *file;
+       CronLine *line;
+
+       for (file = G.cron_files; file; file = file->cf_next) {
+               log5("file %s:", file->cf_username);
+               if (file->cf_deleted)
+                       continue;
+               for (line = file->cf_lines; line; line = line->cl_next) {
+                       log5(" line %s", line->cl_cmd);
+                       if (line->cl_Reboot) {
+                               log5(" job: %d %s",
+                                               (int)line->cl_pid, 
line->cl_cmd);
+                               if (line->cl_pid > 0) {
+                                       log8("user %s: process already running: 
%s",
+                                               file->cf_username, 
line->cl_cmd);
+                               } else if (line->cl_pid == 0) {
+                                       line->cl_pid = -1;
+                                       file->cf_wants_starting = 1;
+                               }
+                       }
+               }
+       }
+}
+#endif
+
 static void start_jobs(void)
 {
        CronFile *file;
@@ -950,6 +1059,12 @@ int crond_main(int argc UNUSED_PARAM, char **argv)
        log8("crond (busybox "BB_VER") started, log level %d", G.log_level);
        rescan_crontab_dir();
        write_pidfile(CONFIG_PID_FILE_PATH "/crond.pid");
+#if ENABLE_FEATURE_CROND_SPECIAL_TIMES
+       if (touch_reboot_file()) {
+               flag_reboot_jobs();
+               start_jobs();
+       }
+#endif
 
        /* Main loop */
        t2 = time(NULL);
_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to