Tomas Mraz aa7429
diff -up at-3.1.20/atd.c.lock-locks at-3.1.20/atd.c
Tomas Mraz aa7429
--- at-3.1.20/atd.c.lock-locks	2016-07-01 10:41:50.640867692 +0200
Tomas Mraz aa7429
+++ at-3.1.20/atd.c	2016-07-01 10:42:32.345844967 +0200
Tomas Mraz aa7429
@@ -74,6 +74,9 @@
Tomas Mraz aa7429
 #include <syslog.h>
Tomas Mraz aa7429
 #endif
Tomas Mraz aa7429
 
Tomas Mraz aa7429
+#include <sys/file.h>
Tomas Mraz aa7429
+#include <utime.h>
Tomas Mraz aa7429
+
Tomas Mraz aa7429
 /* Local headers */
Tomas Mraz aa7429
 
Tomas Mraz aa7429
 #include "privs.h"
Tomas Mraz aa7429
@@ -288,7 +291,7 @@ run_file(const char *filename, uid_t uid
Tomas Mraz aa7429
  * mail to the user.
Tomas Mraz aa7429
  */
Tomas Mraz aa7429
     pid_t pid;
Tomas Mraz aa7429
-    int fd_out, fd_in;
Tomas Mraz aa7429
+    int fd_out, fd_in, fd_std;
Tomas Mraz aa7429
     char jobbuf[9];
Tomas Mraz aa7429
     char *mailname = NULL;
Tomas Mraz aa7429
     int mailsize = 128;
Tomas Mraz aa7429
@@ -410,6 +413,10 @@ run_file(const char *filename, uid_t uid
Tomas Mraz aa7429
 
Tomas Mraz aa7429
     fcntl(fd_in, F_SETFD, fflags & ~FD_CLOEXEC);
Tomas Mraz aa7429
 
Tomas Mraz aa7429
+    if (flock(fd_in, LOCK_EX | LOCK_NB) != 0)
Tomas Mraz aa7429
+	    perr("Somebody already locked the job %8lu (%.500s) - "
Tomas Mraz aa7429
+	     "aborting", jobno, filename);
Tomas Mraz aa7429
+
Tomas Mraz aa7429
     /*
Tomas Mraz aa7429
      * If the spool directory is mounted via NFS `atd' isn't able to
Tomas Mraz aa7429
      * read from the job file and will bump out here.  The file is
Tomas Mraz aa7429
@@ -553,10 +560,7 @@ run_file(const char *filename, uid_t uid
Tomas Mraz aa7429
 	PRIV_END
Tomas Mraz aa7429
     }
Tomas Mraz aa7429
     /* We're the parent.  Let's wait.
Tomas Mraz aa7429
-     */
Tomas Mraz aa7429
-    close(fd_in);
Tomas Mraz aa7429
-
Tomas Mraz aa7429
-    /* We inherited the master's SIGCHLD handler, which does a
Tomas Mraz aa7429
+       We inherited the master's SIGCHLD handler, which does a
Tomas Mraz aa7429
        non-blocking waitpid. So this blocking one will eventually
Tomas Mraz aa7429
        return with an ECHILD error. 
Tomas Mraz aa7429
      */
Tomas Mraz aa7429
@@ -573,14 +577,14 @@ run_file(const char *filename, uid_t uid
Tomas Mraz aa7429
     /* some sendmail implementations are confused if stdout, stderr are
Tomas Mraz aa7429
      * not available, so let them point to /dev/null
Tomas Mraz aa7429
      */
Tomas Mraz aa7429
-    if ((fd_in = open("/dev/null", O_WRONLY)) < 0)
Tomas Mraz aa7429
+    if ((fd_std = open("/dev/null", O_WRONLY)) < 0)
Tomas Mraz aa7429
 	perr("Could not open /dev/null.");
Tomas Mraz aa7429
-    if (dup2(fd_in, STDOUT_FILENO) < 0)
Tomas Mraz aa7429
+    if (dup2(fd_std, STDOUT_FILENO) < 0)
Tomas Mraz aa7429
 	perr("Could not use /dev/null as standard output.");
Tomas Mraz aa7429
-    if (dup2(fd_in, STDERR_FILENO) < 0)
Tomas Mraz aa7429
+    if (dup2(fd_std, STDERR_FILENO) < 0)
Tomas Mraz aa7429
 	perr("Could not use /dev/null as standard error.");
Tomas Mraz aa7429
-    if (fd_in != STDOUT_FILENO && fd_in != STDERR_FILENO)
Tomas Mraz aa7429
-	close(fd_in);
Tomas Mraz aa7429
+    if (fd_std != STDOUT_FILENO && fd_std != STDERR_FILENO)
Tomas Mraz aa7429
+	close(fd_std);
Tomas Mraz aa7429
 
Tomas Mraz aa7429
     if (unlink(filename) == -1)
Tomas Mraz aa7429
         syslog(LOG_WARNING, "Warning: removing output file for job %li failed: %s",
Tomas Mraz aa7429
@@ -588,7 +592,12 @@ run_file(const char *filename, uid_t uid
Tomas Mraz aa7429
 
Tomas Mraz aa7429
     /* The job is now finished.  We can delete its input file.
Tomas Mraz aa7429
      */
Tomas Mraz aa7429
-    chdir(ATJOB_DIR);
Tomas Mraz aa7429
+    if (chdir(ATJOB_DIR) != 0)
Tomas Mraz aa7429
+	perr("Somebody removed %s directory from under us.", ATJOB_DIR);
Tomas Mraz aa7429
+
Tomas Mraz aa7429
+    /* This also removes the flock */
Tomas Mraz aa7429
+    (void)close(fd_in);
Tomas Mraz aa7429
+
Tomas Mraz aa7429
     unlink(newname);
Tomas Mraz aa7429
     free(newname);
Tomas Mraz aa7429
 
Tomas Mraz aa7429
@@ -723,16 +732,18 @@ run_loop()
Tomas Mraz aa7429
 
Tomas Mraz aa7429
 	/* Skip lock files */
Tomas Mraz aa7429
 	if (queue == '=') {
Tomas Mraz aa7429
-            /* FIXME: calhariz */
Tomas Mraz aa7429
-            /* I think the following code is broken, but commenting
Tomas Mraz aa7429
-               may haven unknow side effects.  Make a release and see
Tomas Mraz aa7429
-               in the wild how it works. For more information see:
Tomas Mraz aa7429
-               https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=818508/*
Tomas Mraz aa7429
-
Tomas Mraz aa7429
-	    /* if ((buf.st_nlink == 1) && (run_time + CHECK_INTERVAL <= now)) { */
Tomas Mraz aa7429
-	    /*     /\* Remove stale lockfile FIXME: lock the lockfile, if you fail, it's still in use. *\/ */
Tomas Mraz aa7429
-	    /*     unlink(dirent->d_name); */
Tomas Mraz aa7429
-	    /* } */
Tomas Mraz aa7429
+	    if ((buf.st_nlink == 1) && (run_time + CHECK_INTERVAL <= now)) {
Tomas Mraz aa7429
+		int fd;
Tomas Mraz aa7429
+
Tomas Mraz aa7429
+		fd = open(dirent->d_name, O_RDONLY);
Tomas Mraz aa7429
+		if (fd != -1) {
Tomas Mraz aa7429
+			if (flock(fd, LOCK_EX | LOCK_NB) == 0) {
Tomas Mraz aa7429
+				unlink(dirent->d_name);
Tomas Mraz aa7429
+				syslog(LOG_NOTICE, "removing stale lock file %s\n", dirent->d_name);
Tomas Mraz aa7429
+			}
Tomas Mraz aa7429
+			(void)close(fd);
Tomas Mraz aa7429
+		}
Tomas Mraz aa7429
+	    }
Tomas Mraz aa7429
 	    continue;
Tomas Mraz aa7429
 	}
Tomas Mraz aa7429
 	/* Skip any other file types which may have been invented in