[prev in list] [next in list] [prev in thread] [next in thread]
List: busybox
Subject: Add special times support to crond
From: Jonathan Kolb <kolbyjack () gmail ! com>
Date: 2017-06-22 18:24:38
Message-ID: CAB4zcx5Y_9Ed2pd2bHBP84YfKsnrcvf+i7xpCP1ZZWMQQoc-2A () mail ! gmail ! com
[Download RAW message or body]
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
["crond-special-times.patch.txt" (text/plain)]
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
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic