Author: gahr (ports committer)
Date: Fri Apr 12 14:32:16 2013
New Revision: 249406
URL: http://svnweb.freebsd.org/changeset/base/249406

Log:
  - Do not bail out if stat(2) fails with ENOENT in the spool directory. This
    happens if another atrm process removes a job while we're scanning through
    the directory.
  - While at it, optimize a bit the directory scanning, so that we quit looping
    as soon as all jobs specified in argv have been dealt with.
  
  Approved by:  cognet

Modified:
  head/usr.bin/at/at.c

Modified: head/usr.bin/at/at.c
==============================================================================
--- head/usr.bin/at/at.c        Fri Apr 12 14:23:21 2013        (r249405)
+++ head/usr.bin/at/at.c        Fri Apr 12 14:32:16 2013        (r249406)
@@ -531,6 +531,10 @@ process_jobs(int argc, char **argv, int 
     /* Delete every argument (job - ID) given
      */
     int i;
+    int rc;
+    int nofJobs;
+    int nofDone;
+    int statErrno;
     struct stat buf;
     DIR *spool;
     struct dirent *dirent;
@@ -538,6 +542,9 @@ process_jobs(int argc, char **argv, int 
     char queue;
     long jobno;
 
+    nofJobs = argc - optind;
+    nofDone = 0;
+
     PRIV_START
 
     if (chdir(ATJOB_DIR) != 0)
@@ -553,9 +560,20 @@ process_jobs(int argc, char **argv, int 
     while((dirent = readdir(spool)) != NULL) {
 
        PRIV_START
-       if (stat(dirent->d_name, &buf) != 0)
-           perr("cannot stat in " ATJOB_DIR);
+       rc = stat(dirent->d_name, &buf);
+       statErrno = errno;
        PRIV_END
+       /* There's a race condition between readdir above and stat here:
+        * another atrm process could have removed the file from the spool
+        * directory under our nose. If this happens, stat will set errno to
+        * ENOENT, which we shouldn't treat as fatal.
+        */
+       if (rc != 0) {
+           if (statErrno == ENOENT)
+               continue;
+           else
+               perr("cannot stat in " ATJOB_DIR);
+       }
 
        if(sscanf(dirent->d_name, "%c%5lx%8lx", &queue, &jobno, &ctm)!=3)
            continue;
@@ -601,9 +619,15 @@ process_jobs(int argc, char **argv, int 
                    errx(EXIT_FAILURE, "internal error, process_jobs = %d",
                        what);
                }
+
+               /* All arguments have been processed
+                */
+               if (++nofDone == nofJobs)
+                   goto end;
            }
        }
     }
+end:
     closedir(spool);
 } /* delete_jobs */
 
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to