commit 2d331b3f3d70a5e5bf1362ff9e23627f0ca15288 from: Chris Cappuccio via: GitHub date: Fri Jun 09 17:00:15 2023 UTC Merge pull request #138 from stspdotname/cron add crontab commands: show crontab, crontab edit, crontab install 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