On Thu, 26 Jul 2001, Matthew Jacob wrote:
> It'd be nice if one could pass a time specification to at in the form
> of "next reboot".
>
> -matt
On Thu, 26 Jul 2001, Matthew Emmerton replied:
> Why not just write a script for the command and stick it in
> /usr/local/etc/rc.d?
>
> -- Matt Emmerton
On Thu, Jul 26, 2001 at 03:45:58PM -0700, Matthew Jacob replied:
> Because I thought this might be of general utility.
Okay, try the attached patch. If this is really something that might be
generally usefully I can submit the patch as a PR.
It allows "at reboot" and "at reboot + 1 hour", etc.
It does it by sticking the job in the queue with the filename prefixed
with "_" (yeah, a bit ugly, it was the first thing that came to me) and
with the runtime based on the epoch instead of the current time.
Adding:
@reboot root /usr/libexec/atrun -b
to /etc/crontab causes atrun(8) to rename all of these jobs adding the
current time to the jobs runtime.
% echo "echo test" | at reboot
Job 19 will be executed using /bin/sh
% echo "echo test" | at reboot + 90 minutes
Job 20 will be executed using /bin/sh
% atq
Date Owner Queue Job#
REBOOT dchapes c 19
REBOOT+01:30:00 dchapes c 20
$ date; /usr/libexec/atrun -b
% atq -v
Date Owner Queue Job#
22:34:00 07/26/01 dchapes c 20
21:04:00 07/26/01 dchapes c(done) 19
--
Dave Chapeskie <[EMAIL PROTECTED]>
OpenPGP Key KeyId: 3D2B6B34
Index: usr.bin/at/at.h
===================================================================
RCS file: /cvs/FreeBSD/src/usr.bin/at/at.h,v
retrieving revision 1.5
diff -u -r1.5 at.h
--- usr.bin/at/at.h 2001/07/24 14:15:51 1.5
+++ usr.bin/at/at.h 2001/07/26 22:38:53
@@ -29,3 +29,4 @@
extern char *namep;
extern char atfile[];
extern char atverify;
+extern int reboot_time;
Index: usr.bin/at/parsetime.c
===================================================================
RCS file: /cvs/FreeBSD/src/usr.bin/at/parsetime.c,v
retrieving revision 1.21
diff -u -r1.21 parsetime.c
--- usr.bin/at/parsetime.c 2001/07/24 14:15:51 1.21
+++ usr.bin/at/parsetime.c 2001/07/26 23:28:28
@@ -25,7 +25,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * at [NOW] PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS
+ * at [NOW|REBOOT] PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS
* /NUMBER [DOT NUMBER] [AM|PM]\ /[MONTH NUMBER [NUMBER]] \
* |NOON | |[TOMORROW] |
* |MIDNIGHT | |[DAY OF WEEK] |
@@ -63,7 +63,7 @@
enum { /* symbols */
MIDNIGHT, NOON, TEATIME,
- PM, AM, TOMORROW, TODAY, NOW,
+ PM, AM, TOMORROW, TODAY, NOW, REBOOT,
MINUTES, HOURS, DAYS, WEEKS, MONTHS, YEARS,
NUMBER, PLUS, DOT, SLASH, ID, JUNK,
JAN, FEB, MAR, APR, MAY, JUN,
@@ -86,6 +86,7 @@
{ "tomorrow", TOMORROW,0 }, /* execute 24 hours from time */
{ "today", TODAY, 0 }, /* execute today - don't advance time */
{ "now", NOW,0 }, /* opt prefix for PLUS */
+ { "reboot", REBOOT, 0 }, /* execute on next reboot */
{ "minute", MINUTES,0 }, /* minutes multiplier */
{ "minutes", MINUTES,1 }, /* (pluralized) */
@@ -280,7 +281,7 @@
/*
* plus() parses a now + time
*
- * at [NOW] PLUS NUMBER [MINUTES|HOURS|DAYS|WEEKS|MONTHS|YEARS]
+ * at [NOW|REBOOT] PLUS NUMBER [MINUTES|HOURS|DAYS|WEEKS|MONTHS|YEARS]
*
*/
@@ -563,6 +564,7 @@
*/
time_t nowtimer, runtimer;
struct tm nowtime, runtime;
+ int t;
int hr = 0;
/* this MUST be initialized to zero for midnight/noon/teatime */
@@ -579,6 +581,22 @@
init_scanner(argc-optind, argv+optind);
switch (token()) {
+ case REBOOT:
+ reboot_time = 1;
+ /* Reset "now" to be the epoch */
+ nowtimer = 0;
+ nowtime = *localtime(&nowtimer);
+ runtime = nowtime;
+ runtime.tm_sec = 0;
+ runtime.tm_isdst = 0;
+
+ t = token();
+ if (t == PLUS)
+ plus(&runtime);
+ else if (t != EOF)
+ plonk(sc_tokid);
+ break;
+
case NOW: /* now is optional prefix for PLUS tree */
expect(PLUS);
case PLUS:
Index: usr.bin/at/at.c
===================================================================
RCS file: /cvs/FreeBSD/src/usr.bin/at/at.c,v
retrieving revision 1.19
diff -u -r1.19 at.c
--- usr.bin/at/at.c 2001/07/24 14:15:51 1.19
+++ usr.bin/at/at.c 2001/07/26 23:53:47
@@ -108,7 +108,8 @@
extern char **environ;
int fcreated;
-char atfile[] = ATJOB_DIR "12345678901234";
+char atfile[] = ATJOB_DIR "_Q1234512345678";
+int reboot_time = 0; /* if 'reboot' was specified */
char *atinput = (char*)0; /* where to get input from */
char atqueue = 0; /* which queue to examine for jobs (atq) */
@@ -263,6 +264,8 @@
if ((jobno = nextjob()) == EOF)
perr("cannot generate job number");
+ if (reboot_time)
+ *ppos++ = '_';
sprintf(ppos, "%c%5lx%8lx", queue,
jobno, (unsigned long) (runtimer/60));
@@ -455,7 +458,9 @@
long jobno;
time_t runtimer;
char timestr[TIMESIZE];
+ char tmp[TIMESIZE];
int first=1;
+ int after_boot;
#ifdef __FreeBSD__
(void) setlocale(LC_TIME, "");
@@ -483,22 +488,48 @@
|| !(S_IXUSR & buf.st_mode || atverify))
continue;
- if(sscanf(dirent->d_name, "%c%5lx%8lx", &queue, &jobno, &ctm)!=3)
- continue;
+ if (dirent->d_name[0] == '_') {
+ if(sscanf(dirent->d_name, "_%c%5lx%8lx", &queue, &jobno, &ctm)!=3)
+ continue;
+ after_boot = 1;
+ } else {
+ if(sscanf(dirent->d_name, "%c%5lx%8lx", &queue, &jobno, &ctm)!=3)
+ continue;
+ after_boot = 0;
+ }
if (atqueue && (queue != atqueue))
continue;
runtimer = 60*(time_t) ctm;
- runtime = *localtime(&runtimer);
- strftime(timestr, TIMESIZE, "%X %x", &runtime);
+ if (after_boot) {
+ strlcpy(timestr,"REBOOT",sizeof timestr);
+ if (ctm != 0) {
+ runtime = *gmtime(&runtimer);
+ if (runtime.tm_year != 70) { /* 1970, the epoch */
+ snprintf(tmp,sizeof tmp,"+%dyr",runtime.tm_year-70);
+ strlcat(timestr,tmp,sizeof timestr);
+ }
+ if (runtime.tm_yday != 0) {
+ snprintf(tmp,sizeof tmp,"+%dd",runtime.tm_yday);
+ strlcat(timestr,tmp,sizeof timestr);
+ }
+ if (runtime.tm_hour != 0 || runtime.tm_min != 0) {
+ strftime(tmp, sizeof tmp, "+%X", &runtime);
+ strlcat(timestr,tmp,sizeof timestr);
+ }
+ }
+ } else {
+ runtime = *localtime(&runtimer);
+ strftime(timestr, TIMESIZE, "%X %x", &runtime);
+ }
if (first) {
printf("Date\t\t\tOwner\tQueue\tJob#\n");
first=0;
}
pw = getpwuid(buf.st_uid);
- printf("%s\t%s\t%c%s\t%ld\n",
+ printf("%-18s\t%s\t%c%s\t%ld\n",
timestr,
pw ? pw->pw_name : "???",
queue,
@@ -540,8 +571,13 @@
perr("cannot stat in " ATJOB_DIR);
PRIV_END
- if(sscanf(dirent->d_name, "%c%5lx%8lx", &queue, &jobno, &ctm)!=3)
- continue;
+ if (dirent->d_name[0] == '_') {
+ if(sscanf(dirent->d_name, "_%c%5lx%8lx", &queue, &jobno, &ctm)!=3)
+ continue;
+ } else {
+ if(sscanf(dirent->d_name, "%c%5lx%8lx", &queue, &jobno, &ctm)!=3)
+ continue;
+ }
for (i=optind; i < argc; i++) {
if (atoi(argv[i]) == jobno) {
@@ -724,7 +760,7 @@
case AT:
timer = parsetime(argc, argv);
- if (atverify)
+ if (atverify && !reboot_time)
{
struct tm *tm = localtime(&timer);
fprintf(stderr, "%s\n", asctime(tm));
Index: usr.bin/at/at.man
===================================================================
RCS file: /cvs/FreeBSD/src/usr.bin/at/at.man,v
retrieving revision 1.19
diff -u -r1.19 at.man
--- usr.bin/at/at.man 2001/07/10 14:15:54 1.19
+++ usr.bin/at/at.man 2001/07/27 00:45:24
@@ -106,13 +106,20 @@
.Em today
and to run the job tomorrow by suffixing the time with
.Em tomorrow .
+And finally, you can give a time of
+.Em reboot
+or
+.Em reboot + Ar count \%time-units
+to have the job run some time after the next reboot.
.Pp
For example, to run a job at 4pm three days from now, you would do
.Nm at Ar 4pm + 3 days ,
to run a job at 10:00am on July 31, you would do
-.Nm at Ar 10am Jul 31
-and to run a job at 1am tomorrow, you would do
-.Nm at Ar 1am tomorrow .
+.Nm at Ar 10am Jul 31 ,
+to run a job at 1am tomorrow, you would do
+.Nm at Ar 1am tomorrow
+and to run a job an hour after the next reboot, you would do
+.Nm at Ar reboot + 1 hour .
.Pp
For both
.Nm
@@ -267,6 +274,17 @@
If this is the case for your site, you might want to consider another
batch system, such as
.Em nqs .
+.Pp
+The
+.Em reboot
+specification when used with a month offset doesn't always work as expected.
+For example,
+.Nm at Ar reboot + 1 month
+will in fact be turned into
+.Nm at Ar now + 31 days
+when
+.Nm atrun Fl b
+is run even if the current month does not have 31 days.
.Sh AUTHORS
At was mostly written by
.An Thomas Koenig Aq [EMAIL PROTECTED] .
Index: libexec/atrun/atrun.c
===================================================================
RCS file: /cvs/FreeBSD/src/libexec/atrun/atrun.c,v
retrieving revision 1.16
diff -u -r1.16 atrun.c
--- libexec/atrun/atrun.c 2001/07/23 11:00:31 1.16
+++ libexec/atrun/atrun.c 2001/07/27 00:10:05
@@ -392,11 +392,14 @@
char queue;
time_t now, run_time;
char batch_name[] = "Z2345678901234";
+ char job_name[] = "Q1234512345678";
uid_t batch_uid;
gid_t batch_gid;
int c;
int run_batch;
double load_avg = LOADAVG_MX;
+ int boot = 0;
+ unsigned long boot_time;
/* We don't need root privileges all the time; running under uid and gid daemon
* is fine.
@@ -407,7 +410,7 @@
openlog("atrun", LOG_PID, LOG_CRON);
opterr = 0;
- while((c=getopt(argc, argv, "dl:"))!= -1)
+ while((c=getopt(argc, argv, "bdl:"))!= -1)
{
switch (c)
{
@@ -418,6 +421,10 @@
load_avg = LOADAVG_MX;
break;
+ case 'b':
+ boot++;
+ break;
+
case 'd':
debug ++;
break;
@@ -449,6 +456,31 @@
batch_uid = (uid_t) -1;
batch_gid = (gid_t) -1;
+ if (boot) {
+ /* Scan the directory for jobs to run after reboot and rename them.
+ */
+ boot_time = (unsigned long)now/60;
+
+ while ((dirent = readdir(spool)) != NULL) {
+ if (stat(dirent->d_name,&buf) != 0)
+ perr("cannot stat in " ATJOB_DIR);
+ if (!S_ISREG(buf.st_mode))
+ continue;
+ if (debug)
+ printf ("file: %s\n", dirent->d_name);
+ if (sscanf(dirent->d_name,"_%c%5lx%8lx",&queue,&jobno,&ctm) != 3)
+ continue;
+ ctm += boot_time;
+ snprintf(job_name, sizeof(job_name), "%c%05lx%08lx",queue,
+ jobno,ctm);
+ if (rename(dirent->d_name,job_name) != 0)
+ perr("cannot rename job");
+ }
+ if (debug)
+ printf ("\n");
+ rewinddir(spool);
+ }
+
while ((dirent = readdir(spool)) != NULL) {
if (stat(dirent->d_name,&buf) != 0)
perr("cannot stat in " ATJOB_DIR);
@@ -458,9 +490,18 @@
if (!S_ISREG(buf.st_mode))
continue;
+ if (debug)
+ printf ("file: %s\n", dirent->d_name);
+
+ if (dirent->d_name[0] == '_')
+ continue;
+
if (sscanf(dirent->d_name,"%c%5lx%8lx",&queue,&jobno,&ctm) != 3)
continue;
+ if (debug)
+ printf ("\t\tqueue %c, job %ld time %ld\n", queue, jobno, ctm);
+
run_time = (time_t) ctm*60;
if ((S_IXUSR & buf.st_mode) && (run_time <=now)) {
@@ -494,9 +535,9 @@
usage()
{
if (debug)
- fprintf(stderr, "usage: atrun [-l load_avg] [-d]\n");
+ fprintf(stderr, "usage: atrun [-l load_avg] [-bd]\n");
else
- syslog(LOG_ERR, "usage: atrun [-l load_avg] [-d]");
+ syslog(LOG_ERR, "usage: atrun [-l load_avg] [-bd]");
exit(EXIT_FAILURE);
}
Index: libexec/atrun/atrun.man
===================================================================
RCS file: /cvs/FreeBSD/src/libexec/atrun/atrun.man,v
retrieving revision 1.10
diff -u -r1.10 atrun.man
--- libexec/atrun/atrun.man 2001/07/10 10:49:45 1.10
+++ libexec/atrun/atrun.man 2001/07/27 00:33:15
@@ -18,14 +18,39 @@
.Xr crontab 5
file
.Pa /etc/crontab
-has to contain the line
+has to contain the lines
.Bd -literal
*/5 * * * * root /usr/libexec/atrun
+@reboot root /usr/libexec/atrun -b
.Ed
.Pp
so that
.Xr atrun 8
-gets invoked every five minutes.
+gets invoked every five minutes
+plus once on reboot with the
+.Fl b
+option.
+.Pp
+If the
+.Fl b
+option is specified then
+.Nm
+looks for jobs queued using the
+.Em reboot
+time specification of
+.Xr at 1
+and changes them into normal jobs with the time offset from the current
+time.
+For example, a job originally queued with
+.Dq at roboot + 5 minutes
+would be requeued as if
+.Dq at now + 5 minutes
+were used with
+.Em now
+being the time
+.Nm
+is run with
+.Fl b .
.Pp
At every invocation,
.Nm
Index: etc/crontab
===================================================================
RCS file: /cvs/FreeBSD/src/etc/crontab,v
retrieving revision 1.31
diff -u -r1.31 crontab
--- etc/crontab 2001/02/19 02:47:41 1.31
+++ etc/crontab 2001/07/27 00:46:55
@@ -9,6 +9,7 @@
#minute hour mday month wday who command
#
*/5 * * * * root /usr/libexec/atrun
+@reboot root /usr/libexec/atrun -b
#
# save some entropy so that /dev/random can reseed on boot
*/11 * * * * operator /usr/libexec/save-entropy
PGP signature