cvs commit: patches/at at-3.1.8-fixes-1.patch

jim at linuxfromscratch.org jim at linuxfromscratch.org
Sun Oct 5 14:39:07 PDT 2003


jim         03/10/05 15:39:07

  Added:       at       at-3.1.8-fixes-1.patch
  Log:
  Added: at-3.1.8-fixes-1.patch
  
  Revision  Changes    Path
  1.1                  patches/at/at-3.1.8-fixes-1.patch
  
  Index: at-3.1.8-fixes-1.patch
  ===================================================================
  Submitted By: Jim Gifford (jim at linuxfromscratch dot org)
  Date: 2003-09-18
  Initial Package Version: 3.1.8
  Origin: Rawhide SRC RPM
  Description: Fixes known issues with the at daemon
   
  diff -Naur at-3.1.8.orig/Makefile.in at-3.1.8/Makefile.in
  --- at-3.1.8.orig/Makefile.in	2002-01-18 06:55:33.000000000 +0000
  +++ at-3.1.8/Makefile.in	2003-09-19 01:17:27.000000000 +0000
  @@ -51,6 +51,8 @@
   
   OTHERS		= parsetime.l parsetime.y
   
  +TEST_VERBOSE	= 0
  +
   DOCS =  Problems Copyright README ChangeLog timespec
   
   MISC =  COPYING  Makefile.in configure acconfig.h install-sh \
  @@ -87,11 +89,11 @@
   	$(CC) -c $(CFLAGS) $(DEFS) $*.c
   
   install: all
  -	$(INSTALL) -g root -o root -m 755 -d $(IROOT)$(etcdir)
  -	$(INSTALL) -g root -o root -m 755 -d $(IROOT)$(bindir)
  -	$(INSTALL) -g root -o root -m 755 -d $(IROOT)$(sbindir)
  -	$(INSTALL) -g root -o root -m 755 -d $(IROOT)$(docdir)
  -	$(INSTALL) -g root -o root -m 755 -d $(IROOT)$(atdocdir)
  +	$(INSTALL) -m 755 -d $(IROOT)$(etcdir)
  +	$(INSTALL) -m 755 -d $(IROOT)$(bindir)
  +	$(INSTALL) -m 755 -d $(IROOT)$(sbindir)
  +	$(INSTALL) -m 755 -d $(IROOT)$(docdir)
  +	$(INSTALL) -m 755 -d $(IROOT)$(atdocdir)
   	$(INSTALL) -m 755 -d $(IROOT)$(ATJOB_DIR)
   	$(INSTALL) -g $(DAEMON_GROUPNAME) -o $(DAEMON_USERNAME) -m 755 -d $(IROOT)$(ATSPOOL_DIR)
   	chmod 700 $(IROOT)$(ATJOB_DIR) $(IROOT)$(ATSPOOL_DIR)
  @@ -99,25 +101,25 @@
   	touch $(IROOT)$(LFILE)
   	chmod 600 $(IROOT)$(LFILE)
   	chown $(DAEMON_USERNAME):$(DAEMON_GROUPNAME) $(IROOT)$(LFILE)
  -	test -f $(IROOT)$(etcdir)/at.allow || test -f $(IROOT)$(etcdir)/at.deny || $(INSTALL) -o root -m 600 at.deny $(IROOT)$(etcdir)/
  -	$(INSTALL) -g root -o root -m 4755 -s at $(IROOT)$(bindir)
  +	test -f $(IROOT)$(etcdir)/at.allow || test -f $(IROOT)$(etcdir)/at.deny || $(INSTALL)  -m 600 at.deny $(IROOT)$(etcdir)/
  +	$(INSTALL)   -m 4755 -s at $(IROOT)$(bindir)
   	$(LN_S) -f at $(IROOT)$(bindir)/atq
   	$(LN_S) -f at $(IROOT)$(bindir)/atrm
  -	$(INSTALL) -g root -o root -m 755 batch $(IROOT)$(bindir)
  -	$(INSTALL) -d -o root -g root -m 755 $(IROOT)$(man1dir)
  -	$(INSTALL) -d -o root -g root -m 755 $(IROOT)$(man5dir)
  -	$(INSTALL) -d -o root -g root -m 755 $(IROOT)$(man8dir)
  -	$(INSTALL) -g root -o root -m 755 -s atd $(IROOT)$(sbindir)
  -	$(INSTALL) -g root -o root -m 755 atrun $(IROOT)$(sbindir)
  -	$(INSTALL) -g root -o root -m 644 at.1 $(IROOT)$(man1dir)/
  +	$(INSTALL)   -m 755 batch $(IROOT)$(bindir)
  +	$(INSTALL) -d   -m 755 $(IROOT)$(man1dir)
  +	$(INSTALL) -d   -m 755 $(IROOT)$(man5dir)
  +	$(INSTALL) -d   -m 755 $(IROOT)$(man8dir)
  +	$(INSTALL)   -m 755 -s atd $(IROOT)$(sbindir)
  +	$(INSTALL)   -m 755 atrun $(IROOT)$(sbindir)
  +	$(INSTALL)   -m 644 at.1 $(IROOT)$(man1dir)/
   	cd $(IROOT)$(man1dir) && $(LN_S) -f at.1 atq.1 && $(LN_S) -f at.1 batch.1 && $(LN_S) -f at.1 atrm.1
  -	$(INSTALL) -g root -o root -m 644 atd.8 $(IROOT)$(man8dir)/
  +	$(INSTALL)   -m 644 atd.8 $(IROOT)$(man8dir)/
   	sed "s,\$${exec_prefix},$(exec_prefix),g" <atrun.8>tmpman
  -	$(INSTALL) -g root -o root -m 644 tmpman $(IROOT)$(man8dir)/atrun.8
  +	$(INSTALL)   -m 644 tmpman $(IROOT)$(man8dir)/atrun.8
   	rm -f tmpman
  -	$(INSTALL) -g root -o root -m 644 at_allow.5 $(IROOT)$(man5dir)/
  +	$(INSTALL)   -m 644 at_allow.5 $(IROOT)$(man5dir)/
   	cd $(IROOT)$(man5dir) && $(LN_S) -f at_allow.5 at_deny.5 
  -	$(INSTALL) -g root -o root -m 644 $(DOCS) $(IROOT)$(atdocdir)
  +	$(INSTALL)   -m 644 $(DOCS) $(IROOT)$(atdocdir)
   	rm -f $(IROOT)$(mandir)/cat1/at.1* $(IROOT)$(mandir)/cat1/batch.1* \
   		$(IROOT)$(mandir)/cat1/atq.1*
   	rm -f $(IROOT)$(mandir)/cat1/atd.8*
  @@ -151,6 +153,9 @@
   parsetest: lex.yy.c y.tab.c
   	$(CC) -o parsetest $(CFLAGS) $(DEFS) -DTEST_PARSER -DNEED_YYWRAP lex.yy.c y.tab.c
   
  +test: parsetest
  +	PERL_DL_NONLAZY=1 perl -e 'use Test::Harness qw(&runtests $$verbose); $$verbose=$(TEST_VERBOSE); runtests @ARGV;' test.pl
  +
   .depend: $(CSRCS)
   	gcc $(CFLAGS) $(DEFS) -MM $(CSRCS) > .depend
   
  diff -Naur at-3.1.8.orig/at.1.in at-3.1.8/at.1.in
  --- at-3.1.8.orig/at.1.in	2002-01-18 07:44:26.000000000 +0000
  +++ at-3.1.8/at.1.in	2003-09-19 01:17:35.000000000 +0000
  @@ -1,4 +1,4 @@
  -.Id $Id: at-3.1.8-fixes-1.patch,v 1.1 2003/10/05 21:39:07 jim Exp $
  +.Id $Id: at.1.in,v 1.8 1997/09/28 20:00:25 ig25 Exp 
   .TH AT 1 "Nov 1996" local "Linux Programmer's Manual"
   .SH NAME
   at, batch, atq, atrm \- queue, examine or delete jobs for later execution
  @@ -39,7 +39,10 @@
   and
   .B batch
   read commands from standard input or a specified file which are to
  -be executed at a later time, using
  +be executed at a later time, using the shell set by the user's environment
  +variable
  +.BR SHELL
  +or
   .BR /bin/sh .
   .TP 8
   .BR at
  @@ -117,7 +120,7 @@
   .B at 1am tomorrow.
   .PP
   The exact definition of the time specification can be found in
  -.IR @prefix@/share/doc/at/timespec .
  +.IR @prefix@/share/doc/at- at VERSION@/timespec .
   .PP
   For both
   .BR at " and " batch ,
  diff -Naur at-3.1.8.orig/at.c at-3.1.8/at.c
  --- at-3.1.8.orig/at.c	2002-01-18 04:15:27.000000000 +0000
  +++ at-3.1.8/at.c	2003-09-19 01:17:35.000000000 +0000
  @@ -199,7 +199,7 @@
   	fscanf(fid, "%5lx", &jobno);
   	rewind(fid);
       } else {
  -	fid = fopen(ATJOB_DIR "/.SEQ", "w");
  +	fid = fopen(LFILE, "w");
   	if (fid == NULL)
   	    return EOF;
       }
  @@ -231,6 +231,7 @@
       pid_t pid;
       int istty;
       int kill_errno;
  +    char *sh, *shell;
   
   /* Install the signal handler for SIGINT; terminate after removing the
    * spool file if necessary
  @@ -343,8 +344,11 @@
   	if (fpin == NULL)
   	    perr("Cannot open input file %.500s", atinput);
       }
  -    fprintf(fp, "#!/bin/sh\n# atrun uid=%d gid=%d\n# mail %8s %d\n",
  -	    real_uid, real_gid, mailname, send_mail);
  +    sh = (char *) getenv ("SHELL");
  +    shell = (sh ? sh : "/bin/sh");
  +
  +    fprintf(fp, "#!%s\n# atrun uid=%d gid=%d\n# mail %8s %d\n",
  +	    shell, real_uid, real_gid, mailname, send_mail);
   
       /* Write out the umask at the time of invocation
        */
  @@ -357,24 +361,27 @@
        */
       for (atenv = environ; *atenv != NULL; atenv++) {
   	int export = 1;
  -	char *eqp;
  +	char *pch;
  +       char * eqp = *atenv;
  +       char * valp = *atenv;
   
  -	eqp = strchr(*atenv, '=');
  -	if (ap == NULL)
  -	    eqp = *atenv;
  -	else {
  +	if ((pch = strchr(*atenv, '=')) != 0) {
   	    unsigned int i;
  +
  +            eqp = pch;
  +            valp = pch + 1;
   	    for (i = 0; i < sizeof(no_export) / sizeof(no_export[0]); i++) {
   		export = export
   		    && (strncmp(*atenv, no_export[i],
   				(size_t) (eqp - *atenv)) != 0);
   	    }
  -	    eqp++;
  -	}
  +	} else {
  +            continue; /* no '=', so bail on this one */
  +        }
   
   	if (export) {
  -	    fwrite(*atenv, sizeof(char), eqp - *atenv, fp);
  -	    for (ap = eqp; *ap != '\0'; ap++) {
  +	    fwrite(*atenv, sizeof(char), valp - *atenv, fp);
  +	    for (ap = valp; *ap != '\0'; ap++) {
   		if (*ap == '\n')
   		    fprintf(fp, "\"\n\"");
   		else {
  @@ -405,7 +412,7 @@
   		}
   	    }
   	    fputs("; export ", fp);
  -	    fwrite(*atenv, sizeof(char), eqp - *atenv - 1, fp);
  +	    fwrite(*atenv, sizeof(char), eqp - *atenv, fp);
   	    fputc('\n', fp);
   
   	}
  @@ -851,10 +858,11 @@
   	/* POSIX.2 allows the shell specified by the user's SHELL environment
   	   variable, the login shell from the user's password database entry,
   	   or /bin/sh to be the command interpreter that processes the at-job.
  -	   It also alows a warning diagnostic to be printed.  Because of the
  +	   It also allows a warning diagnostic to be printed.  Because of the
   	   possible variance, we always output the diagnostic. */
   
  -	fprintf(stderr, "warning: commands will be executed using /bin/sh\n");
  +/* 	fprintf(stderr, "warning: commands will be executed using /bin/sh\n");
  + */
   
   	writefile(timer, queue);
   	break;
  diff -Naur at-3.1.8.orig/atd.c at-3.1.8/atd.c
  --- at-3.1.8.orig/atd.c	2002-01-18 04:15:27.000000000 +0000
  +++ at-3.1.8/atd.c	2003-09-19 01:17:35.000000000 +0000
  @@ -113,7 +113,7 @@
   static char rcsid[] = "$Id: at-3.1.8-fixes-1.patch,v 1.1 2003/10/05 21:39:07 jim Exp $";
   static double load_avg = LOADAVG_MX;
   static time_t now;
  -static time_t last_chg;
  +//static time_t last_chg;
   static int nothing_to_do;
   unsigned int batch_interval;
   static int run_as_daemon = 0;
  @@ -188,7 +188,7 @@
   #endif
   
   static void
  -run_file(const char *filename, uid_t uid, gid_t gid)
  +run_file(char *filename, uid_t uid, gid_t gid)
   {
   /* Run a file by by spawning off a process which redirects I/O,
    * spawns a subshell, then waits for it to complete and sends
  @@ -196,9 +196,9 @@
    */
       pid_t pid;
       int fd_out, fd_in;
  -    char mailbuf[9], jobbuf[9];
  +    char mailbuf[256], jobbuf[9];
       char *mailname = NULL;
  -    char *newname;
  +    char newname[256];
       FILE *stream;
       int send_mail = 0;
       struct stat buf, lbuf;
  @@ -209,17 +209,24 @@
       int ngid;
       char queue;
       unsigned long jobno;
  +    char *shell;
   
       sscanf(filename, "%c%5lx", &queue, &jobno);
   
       sprintf(jobbuf, "%8lu", jobno);
   
  -    if ((newname = malloc(strlen(filename) + 1)) == NULL)
  -	pabort("Job %8lu : out of virtual memory", jobno);
  +    if( strlen( filename ) >= sizeof( newname ) - 1 )
  +    	pabort("File name too long: %s", filename );
   
       strcpy(newname, filename);
  +    
  +    newname[0] = '!';
  +    
  +    if( rename( filename, newname ) < 0 )
  +    	perr( "Error renaming job file." );
   
  -    newname[0] = '=';
  +    filename[0] = '!';
  +    newname[0] = '=';    
   
       /* We try to make a hard link to lock the file.  If we fail, then
        * somebody else has already locked it (a second atd?); log the
  @@ -234,13 +241,15 @@
   	}
       }
       /* If something goes wrong between here and the unlink() call,
  -     * the job gets restarted as soon as the "=" entry is cleared
  -     * by the main atd loop.
  -     */
  +     * the job will remain in the "!" queue.
  +     * no point in retrying, and need glaring proof that something went wrong
  +     */     
   
       pid = fork();
  -    if (pid == -1)
  +    if (pid == -1) {
  +        unlink( newname );
   	perr("Cannot fork");
  +    }
   
       else if (pid != 0) {
   	return;
  @@ -252,6 +261,7 @@
   
       pentry = getpwuid(uid);
       if (pentry == NULL) {
  +        unlink( newname );
   	pabort("Userid %lu not found - aborting job %8lu (%.500s)",
   	       (unsigned long) uid, jobno, filename);
       }
  @@ -261,34 +271,49 @@
   
       PRIV_END
   
  -    if (stream == NULL)
  +    if (stream == NULL) {
  +    	unlink( newname );
   	perr("Cannot open input file");
  +    }
   
  -    if ((fd_in = dup(fileno(stream))) < 0)
  +    if ((fd_in = dup(fileno(stream))) < 0) {
  +    	unlink( newname );
   	perr("Error duplicating input file descriptor");
  +    }
   
  -    if (fstat(fd_in, &buf) == -1)
  +    if (fstat(fd_in, &buf) == -1) {
  +    	unlink( newname );
   	perr("Error in fstat of input file descriptor");
  +    }
   
  -    if (lstat(filename, &lbuf) == -1)
  +    if (lstat(filename, &lbuf) == -1) {
  +    	unlink( newname );
   	perr("Error in fstat of input file");
  +    }
   
  -    if (S_ISLNK(lbuf.st_mode))
  +    if (S_ISLNK(lbuf.st_mode)) {
  +    	unlink( newname );
   	perr("Symbolic link encountered in job %8lu (%.500s) - aborting",
   	     jobno, filename);
  +    }			     
   
       if ((lbuf.st_dev != buf.st_dev) || (lbuf.st_ino != buf.st_ino) ||
   	(lbuf.st_uid != buf.st_uid) || (lbuf.st_gid != buf.st_gid) ||
  -	(lbuf.st_size != buf.st_size))
  +	(lbuf.st_size != buf.st_size)) {
  +	unlink( newname );
   	perr("Somebody changed files from under us for job %8lu (%.500s) - "
   	     "aborting", jobno, filename);
  +    }	    
   
       if (buf.st_nlink > 2) {
  -	perr("Someboy is trying to run a linked script for job %8lu (%.500s)",
  +    	unlink( newname );
  +	perr("Somebody is trying to run a linked script for job %8lu (%.500s)",
   	     filename);
       }
  -    if ((fflags = fcntl(fd_in, F_GETFD)) < 0)
  +    if ((fflags = fcntl(fd_in, F_GETFD)) < 0) {
  +    	unlink( newname );
   	perr("Error in fcntl");
  +    }		
   
       fcntl(fd_in, F_SETFD, fflags & ~FD_CLOEXEC);
   
  @@ -299,33 +324,48 @@
        * NFS and works with local file systems.  It's not clear where
        * the bug is located.  -Joey
        */
  -    if (fscanf(stream, "#!/bin/sh\n# atrun uid=%d gid=%d\n# mail %8s %d",
  -	       &nuid, &ngid, mailbuf, &send_mail) != 4)
  +    if (fscanf(stream, "#!%as\n# atrun uid=%d gid=%d\n# mail %255s %d",
  +	       &shell, &nuid, &ngid, mailbuf, &send_mail) != 5) {
  +	unlink( newname );
   	pabort("File %.500s is in wrong format - aborting",
   	       filename);
  +    }	       
  +    mailbuf[255] = '\0';
   
  -    if (mailbuf[0] == '-')
  +    if (mailbuf[0] == '-') {
  +    	unlink( newname );
   	pabort("illegal mail name %.300s in job %8lu (%.300s)", mailbuf,
   	       jobno, filename);
  +    }	       
   
       mailname = mailbuf;
  -    if (nuid != uid)
  +    if (nuid != uid) {
  +    	unlink( newname );
   	pabort("Job %8lu (%.500s) - userid %d does not match file uid %d",
   	       jobno, filename, nuid, uid);
  +    }	       
   
  -    if (ngid != gid)
  +    if (ngid != gid) {
  +    	unlink( newname );
   	pabort("Job %8lu %.500s - groupid %d does not match file gid %d",
   	       jobno, filename, ngid, gid);
  +    }	       
   
       /* We are now committed to executing this script.  Unlink the
        * original.
        */
   
       unlink(filename);
  +    
  +    /* If we bail out from now on, the job gets stuck in "="
  +     * The main loop should take care of that.
  +     */
   
       fclose(stream);
       if (chdir(ATSPOOL_DIR) < 0)
   	perr("Cannot chdir to " ATSPOOL_DIR);
  +	
  +    filename[0] = queue;	
   
       /* Create a file to hold the output of the job we are about to run.
        * Write the mail header.  Complain in case 
  @@ -394,10 +434,15 @@
   	    if (setuid(uid) < 0)
   		perr("Cannot set user id");
   
  +	    if (SIG_ERR == signal(SIGCHLD, SIG_DFL))
  +		perr("Cannot reset signal handler to default");
  +
   	    chdir("/");
   
  -	    if (execle("/bin/sh", "sh", (char *) NULL, nenvp) != 0)
  -		perr("Exec failed for /bin/sh");
  +	    if (execle(shell, shell, (char *) NULL, nenvp) != 0)
  +		perr("Exec failed for %s", shell);
  +
  +	    free (shell);
   
   	PRIV_END
       }
  @@ -413,19 +458,21 @@
       waitpid(pid, (int *) NULL, 0);
   
       /* Send mail.  Unlink the output file after opening it, so it
  -     * doesn't hang around after the run.
  +     * doesn't hang around after the run (if we are to send mail)
        */
  -    stat(filename, &buf);
  -    if (open(filename, O_RDONLY) != STDIN_FILENO)
  -	perr("Open of jobfile failed");
  +     
  +    if( send_mail != -1 ) {
  +      stat(filename, &buf);
  +      if (open(filename, O_RDONLY) != STDIN_FILENO)
  +	  perr("Open of jobfile failed");
   
  -    unlink(filename);
  +      unlink(filename);
  +    }
   
       /* The job is now finished.  We can delete its input file.
        */
       chdir(ATJOB_DIR);
       unlink(newname);
  -    free(newname);
   
       if (((send_mail != -1) && (buf.st_size != size)) || (send_mail == 1)) {
   
  @@ -449,7 +496,8 @@
   #elif  defined(MAILX)
   	    execl(MAILX, "mailx", mailname, (char *) NULL);
   #else
  -#error      "No mail command specified."
  +/*#error      "No mail command specified."*/
  +	perr("No mail command specified.");
   #endif
   	    perr("Exec failed for mail command");
   
  @@ -458,6 +506,8 @@
       exit(EXIT_SUCCESS);
   }
   
  +#define CHECK_INTERVAL_5MIN	300
  +
   static time_t
   run_loop()
   {
  @@ -487,7 +537,7 @@
        * atrun.
        */
   
  -    next_job = now + CHECK_INTERVAL;
  +    next_job = now + CHECK_INTERVAL_5MIN;
       if (next_batch == 0)
   	next_batch = now;
   
  @@ -498,11 +548,11 @@
   
       if (stat(".", &buf) == -1)
   	perr("Cannot stat " ATJOB_DIR);
  -
  +/*
       if (nothing_to_do && buf.st_mtime <= last_chg)
   	return next_job;
       last_chg = buf.st_mtime;
  -
  +*/    
       if ((spool = opendir(".")) == NULL)
   	perr("Cannot read " ATJOB_DIR);
   
  @@ -558,6 +608,7 @@
   		 * Let's remove the lockfile and reschedule.
   		 */
   		strncpy(lock_name, dirent->d_name, sizeof(lock_name));
  +		lock_name[sizeof(lock_name)-1] = '\0';
   		lock_name[0] = '=';
   		unlink(lock_name);
   		next_job = now;
  @@ -574,7 +625,7 @@
   	nothing_to_do = 0;
   
   	/* There's a job for later.  Note its execution time if it's
  -	 * the earlierst so far.
  +	 * the earliest so far.
   	 */
   	if (run_time > now) {
   	    if (next_job > run_time) {
  @@ -592,6 +643,7 @@
   	    run_batch++;
   	    if (strcmp(batch_name, dirent->d_name) > 0) {
   		strncpy(batch_name, dirent->d_name, sizeof(batch_name));
  +		batch_name[sizeof(batch_name)-1] = '\0';
   		batch_uid = buf.st_uid;
   		batch_gid = buf.st_gid;
   		batch_queue = queue;
  @@ -628,7 +680,7 @@
   int
   main(int argc, char *argv[])
   {
  -/* Browse through  ATJOB_DIR, checking all the jobfiles wether they should
  +/* Browse through  ATJOB_DIR, checking all the jobfiles whether they should
    * be executed and or deleted. The queue is coded into the first byte of
    * the job filename, the date (in minutes since Eon) as a hex number in the
    * following eight bytes, followed by a dot and a serial number.  A file
  diff -Naur at-3.1.8.orig/atrun.8.in at-3.1.8/atrun.8.in
  --- at-3.1.8.orig/atrun.8.in	2002-01-18 04:15:27.000000000 +0000
  +++ at-3.1.8/atrun.8.in	2003-09-19 01:17:36.000000000 +0000
  @@ -11,7 +11,7 @@
   .B atrun
   runs jobs queued by
   .BR at(1) .
  -It is a shell script containing invoking
  +It is a shell script invoking
   .B @sbindir@/atd
   with the
   .I -s
  diff -Naur at-3.1.8.orig/batch.in at-3.1.8/batch.in
  --- at-3.1.8.orig/batch.in	1997-03-12 23:57:40.000000000 +0000
  +++ at-3.1.8/batch.in	2003-09-19 01:17:25.000000000 +0000
  @@ -1,4 +1,42 @@
   #! /bin/sh
   prefix=@prefix@
   exec_prefix=@exec_prefix@
  -exec @bindir@/at -qb now "$@"
  +
  +# Set defaults
  +OPT_f=""
  +OPT_m=""
  +OPT_q="-q b"
  +OPT_v=""
  +OPT_V=""
  +time_date_arg="now"
  +
  +# Note that we use `"$@"' to let each command-line parameter expand to a 
  +# separate word. The quotes around `$@' are essential!
  +# We need TEMP as the `eval set --' would nuke the return value of getopt.
  +TEMP=`@GETOPT@ 'f:mq:vV' "$@"`
  +
  +if [ $? != 0 ] ; then
  +    echo "batch: error parsing command-line arguments" >&2
  +    exit 1
  +fi
  +
  +# Note the quotes around `$TEMP': they are essential!
  +eval set -- "$TEMP"
  +
  +while true ; do
  +    case "$1" in
  +        -f) OPT_f="-f $2" ; shift 2 ;;
  +        -m) OPT_m="-m"; shift ;;
  +        -q) OPT_q="-q $2"; shift 2 ;;
  +        -v) OPT_v="-v"; shift ;;
  +        -V) OPT_V="-V"; shift ;;
  +        --) shift ; break ;;
  +        *) echo "batch: internal parsing error" >&2 ; exit 1 ;;
  +    esac
  +done
  +
  +if [ ! -z "$*" ] ; then
  +    time_date_arg="$*"
  +fi
  +
  +exec @bindir@/at $OPT_f $OPT_m $OPT_q $OPT_v $OPT_V $time_date_arg
  diff -Naur at-3.1.8.orig/configure.in at-3.1.8/configure.in
  --- at-3.1.8.orig/configure.in	2002-01-18 08:07:02.000000000 +0000
  +++ at-3.1.8/configure.in	2003-09-19 01:17:25.000000000 +0000
  @@ -90,6 +90,11 @@
   MAIL_CMD="$ac_cv_path_SENDMAIL"
   fi
   
  +AC_PATH_PROG(GETOPT, getopt, , $PATH:/bin:/usr/bin:/usr/local/bin )
  +if test "$ac_cv_path_GETOPT" != "" ; then
  +AC_DEFINE_UNQUOTED(GETOPT,"$ac_cv_path_GETOPT")
  +fi
  +
   AC_SUBST(MAIL_CMD)
   
   AC_MSG_CHECKING(etcdir)
  diff -Naur at-3.1.8.orig/parsetime.l at-3.1.8/parsetime.l
  --- at-3.1.8.orig/parsetime.l	1997-09-28 18:26:30.000000000 +0000
  +++ at-3.1.8/parsetime.l	2003-09-19 01:17:26.000000000 +0000
  @@ -32,7 +32,6 @@
       } while(0)
   %}
   
  -WORD		[a-z][a-z0-9]+
   %%
   
   now		{ COPY_TOK ; return NOW; }
  @@ -57,6 +56,7 @@
   day(s)?		{ COPY_TOK ; return DAY; }
   week(s)?	{ COPY_TOK ; return WEEK; }
   month(s)?	{ COPY_TOK ; return MONTH; }
  +year(s)?	{ COPY_TOK ; return YEAR; }
   jan(uary)?	{ COPY_TOK ; return JAN; }
   feb(ruary)?	{ COPY_TOK ; return FEB; }
   mar(ch)?	{ COPY_TOK ; return MAR; }
  @@ -69,9 +69,16 @@
   oct(ober)?	{ COPY_TOK ; return OCT; }
   nov(ember)?	{ COPY_TOK ; return NOV; }
   dec(ember)?	{ COPY_TOK ; return DEC; }
  +utc		{ COPY_TOK ; return UTC; }
  +[0-9]{1}	{ COPY_TOK ; COPY_VAL; return INT1DIGIT; }
  +[0-9]{2}	{ COPY_TOK ; COPY_VAL; return INT2DIGIT; }
  +[0-9]{4}	{ COPY_TOK ; COPY_VAL; return INT4DIGIT; }
  +[0-9]{5,8}	{ COPY_TOK ; COPY_VAL; return INT5_8DIGIT; }
   [0-9]+		{ COPY_TOK ; COPY_VAL; return INT; }
  +[0-9]{1,2}\.[0-9]{1,2}\.[0-9]{2}([0-9]{2})?	{ COPY_TOK ; COPY_VAL; return DOTTEDDATE; }
  +[0-9]{2}([0-9]{2})?-[0-9]{1,2}-[0-9]{1,2}	{ COPY_TOK ; COPY_VAL; return HYPHENDATE; }
  +[012]?[0-9][:'h,.][0-9]{2}	{ COPY_TOK ; COPY_VAL; return HOURMIN; }
   [ \t\n]		;
  -{WORD}		{ COPY_TOK ; COPY_VAL; return WORD; }
   .		{ COPY_TOK ; return yytext[0]; }
   
   %%
  diff -Naur at-3.1.8.orig/parsetime.y at-3.1.8/parsetime.y
  --- at-3.1.8.orig/parsetime.y	2002-01-18 04:15:27.000000000 +0000
  +++ at-3.1.8/parsetime.y	2003-09-19 01:17:26.000000000 +0000
  @@ -22,6 +22,13 @@
   	int		intval;
   }
   
  +%token  <charval> DOTTEDDATE
  +%token  <charval> HYPHENDATE
  +%token  <charval> HOURMIN
  +%token  <charval> INT1DIGIT
  +%token  <charval> INT2DIGIT
  +%token  <charval> INT4DIGIT
  +%token  <charval> INT5_8DIGIT
   %token  <charval> INT
   %token  NOW
   %token  AM PM
  @@ -31,48 +38,61 @@
   %token  NEXT
   %token  MINUTE HOUR DAY WEEK MONTH YEAR
   %token  JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
  -%token  <charval> WORD
  +%token  UTC
   
  -%type <intval> inc_period
  -%type <intval> inc_number
  +%type <charval> concatenated_date
  +%type <charval> hr24clock_hr_min
  +%type <charval> int1_2digit
  +%type <charval> int2_or_4digit
  +%type <charval> integer
  +%type <intval> inc_dec_period
  +%type <intval> inc_dec_number
   %type <intval> day_of_week
   
   %start timespec
   %%
  -timespec        : date
  +timespec        : spec_base
  +		| spec_base inc_or_dec
  +		    {
  +			time_only = 0;
  +
  +		    }
  +                ;
  +
  +spec_base	: date
   		| time
   		    {
   			time_only = 1;
   		    }
                   | time date
  -                | time_or_not inc_or_dec
  -                | time_or_not date inc_or_dec
  -                | nowspec
  -                ;
  +                | NOW
  +		;
   
  -nowspec         : now
  -                | now inc_or_dec
  +time		: time_base
  +		| time_base timezone_name
                   ;
   
  -now		: NOW 
  -                | TOMORROW
  -		   {
  -			add_date(1, DAY);
  -		   }
  -		;
  -
  -time_or_not     : time
  -		|
  +time_base	: hr24clock_hr_min
  +		    {
  +			exectm.tm_min = -1;
  +			exectm.tm_hour = -1;
  +			sscanf($1, "%2d %2d", &exectm.tm_hour,
  +			    &exectm.tm_min);
  +			free($1);
   
  -time            : hr24clock_hr_min
  -                | hr24clock_hr_min timezone_name
  -                | hr24clock_hour time_sep minute
  -                | hr24clock_hour time_sep minute timezone_name
  -                | hr24clock_hour am_pm
  -                | hr24clock_hour am_pm timezone_name
  -                | hr24clock_hour time_sep minute am_pm
  -                | hr24clock_hour time_sep minute am_pm timezone_name
  -                | NOON
  +			if (exectm.tm_min > 60 || exectm.tm_min < 0) {
  +			    yyerror("Problem in minutes specification");
  +			    YYERROR;
  +			}
  +			if (exectm.tm_hour > 24 || exectm.tm_hour < 0) {
  +			    yyerror("Problem in hours specification");
  +			    YYERROR;
  +		        }
  +		    }
  +		| time_hour am_pm
  +		| time_hour_min
  +		| time_hour_min am_pm
  +		| NOON
   		    {
   			exectm.tm_hour = 12;
   			exectm.tm_min = 0;
  @@ -81,128 +101,23 @@
   		    {
   			exectm.tm_hour = 0;
   			exectm.tm_min = 0;
  -			add_date(1, DAY);
   		    }
   		| TEATIME
   		    {
   			exectm.tm_hour = 16;
   			exectm.tm_min = 0;
   		    }
  -                ;
  -
  -date            : month_name day_number
  -                | month_name day_number year_number
  -                | month_name day_number ',' year_number
  -                | day_of_week
  -		   {
  -		       add_date ((6 + $1 - exectm.tm_wday) %7 + 1, DAY);
  -		   }
  -                | TODAY
  -                | TOMORROW
  -		   {
  -			add_date(1, DAY);
  -		   }
  -		| year_number '-' month_number '-' day_number
  -		| day_number '.' month_number '.' year_number
  -		| day_number '.' month_number
  -		| day_number month_name
  -		| day_number month_name year_number
  -		| month_number '/' day_number '/' year_number
  -                ;
  -
  -inc_or_dec	: increment
  -		| decrement
  -
  -increment       : '+' inc_number inc_period
  -		    {
  -		        add_date($2, $3);
  -		    }
  -                | NEXT inc_period		
  -		    {
  -			add_date(1, $2);
  -		    }
  -		| NEXT day_of_week
  -		    {
  -			add_date ((6 + $2 - exectm.tm_wday) %7 +1, DAY);
  -		    }
  -                ;
  -
  -decrement	: '-' inc_number inc_period
  -		    {
  -			add_date(-$2, $3);
  -		    }
   		;
   
  -inc_period      : MINUTE { $$ = MINUTE ; }
  -                | HOUR	 { $$ = HOUR ; }
  -                | DAY	 { $$ = DAY ; }
  -                | WEEK   { $$ = WEEK ; }
  -                | MONTH  { $$ = MONTH ; }
  -                | YEAR   { $$ = YEAR ; }
  -                ;
  +hr24clock_hr_min: INT4DIGIT
  +		;
   
  -hr24clock_hr_min: INT
  +time_hour	: int1_2digit
   		    {
  -			if (strlen($1) == 4) {
  -			    exectm.tm_min = -1;
  -			    exectm.tm_hour = -1;
  -			    sscanf($1, "%2d %2d", &exectm.tm_hour,
  -				&exectm.tm_min);
  -			} else if (strlen($1) >= 5 && strlen($1) <= 8) {
  -				/* Ok, this is a kluge.  I hate design errors...  -Joey */
  -				char shallot[5];
  -				char *onion;
  -
  -				onion=$1;
  -				memset (shallot, 0, sizeof (shallot));
  -				if (strlen($1) == 5 || strlen($1) == 7) {
  -				    strncpy (shallot,onion,1);
  -				    onion++;
  -				} else {
  -				    strncpy (shallot,onion,2);
  -				    onion+=2;
  -				}
  -				sscanf(shallot, "%d", &exectm.tm_mon);
  -
  -				if (exectm.tm_mon < 1 || exectm.tm_mon > 12) {
  -				    yyerror("Error in month number");
  -				    YYERROR;
  -				}
  -				exectm.tm_mon--;
  -
  -				memset (shallot, 0, sizeof (shallot));
  -				strncpy (shallot,onion,2);
  -			    	sscanf(shallot, "%d", &exectm.tm_mday);
  -				if (exectm.tm_mday < 0 || exectm.tm_mday > 31)
  -				{
  -				    yyerror("Error in day of month");
  -				    YYERROR;
  -				}
  -
  -				onion+=2;
  -				memset (shallot, 0, sizeof (shallot));
  -				strncpy (shallot,onion,4);
  -				if ( sscanf(shallot, "%d", &exectm.tm_year) != 1) {
  -				    yyerror("Error in year");
  -				    YYERROR;
  -				}
  -				if (exectm.tm_year < 70) {
  -				    exectm.tm_year += 100;
  -				}
  -				else if (exectm.tm_year > 1900) {
  -				    exectm.tm_year -= 1900;
  -				}
  -			}
  -			else {
  -			    sscanf($1, "%d", &exectm.tm_hour);
  -			    exectm.tm_min = 0;
  -			}
  +			sscanf($1, "%d", &exectm.tm_hour);
  +			exectm.tm_min = 0;
   			free($1);
   
  -			if (exectm.tm_min > 60 || exectm.tm_min < 0) {
  -			    yyerror("Problem in minutes specification");
  -			    YYERROR;
  -			}
   			if (exectm.tm_hour > 24 || exectm.tm_hour < 0) {
   			    yyerror("Problem in hours specification");
   			    YYERROR;
  @@ -210,29 +125,22 @@
   		    }
   		;
   
  -timezone_name	: WORD
  +time_hour_min	: HOURMIN
   		    {
  -			if (strcasecmp($1,"utc") == 0) {
  -			    isgmt = 1;
  -			}
  -			else {
  -			    yyerror("Only UTC timezone is supported");
  -			    YYERROR;
  -			}
  +			exectm.tm_min = -1;
  +			exectm.tm_hour = -1;
  +			sscanf($1, "%d %*c %d", &exectm.tm_hour,
  +			    &exectm.tm_min);
   			free($1);
  -		    }
  -		;
  -
  -hr24clock_hour	: hr24clock_hr_min
  -		;
   
  -minute		: INT
  -                    {
  -			if (sscanf($1, "%d", &exectm.tm_min) != 1) {
  -			    yyerror("Error in minute");
  +			if (exectm.tm_min > 60 || exectm.tm_min < 0) {
  +			    yyerror("Problem in minutes specification");
  +			    YYERROR;
  +			}
  +			if (exectm.tm_hour > 24 || exectm.tm_hour < 0) {
  +			    yyerror("Problem in hours specification");
   			    YYERROR;
   		        }
  -			free($1);
   		    }
   		;
   
  @@ -243,7 +151,7 @@
   			    YYERROR;
   			}
   			else if (exectm.tm_hour == 12) {
  -			    exectm.tm_hour = 0;
  +			    exectm.tm_hour -=12;
   			}
   		    }
   		| PM
  @@ -258,6 +166,171 @@
   		    }
   		;
   
  +timezone_name	: UTC
  +		    {
  +			isgmt = 1;
  +		    }
  +		;
  +
  +date            : month_name day_number
  +                | month_name day_number year_number
  +                | month_name day_number ',' year_number
  +                | day_of_week
  +		   {
  +		       add_date ((6 + $1 - exectm.tm_wday) %7 + 1, DAY);
  +		   }
  +                | TODAY
  +                | TOMORROW
  +		   {
  +			add_date(1, DAY);
  +		   }
  +		| HYPHENDATE
  +		   {
  +			int ynum = -1;
  +			int mnum = -1;
  +			int dnum = -1;
  +
  +			if (sscanf($1, "%d %*c %d %*c %d", &ynum, &mnum, &dnum) != 3) {
  +			    yyerror("Error in hypenated date");
  +			    YYERROR;
  +			}
  +
  +			if (mnum < 1 || mnum > 12) {
  +			    yyerror("Error in month number");
  +			    YYERROR;
  +			}
  +			exectm.tm_mon = mnum -1;
  +
  +			if (ynum < 70) {
  +			    ynum += 100;
  +			}
  +			else if (ynum > 1900) {
  +			    ynum -= 1900;
  +			}
  +			exectm.tm_year = ynum ;
  +
  +			if (   dnum < 0
  +			    || ((mnum ==  1 || mnum ==  3 || mnum ==  5 ||
  +			         mnum ==  7 || mnum ==  8 || mnum == 10 ||
  +				 mnum == 12) && dnum > 31)
  +			    || ((mnum ==  4 || mnum ==  6 || mnum ==  9 ||
  +			         mnum == 11) && dnum > 30)
  +			    || (mnum ==  2 && dnum > 29 &&  __isleap(ynum+1900))
  +			    || (mnum ==  2 && dnum > 28 && !__isleap(ynum+1900))
  +			   )
  +			{
  +			    yyerror("Error in day of month");
  +			    YYERROR; 
  +			}
  +			exectm.tm_mday = dnum;
  +
  +			free($1);
  +		   }
  +		| DOTTEDDATE
  +		   {
  +			int ynum = -1;
  +			int mnum = -1;
  +			int dnum = -1;
  +
  +			if (sscanf($1, "%d %*c %d %*c %d", &dnum, &mnum, &ynum) != 3) {
  +			    yyerror("Error in dotted date");
  +			    YYERROR;
  +			}
  +
  +			if (mnum < 1 || mnum > 12) {
  +			    yyerror("Error in month number");
  +			    YYERROR;
  +			}
  +			exectm.tm_mon = mnum -1;
  +
  +			if (ynum < 70) {
  +			    ynum += 100;
  +			}
  +			else if (ynum > 1900) {
  +			    ynum -= 1900;
  +			}
  +			exectm.tm_year = ynum ;
  +
  +			if (   dnum < 0
  +			    || ((mnum ==  1 || mnum ==  3 || mnum ==  5 ||
  +			         mnum ==  7 || mnum ==  8 || mnum == 10 ||
  +				 mnum == 12) && dnum > 31)
  +			    || ((mnum ==  4 || mnum ==  6 || mnum ==  9 ||
  +			         mnum == 11) && dnum > 30)
  +			    || (mnum ==  2 && dnum > 29 &&  __isleap(ynum+1900))
  +			    || (mnum ==  2 && dnum > 28 && !__isleap(ynum+1900))
  +			   )
  +			{
  +			    yyerror("Error in day of month");
  +			    YYERROR; 
  +			}
  +			exectm.tm_mday = dnum;
  +
  +			free($1);
  +		   }
  +		| day_number month_name
  +		| day_number month_name year_number
  +		| month_number '/' day_number '/' year_number
  +		| concatenated_date
  +		    {
  +			/* Ok, this is a kluge.  I hate design errors...  -Joey */
  +			char shallot[5];
  +			char *onion;
  +
  +			onion=$1;
  +			memset (shallot, 0, sizeof (shallot));
  +			if (strlen($1) == 5 || strlen($1) == 7) {
  +			    strncpy (shallot,onion,1);
  +			    onion++;
  +			} else {
  +			    strncpy (shallot,onion,2);
  +			    onion+=2;
  +			}
  +			sscanf(shallot, "%d", &exectm.tm_mon);
  +
  +			if (exectm.tm_mon < 1 || exectm.tm_mon > 12) {
  +			    yyerror("Error in month number");
  +			    YYERROR;
  +			}
  +			exectm.tm_mon--;
  +
  +			memset (shallot, 0, sizeof (shallot));
  +			strncpy (shallot,onion,2);
  +		    	sscanf(shallot, "%d", &exectm.tm_mday);
  +			if (exectm.tm_mday < 0 || exectm.tm_mday > 31)
  +			{
  +			    yyerror("Error in day of month");
  +			    YYERROR;
  +			}
  +
  +			onion+=2;
  +			memset (shallot, 0, sizeof (shallot));
  +			strncpy (shallot,onion,4);
  +			if ( sscanf(shallot, "%d", &exectm.tm_year) != 1) {
  +			    yyerror("Error in year");
  +			    YYERROR;
  +			}
  +			if (exectm.tm_year < 70) {
  +			    exectm.tm_year += 100;
  +			}
  +			else if (exectm.tm_year > 1900) {
  +			    exectm.tm_year -= 1900;
  +			}
  +
  +			free ($1);
  +		    }
  +                | NEXT inc_dec_period		
  +		    {
  +			add_date(1, $2);
  +		    }
  +		| NEXT day_of_week
  +		    {
  +			add_date ((6 + $2 - exectm.tm_wday) %7 +1, DAY);
  +		    }
  +                ;
  +
  +concatenated_date: INT5_8DIGIT
  +		;
   
   month_name	: JAN { exectm.tm_mon = 0; }
   		| FEB { exectm.tm_mon = 1; }
  @@ -273,7 +346,7 @@
   		| DEC { exectm.tm_mon =11; }
   		;
   
  -month_number	: INT
  +month_number	: int1_2digit
   		    {
   			{
   			    int mnum = -1;
  @@ -287,7 +360,9 @@
   			    free($1);
   			}
   		    }
  -day_number	: INT
  +		;
  +
  +day_number	: int1_2digit
                        {
   			exectm.tm_mday = -1;
   			sscanf($1, "%d", &exectm.tm_mday);
  @@ -300,7 +375,7 @@
   		     }
   		;
   
  -year_number	: INT
  +year_number	: int2_or_4digit
   		    { 
   			{
   			    int ynum;
  @@ -322,7 +397,6 @@
   		    }
   		;
   
  -
   day_of_week	: SUN { $$ = 0; }
   		| MON { $$ = 1; }
   		| TUE { $$ = 2; }
  @@ -332,7 +406,23 @@
   		| SAT { $$ = 6; }
   		;
   
  -inc_number	: INT
  +inc_or_dec	: increment
  +		| decrement
  +		;
  +
  +increment       : '+' inc_dec_number inc_dec_period
  +		    {
  +		        add_date($2, $3);
  +		    }
  +                ;
  +
  +decrement	: '-' inc_dec_number inc_dec_period
  +		    {
  +			add_date(-$2, $3);
  +		    }
  +		;
  +
  +inc_dec_number	: integer
   		    {
   			if (sscanf($1, "%d", &$$) != 1) {
   			    yyerror("Unknown increment");
  @@ -342,11 +432,27 @@
   		    }
   		;
   
  -time_sep	: ':'
  -		| '\''
  -		| '.'
  -		| 'h'
  -		| ','
  +inc_dec_period	: MINUTE { $$ = MINUTE ; }
  +		| HOUR	 { $$ = HOUR   ; }
  +		| DAY	 { $$ = DAY    ; }
  +		| WEEK   { $$ = WEEK   ; }
  +		| MONTH  { $$ = MONTH  ; }
  +		| YEAR   { $$ = YEAR   ; }
  +		;
  +
  +int1_2digit	: INT1DIGIT
  +		| INT2DIGIT
  +		;
  +
  +int2_or_4digit	: INT2DIGIT
  +		| INT4DIGIT
  +		;
  +
  +integer		: INT
  +		| INT1DIGIT
  +		| INT2DIGIT
  +		| INT4DIGIT
  +		| INT5_8DIGIT
   		;
   
   %%
  @@ -370,10 +476,7 @@
   	if (exectime == (time_t)-1)
   	    return 0;
   	if (isgmt) {
  -	    exectime += timezone;
  -	    if (daylight) {
  -		exectime -= 3600;
  -	    }
  +	    exectime -= timezone;
   	}
   	if (time_only && (currtime > exectime)) {
   	    exectime += 24*3600;
  @@ -386,39 +489,29 @@
   }
   
   #ifdef TEST_PARSER
  -/*
  -
  -Here are some lines to test:
  -
  -./parsetest 7AM Mar 24 2000
  -./parsetest 7AM Mar 24 00
  -./parsetest 7AM 032400
  -./parsetest 7AM 03/24/00
  -./parsetest 7AM 24.03.00
  -./parsetest 7AM Mar 24
  -
  -./parsetest 03242000
  -./parsetest noon 03242000
  -./parsetest 5:30
  -./parsetest 4pm + 3 days
  -./parsetest 10am Jul 31
  -
  - */
  + 
   int
   main(int argc, char **argv)
   {
  +    int retval = 1;
       time_t res;
       res = parsetime(argc-1, &argv[1]);
  +    if (time_only) {
  +	fprintf(stderr, "time_only = 1\n");
  +    }
       if (res > 0) {
   	printf("%s",ctime(&res));
  +	retval = 0;
       }
       else {
   	printf("Ooops...\n");
  +	retval = 1;
       }
  -    return 0;
  +    return retval;
   }
   
   #endif
  +
   int yyerror(char *s)
   {
       if (last_token == NULL)
  @@ -430,12 +523,36 @@
   void
   add_seconds(struct tm *tm, long numsec)
   {
  +    struct tm basetm = *tm;
       time_t timeval;
  +
       timeval = mktime(tm);
       if (timeval == (time_t)-1)
           timeval = (time_t)0;
       timeval += numsec;
       *tm = *localtime(&timeval);
  +
  +    /*
  +     * Adjust +-1 hour when moving in or out of DST
  +     */
  +
  +    if (daylight > 0)	/* Only check if DST is used here */
  +    {
  +	/* Set tm_isdst on &basetm and tm */
  +	(void) mktime(&basetm);
  +	(void) mktime(tm);
  +
  +	if      (basetm.tm_isdst > 0 && tm->tm_isdst < 1)
  +	{   /* DST to no DST */
  +	    timeval += 3600l;
  +	    *tm = *localtime(&timeval);
  +	}
  +	else if (basetm.tm_isdst < 1 && tm->tm_isdst > 0)
  +	{   /* no DST to DST */
  +	    timeval -= 3600l;
  +	    *tm = *localtime(&timeval);
  +	}
  +    }
   }
   
   int
  @@ -468,6 +585,10 @@
   	    }
   	    exectm.tm_mon = newmonth % 12;
   	    number += newmonth / 12 ;
  +
  +	    /* Recalculate tm_isdst so we don't get a +-1 hour creep */
  +	    exectm.tm_isdst = -1;
  +	    (void) mktime(&exectm);
   	}
   	if (number == 0) {
   	    break;
  @@ -476,6 +597,9 @@
   
       case YEAR:
   	exectm.tm_year += number;
  +	/* Recalculate tm_isdst so we don't get a +-1 hour creep */
  +	exectm.tm_isdst = -1;
  +	(void) mktime(&exectm);
   	break;
   
       default:
  @@ -483,5 +607,6 @@
   	fprintf(stderr,"Unexpected case %d\n", period);
   	abort();
       }
  +
       return 0;
   }
  diff -Naur at-3.1.8.orig/timespec at-3.1.8/timespec
  --- at-3.1.8.orig/timespec	1997-03-12 18:11:05.000000000 +0000
  +++ at-3.1.8/timespec	2003-09-19 01:17:26.000000000 +0000
  @@ -2,6 +2,13 @@
    * Abbreviated version of the yacc grammar used by at(1).
    */
   
  +%token  <charval> DOTTEDDATE
  +%token  <charval> HYPHENDATE
  +%token  <charval> HOURMIN
  +%token  <charval> INT1DIGIT
  +%token  <charval> INT2DIGIT
  +%token  <charval> INT4DIGIT
  +%token  <charval> INT5_8DIGIT
   %token  <charval> INT
   %token  NOW
   %token  AM PM
  @@ -11,100 +18,115 @@
   %token  NEXT
   %token  MINUTE HOUR DAY WEEK MONTH YEAR
   %token  JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC
  -%token  <charval> WORD
  +%token  UTC
   
  -%type <intval> inc_period
  -%type <intval> inc_number
  +%type <charval> concatenated_date
  +%type <charval> hr24clock_hr_min
  +%type <charval> int1_2digit
  +%type <charval> int2_or_4digit
  +%type <charval> integer
  +%type <intval> inc_dec_period
  +%type <intval> inc_dec_number
   %type <intval> day_of_week
   
   %start timespec
   %%
  -timespec        : time
  -                | time date
  -                | time increment
  -                | time date increment
  -		| time decrement
  -		| time date decrement
  -                | nowspec
  -                ;
  -
  -nowspec         : now
  -                | now increment
  -		| now decrement
  +timespec        : spec_base
  +		| spec_base inc_or_dec
                   ;
   
  -now		: NOW 
  +spec_base	: date
  +		| time
  +                | time date
  +                | NOW
   		;
   
  -time            : hr24clock_hr_min
  -                | hr24clock_hr_min timezone_name
  -                | hr24clock_hour time_sep minute
  -                | hr24clock_hour time_sep minute timezone_name
  -                | hr24clock_hour am_pm
  -                | hr24clock_hour am_pm timezone_name
  -                | hr24clock_hour time_sep minute am_pm
  -                | hr24clock_hour time_sep minute am_pm timezone_name
  -                | NOON
  +time		: time_base
  +		| time_base timezone_name
  +                ;
  +
  +time_base	: hr24clock_hr_min
  +		| time_hour am_pm
  +		| time_hour_min
  +		| time_hour_min am_pm
  +		| NOON
                   | MIDNIGHT
   		| TEATIME
  -                ;
  +		;
  +
  +hr24clock_hr_min: INT4DIGIT
  +		;
  +
  +time_hour	: int1_2digit
  +		;
  +
  +time_hour_min	: HOURMIN
  +		;
  +
  +am_pm		: AM
  +		| PM
  +		;
  +
  +timezone_name	: UTC
  +		;
   
   date            : month_name day_number
  +                | month_name day_number year_number
                   | month_name day_number ',' year_number
                   | day_of_week
                   | TODAY
                   | TOMORROW
  -		| year_number '-' month_number '-' day_number
  -		| day_number '.' month_number '.' year_number
  -		| day_number '.' month_number
  +		| HYPHENDATE
  +		| DOTTEDDATE
   		| day_number month_name
   		| day_number month_name year_number
   		| month_number '/' day_number '/' year_number
  -                ;
  -
  -increment       : '+' inc_number inc_period
  -                | NEXT inc_period		
  +		| concatenated_date
  +                | NEXT inc_dec_period		
   		| NEXT day_of_week
                   ;
   
  -decrement	: '-' inc_number inc_period
  +concatenated_date: INT5_8DIGIT
   		;
   
  -inc_period      : MINUTE | HOUR | DAY | WEEK | MONTH | YEAR
  +month_name	: JAN | FEB | MAR | APR | MAY | JUN
  +		| JUL | AUG | SEP | OCT | NOV | DEC
   		;
   
  -hr24clock_hr_min: INT
  +month_number	: int1_2digit
   		;
   
  -timezone_name	: WORD
  +day_number	: int1_2digit
   		;
   
  -hr24clock_hour	: hr24clock_hr_min
  +year_number	: int2_or_4digit
   		;
   
  -minute		: INT
  +day_of_week	: SUN | MON | TUE | WED | THU | FRI | SAT
   		;
   
  -am_pm		: AM | PM
  +inc_or_dec	: increment | decrement
   		;
   
  -month_name	: JAN | FEB | MAR | APR | MAY | JUN | JUL
  -		| AUG | SEP | OCT | NOV | DEC
  -		;
  +increment       : '+' inc_dec_number inc_dec_period
  +                ;
   
  -month_number	: INT
  +decrement	: '-' inc_dec_number inc_dec_period
   		;
  -day_number	: INT
  +
  +inc_dec_number	: integer
   		;
   
  -year_number	: INT
  +inc_dec_period	: MINUTE | HOUR | DAY | WEEK | MONTH | YEAR
   		;
   
  -day_of_week	: SUN | MON | TUE | WED | THU | FRI | SAT
  +int1_2digit	: INT1DIGIT | INT2DIGIT
   		;
   
  -inc_number	: INT
  +int2_or_4digit	: INT2DIGIT | INT4DIGIT
   		;
   
  -time_sep	: ':' | '\'' | '.' | 'h' | ','
  +integer		: INT | INT1DIGIT | INT2DIGIT | INT4DIGIT | INT5_8DIGIT
   		;
  +
  +%%
  
  
  



More information about the patches mailing list