Commit Diff


commit - d84619f38238a58126adf8d62870c7fc8593aca5
commit + 2d331b3f3d70a5e5bf1362ff9e23627f0ca15288
blob - 4a9419a0ddac0891c65b10ea7ab7e5150a51e051
blob + 08c1f3f3b37b555c2e7c4d573e06af93601a01d3
--- commands.c
+++ commands.c
@@ -82,6 +82,7 @@ static int	doconfig(int, char**);
 static int	exitconfig(int, char**);
 int		rtable(int, char**);
 int		group(int, char**);
+static int	pr_crontab(int, char **, FILE *);
 static int	pr_routes(int, char **);
 static int	pr_routes6(int, char **);
 static int	pr_arp(int, char **);
@@ -448,6 +449,8 @@ Menu showlist[] = {
 	{ "monitor",	"Monitor routing/arp table changes", CMPL0 0, 0, 0, 0, monitor },
 	{ "version",	"Software information",	CMPL0 0, 0, 0, 0, version },
 	{ "users",	"System users",		CMPL0 0, 0, 0, 0, who },
+	{ "crontab",	"Scheduled background jobs",	CMPL0 0, 0, 0, 0, pr_crontab },
+	{ "scheduler",	"Scheduled background jobs",	CMPL0 0, 0, 0, 0, pr_crontab },
 	{ "running-config",	"Operating configuration", CMPL0 0, 0, 0, 0, pr_conf },
 	{ "startup-config", "Startup configuration", CMPL0 0, 0, 0, 0, pr_s_conf },
 	{ "active-config", "Configuration of active context", CMPL0 0, 0, 0, 0, pr_a_conf },
@@ -1062,6 +1065,7 @@ static char tracerthelp[];
 static char tracert6help[];
 static char sshhelp[];
 static char telnethelp[];
+static char crontabhelp[];
 static char showhelp[];
 static char whohelp[];
 static char dohelp[];
@@ -1698,6 +1702,7 @@ static char
 	tracert6help[] ="Print the route to IPv6 host",
 	sshhelp[] =	"SSH connection to remote host",
 	telnethelp[] =	"Telnet connection to remote host",
+	crontabhelp[] =	"Configure scheduled background jobs",
 	quithelp[] =	"Close current connection",
 	exithelp[] =	"Leave configuration mode and return to privileged mode",
 	verbosehelp[] =	"Set verbose diagnostics",
@@ -1755,6 +1760,7 @@ struct ghs mantab[] = {
 	{ "carp", "Search for tag carp", CMPL0 NULL, 0 },
 	{ "config", "Search for tag config", CMPL0 NULL, 0 },
 	{ "configure", "Search for tag configure", CMPL0 NULL, 0 },
+	{ "crontab", "Search for tag crontab", CMPL0 NULL, 0 },
 	{ "csh", "Search for tag csh", CMPL0 NULL, 0 },
 	{ "ddb", "Search for tag ddb", CMPL0 NULL, 0 },
 	{ "dhcp", "Search for tag dhcp", CMPL0 NULL, 0 },
@@ -1848,6 +1854,7 @@ struct ghs mantab[] = {
 	{ "sadb", "Search for tag sadb", CMPL0 NULL, 0 },
 	{ "sasync", "Search for tag sasync", CMPL0 NULL, 0 },
 	{ "sasyncd", "Search for tag sasyncd", CMPL0 NULL, 0 },
+	{ "scheduler", "Search for tag scheduler", CMPL0 NULL, 0 },
 	{ "sensor", "Search for tag sensor", CMPL0 NULL, 0 },
 	{ "sh", "Search for tag sh", CMPL0 NULL, 0 },
 	{ "shell", "Search for tag shell", CMPL0 NULL, 0 },
@@ -1939,6 +1946,8 @@ Command cmdtab[] = {
 	{ "tftp",	tftphelp,	CMPL(t) (char **)ctl_tftp, ssctl, ctlhandler,	1, 1, 0, 1 },
 	{ "resolv",	resolvhelp,	CMPL(t) (char **)ctl_resolv, ssctl, ctlhandler, 1, 1, 0, 1 },
 	{ "motd",       motdhelp,       CMPL(t) (char **)ctl_motd, ssctl, ctlhandler,    1, 1, 0, 1 },
+	{ "crontab",    crontabhelp,    CMPL(t) (char **)ctl_crontab, ssctl, ctlhandler,    1, 1, 0, 1 },
+	{ "scheduler",  crontabhelp,    CMPL(t) (char **)ctl_crontab, ssctl, ctlhandler,    1, 1, 0, 1 },
 	{ "inet",	inethelp,	CMPL(t) (char **)ctl_inet, ssctl, ctlhandler,	1, 1, 0, 1 },
 	{ "ping",	pinghelp,	CMPL0 0, 0, ping,		0, 0, 0, 0 },
 	{ "ping6",	ping6help,	CMPL0 0, 0, ping6,		0, 0, 0, 0 },
@@ -3216,6 +3225,26 @@ done:
 	return 0;
 }
 
+static int
+pr_crontab(int argc, char **argv, FILE *outfile)
+{
+	char *crontab_argv[] = { CRONTAB, "-l", "-u", "root", NULL };
+
+	if (priv != 1) {
+		printf("%% Privilege required\n");
+		return 0 ;
+	}
+
+	fprintf(outfile, "%% To view crontab syntax documentation in NSH, "
+	    "run: !man 5 crontab\n\n");
+	fflush(outfile);
+
+	if (cmdargs_output(CRONTAB, crontab_argv, fileno(outfile), -1) != 0)
+		printf("%% crontab command failed\n");
+
+	return 0;
+}
+
 int
 pr_routes(int argc, char **argv)
 {
blob - 224415e3acd5fe0a9b7ad75a76edc348fd0c37e5
blob + 84ff64c42be556f8392417b7ba5f35c45332fff5
--- conf.c
+++ conf.c
@@ -187,6 +187,7 @@ conf(FILE *output)
 {
 	char cpass[_PASSWORD_LEN+1];
 	char hostbuf[MAXHOSTNAMELEN];
+	off_t offset;
 
 	fprintf(output, "!\n");
 
@@ -285,6 +286,11 @@ conf(FILE *output)
 	conf_ctl(output, "", "ftp-proxy", 0);
 	conf_ctl(output, "", "inet", 0);
 	conf_ctl(output, "", "sshd", 0);
+
+	offset = ftello(output);
+	conf_ctl(output, "", "crontab", 0);
+	if (offset != ftello(output)) /* we have custom crontab rules */
+		fprintf(output, "crontab install\n");
 
 	conf_rtables(output);
 
blob - b617dc27b60cd8856efb13d9b6dc0718eacfe45a
blob + e00aca8725b24f1c83a3c52d34067c81b03e0337
--- ctl.c
+++ ctl.c
@@ -32,7 +32,10 @@
 static char table[16];
 
 /* service routines */
+void edit_crontab(char *, char **, char *);
+void install_crontab(char *, char **, char *);
 void call_editor(char *, char **, char *);
+int edit_file(char *, mode_t, char *, char **);
 void ctl_symlink(char *, char *, char *);
 int rule_writeline(char *, mode_t, char *);
 int fill_tmpfile(char **, char *, char **);
@@ -69,11 +72,23 @@ struct daemons ctl_daemons[] = {
 { "ldap",	"LDAP",	ctl_ldap,	LDAPCONF_TEMP,	0600, 0, RT_TABLEID_MAX },
 { "ifstate",	"If state",ctl_ifstate,	IFSTATECONF_TEMP,0600, 0, RT_TABLEID_MAX },
 { "motd",        "MOTD",  ctl_motd,        MOTD_TEMP,0644, 0, 0 },
+{ "crontab",	"crontab",  ctl_crontab, CRONTAB_TEMP, 0600, 0, 0 },
+{ "scheduler",	"scheduler",  ctl_crontab, CRONTAB_TEMP, 0600, 0, 0 },
 { 0, 0, 0, 0, 0, 0 }
 };
 
 /* per-daemon commands, and their C or executable functions */ 
+
+/* CRONTAB */
+struct ctl ctl_crontab[] = {
+        { "edit",           "edit scheduled background jobs",
+            { "crontab", NULL, NULL }, edit_crontab, 0, T_HANDLER },
+        { "install",           "install scheduled background job config",
+            { "crontab", NULL, NULL }, install_crontab, 0, T_HANDLER },
+        { 0, 0, { 0 }, 0, 0, 0 }
+};
 
+
 /* MOTD */
 struct ctl ctl_motd[] = {
         { "edit",           "edit message-of-the-day",
@@ -697,10 +712,62 @@ fill_tmpfile(char **fillargs, char *tmpfile, char **tm
 }
 
 void
-call_editor(char *name, char **args, char *z)
+edit_crontab(char *name, char **args, char *z)
+{
+	char *crontab_argv[] = { CRONTAB, "-u", "root", "-l", NULL };
+	char tmpfile[PATH_MAX];
+	int found = 0;
+	struct daemons *daemons;
+	int fd = -1;
+
+	for (daemons = ctl_daemons; daemons->name != 0; daemons++)
+		if (strncmp(daemons->name, name, strlen(name)) == 0) {
+			found = 1;
+			break;
+		}
+
+	if (!found) {
+		printf("%% edit_crontab internal error\n");
+		return;
+	}
+
+	snprintf(tmpfile, sizeof(tmpfile), "%s.%d", daemons->tmpfile,
+	    cli_rtable);
+
+	fd = open(tmpfile, O_RDWR | O_EXCL);
+	if (fd == -1) {
+		if (errno != ENOENT) {
+			printf("%% open %s: %s\n", tmpfile, strerror(errno));
+			return;
+		}
+		fd = open(tmpfile, O_RDWR | O_CREAT | O_EXCL, daemons->mode);
+		if (fd == -1) {
+			printf("%% open %s: %s\n", tmpfile, strerror(errno));
+			return;
+		}
+
+		/* Populate temporary file with current crontab. */
+		if (cmdargs_output(CRONTAB, crontab_argv, fd, -1) != 0) {
+			printf("%% crontab -l command failed\n");
+			goto done;
+		}
+	}
+
+	if (edit_file(tmpfile, daemons->mode, daemons->propername, args) == 0) {
+		crontab_argv[3] = tmpfile;
+		if (cmdargs(CRONTAB, crontab_argv) != 0)
+			printf("%% failed to install crontab\n");
+	}
+done:
+	close(fd);
+}
+
+void
+install_crontab(char *name, char **args, char *z)
 {
+	char *crontab_argv[] = { CRONTAB, "-u", "root", NULL, NULL };
+	char tmpfile[PATH_MAX];
 	int fd, found = 0;
-	char *editor, tmpfile[64];
 	struct daemons *daemons;
 
 	for (daemons = ctl_daemons; daemons->name != 0; daemons++)
@@ -710,6 +777,35 @@ call_editor(char *name, char **args, char *z)
 		}
 
 	if (!found) {
+		printf("%% install_crontab internal error\n");
+		return;
+	}
+
+	snprintf(tmpfile, sizeof(tmpfile), "%s.%d", daemons->tmpfile,
+	    cli_rtable);
+
+	if ((fd = acq_lock(tmpfile)) > 0) {
+		crontab_argv[3] = tmpfile;
+		if (cmdargs(CRONTAB, crontab_argv) != 0)
+			printf("%% failed to install crontab\n");
+		rls_lock(fd);
+	}
+}
+
+void
+call_editor(char *name, char **args, char *z)
+{
+	int found = 0;
+	char tmpfile[64];
+	struct daemons *daemons;
+
+	for (daemons = ctl_daemons; daemons->name != 0; daemons++)
+		if (strncmp(daemons->name, name, strlen(name)) == 0) {
+			found = 1;
+			break;
+		}
+
+	if (!found) {
 		printf("%% call_editor internal error\n");
 		return;
 	}
@@ -717,6 +813,16 @@ call_editor(char *name, char **args, char *z)
 	snprintf(tmpfile, sizeof(tmpfile), "%s.%d", daemons->tmpfile,
 	    cli_rtable);
 
+	edit_file(tmpfile, daemons->mode, daemons->propername, args);
+}
+
+int
+edit_file(char *tmpfile, mode_t mode, char *propername, char **args)
+{
+	char *editor;
+	int fd;
+	int ret = 0;
+
 	/* acq lock, call editor, test config with cmd and args, release lock */
 	if ((editor = getenv("VISUAL")) == NULL) {
 		if ((editor = getenv("EDITOR")) == NULL)
@@ -724,14 +830,22 @@ call_editor(char *name, char **args, char *z)
 	}
 	if ((fd = acq_lock(tmpfile)) > 0) {
 		char *argv[] = { editor, tmpfile, NULL };
-		cmdargs(editor, argv);
-		chmod(tmpfile, daemons->mode);
-		if (args != NULL)
-			cmdargs(args[0], args);
+		ret = cmdargs(editor, argv);
+		if (ret == 0 && chmod(tmpfile, mode) == -1) {
+			printf("%% chmod %o %s: %s\n",
+			    mode, tmpfile, strerror(errno));
+			ret = 1;
+		}
+		if (ret == 0 && args != NULL)
+			ret = cmdargs(args[0], args);
 		rls_lock(fd);
-	} else
+	} else {
 		printf ("%% %s configuration is locked for editing\n",
-		    daemons->propername);
+		    propername);
+		return 1;
+	}
+
+	return ret;
 }
 
 int
blob - 2ae9f799551bdf7081e8be62c03b4b7a8f97f104
blob + 23cea48dd84cd5bce7b4c64b2ebd91bbf33f4f0a
--- ctl.h
+++ ctl.h
@@ -121,6 +121,7 @@ struct daemons {
 #define LDAPCONF_TEMP   "/var/run/ldapd.conf"
 #define IFSTATECONF_TEMP "/var/run/ifstated.conf"
 #define MOTD_TEMP "/var/run/motd"
+#define CRONTAB_TEMP     "/var/run/crontab"
 
 /* ctl tests*/
 extern char *ctl_bgp_test[];
@@ -178,5 +179,6 @@ extern struct ctl ctl_dns[];
 extern struct ctl ctl_inet[];
 extern struct ctl ctl_ldap[];
 extern struct ctl ctl_motd[];
+extern struct ctl ctl_crontab[];
 extern struct ctl ctl_resolv[];
 void flag_x(char *, char *, int, char *);
blob - 610184e1adf628ff1d5a11f25b77b38f302ad923
blob + a1f2ecea9d8252e146f3e086eba407199cdc685d
--- externs.h
+++ externs.h
@@ -167,6 +167,7 @@ extern pid_t child;
 #define SSH		"/usr/bin/ssh"
 #define PKILL		"/usr/bin/pkill"
 #define DIFF		"/usr/bin/diff"
+#define CRONTAB		"/usr/bin/crontab"
 #define REBOOT		"/sbin/reboot"
 #define HALT		"/sbin/halt"
 #define SU		"/usr/bin/su"
blob - 83288f6f5bc17abddbcf6da9eed5f016be75e964
blob + 1e1153b1ba8b2989aead1c19f5b9d61ee615af12
--- nsh.8
+++ nsh.8
@@ -1680,7 +1680,43 @@ The
 .Ar options
 are documented in
 .Xr telnet 1 .
+.Pp
+.Tg crontab
+.Ic crontab Op Cm edit | install
+.Pp
+Edit the configuration of scheduled background jobs which are
+managed by
+.Xr cron 8 .
+Only the crontab file of the root user can be edited.
+See the
+.Xr crontab 5
+man page for information about configuration file syntax.
+.Pp
+.Nm
+stores a private copy of the root user's crontab in
+.Pa /var/run/crontab.0 .
+The
+.Cm crontab edit
+command edits this file and then installs it to the system by running the
+.Xr crontab 1
+command.
+.Pp
+The
+.Cm crontab install
+command skips editing but otherwise has the same effect.
+This command can be used to overwrite the system crontab in case it has
+become out of sync with the copy managed by
+.Nm .
+.Pp
+.Tg scheduler
+.Ic scheduler Op Cm edit | install
 .Pp
+The
+.Cm scheduler
+command is an alias for the
+.Cm crontab
+command described above.
+.Pp
 .Tg reboot
 .Ic reboot
 .Pp
@@ -1772,7 +1808,7 @@ nsh/no verbose
 .Op hostname | interface | autoconf | ip | inet | inet6 | route | route6\
  | sadb | arp | ndp | vlan | kernel | bgp | ospf | ospf6 | pf | eigrp | rip\
  | ldp | ike | ipsec | dvmrp | relay | dhcp | smtp | ldap | monitor\
- | version | users | running-config | startup-config |\&? | help
+ | version | users | crontab | running-config | startup-config |\&? | help
 .Pp
 The main diagnostic and informational command is 'show'.
 show without arguments  displays the available diagnostic show sub commands.
@@ -1815,6 +1851,7 @@ nsh(p)/show
   monitor         Monitor routing/arp table changes
   version         Software information
   users           System users
+  crontab         Scheduled background jobs
   running-config  Operating configuration
   startup-config  Startup configuration
   ?               Options
@@ -2615,7 +2652,22 @@ memory: 8175MB
 kernel: OpenBSD 7.1 (GENERIC.MP) #459: Mon Apr  4 18:16:13 MDT 2022
     deraadt@amd64.openbsd.org:/usr/src/sys/arch/amd64/compile/GENERIC.MP
 .Ed
+.Pp
+.Ic show crontab
+.Pp
+Display the scheduled background jobs of the root user which are
+managed by
+.Xr cron 8 .
+See the
+.Xr crontab 5
+manual page for information about scheduling rules syntax.
+.Pp
+.Ic show scheduler
 .Pp
+Alias for the
+.Cm show crontab
+command described above.
+.Pp
 .Ic show running-config
 .Pp
 Display the current running configuration on the system, including