[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