From owner-freebsd-hackers Thu Jul 26 18:18: 3 2001 Delivered-To: freebsd-hackers@freebsd.org Received: from squigy.ddm.crosswinds.net (p31b.neon3.sentex.ca [64.7.131.47]) by hub.freebsd.org (Postfix) with ESMTP id 6120B37B407 for ; Thu, 26 Jul 2001 18:17:31 -0700 (PDT) (envelope-from dchapes@ddm.crosswinds.net) Received: from rama.ddm.crosswinds.net (rama.ddm.crosswinds.net [204.50.152.20]) by squigy.ddm.crosswinds.net (Postfix) with ESMTP id D209D8B94A; Thu, 26 Jul 2001 21:17:29 -0400 (EDT) Received: by rama.ddm.crosswinds.net (Postfix, from userid 5000) id 0908132663; Thu, 26 Jul 2001 21:17:28 -0400 (EDT) Date: Thu, 26 Jul 2001 21:17:28 -0400 To: Matthew Jacob Cc: hackers@FreeBSD.ORG Subject: Re: perhaps one of phk's "intern" projects? Message-ID: <20010726211728.B89345@ddm.crosswinds.net> References: <20010726154548.I18705-100000@wonky.feral.com> Mime-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="1Ow488MNN9B9o/ov" Content-Disposition: inline User-Agent: Mutt/1.2.5i In-Reply-To: <20010726154548.I18705-100000@wonky.feral.com>; from mjacob@feral.com on Thu, Jul 26, 2001 at 03:45:58PM -0700 From: dchapes@ddm.crosswinds.net (Dave Chapeskie) Sender: owner-freebsd-hackers@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG --1Ow488MNN9B9o/ov Content-Type: multipart/mixed; boundary="y2zxS2PfCDLh6JVG" Content-Disposition: inline --y2zxS2PfCDLh6JVG Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable 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 --=20 Dave Chapeskie OpenPGP Key KeyId: 3D2B6B34 --y2zxS2PfCDLh6JVG Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="at.patch" 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 ig25@rz.uni-karlsruhe.de . 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 --y2zxS2PfCDLh6JVG-- --1Ow488MNN9B9o/ov Content-Type: application/pgp-signature Content-Disposition: inline -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.0.6 (FreeBSD) iEYEARECAAYFAjtgwSUACgkQWqkc/T0razToOACfZCL3yOFTlTl/pNcOuvl+ZKjs jjEAoK4c3xyfuWVHdmM9IhQLtjTWV2I9 =8ilv -----END PGP SIGNATURE----- --1Ow488MNN9B9o/ov-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-hackers" in the body of the message