root/anacron/lock.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. open_tsfile
  2. lock_file
  3. consider_job
  4. unlock
  5. update_timestamp
  6. fake_job

   1 /*
   2     Anacron - run commands periodically
   3     Copyright (C) 1998  Itai Tzur <itzur@actcom.co.il>
   4     Copyright (C) 1999  Sean 'Shaleh' Perry <shaleh@debian.org>
   5     Copyirght (C) 2004  Pascal Hakim <pasc@redellipse.net>
   6 
   7     This program is free software; you can redistribute it and/or modify
   8     it under the terms of the GNU General Public License as published by
   9     the Free Software Foundation; either version 2 of the License, or
  10     (at your option) any later version.
  11 
  12     This program is distributed in the hope that it will be useful,
  13     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15     GNU General Public License for more details.
  16 
  17     You should have received a copy of the GNU General Public License along
  18     with this program; if not, write to the Free Software Foundation, Inc.,
  19     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  20  
  21     The GNU General Public License can also be found in the file
  22     `COPYING' that comes with the Anacron source distribution.
  23 */
  24 
  25 
  26 /* Lock and timestamp management
  27  */
  28 
  29 #include <stdio.h>
  30 #include <fcntl.h>
  31 #include <sys/stat.h>
  32 #include <sys/types.h>
  33 #include <unistd.h>
  34 #include <errno.h>
  35 #include <signal.h>
  36 #include "global.h"
  37 #include "gregor.h"
  38 
  39 static void
  40 open_tsfile(job_rec *jr)
     /* [previous][next][first][last][top][bottom][index][help]  */
  41 /* Open the timestamp file for job jr */
  42 {
  43     jr->timestamp_fd = open(jr->ident, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
  44     if (jr->timestamp_fd == -1)
  45         die_e("Can't open timestamp file for job %s", jr->ident);
  46     fcntl(jr->timestamp_fd, F_SETFD, 1);    /* set close-on-exec flag */
  47     /* We want to own this file, and set its mode to 0600. This is necessary
  48      * in order to prevent other users from putting locks on it. */
  49     if (fchown(jr->timestamp_fd, getuid(), getgid()))
  50         die_e("Can't chown timestamp file %s", jr->ident);
  51     if (fchmod(jr->timestamp_fd, S_IRUSR | S_IWUSR))
  52         die_e("Can't chmod timestamp file %s", jr->ident);
  53 }
  54 
  55 static int
  56 lock_file(int fd)
     /* [previous][next][first][last][top][bottom][index][help]  */
  57 /* Attempt to put an exclusive fcntl() lock on file "fd"
  58  * Return 1 on success, 0 on failure.
  59  */
  60 {
  61     int r;
  62     struct flock sfl;
  63 
  64     sfl.l_type = F_WRLCK;
  65     sfl.l_start = 0;
  66     sfl.l_whence = SEEK_SET;
  67     sfl.l_len = 0;   /* we lock all the file */
  68     errno = 0;
  69     r = fcntl(fd, F_SETLK, &sfl);
  70     if (r != -1) return 1;
  71     if (errno != EACCES && errno != EAGAIN)
  72         die_e("fcntl() error");
  73     return 0;
  74 }
  75 
  76 int
  77 consider_job(job_rec *jr)
     /* [previous][next][first][last][top][bottom][index][help]  */
  78 /* Check the timestamp of the job. If "its time has come", lock the job
  79  * and return 1, if it's too early, or we can't get the lock, return 0.
  80  */
  81 {
  82     char timestamp[9];
  83     int ts_year, ts_month, ts_day, dn;
  84     ssize_t b;
  85 
  86     open_tsfile(jr);
  87 
  88     /* read timestamp */
  89     b = read(jr->timestamp_fd, timestamp, 8);
  90     if (b == -1) die_e("Error reading timestamp file %s", jr->ident);
  91     timestamp[8] = 0;
  92 
  93     /* is it too early? */
  94     if (!force && b == 8)
  95     {
  96         int day_delta;
  97         time_t jobtime;
  98         struct tm *t;
  99 
 100         if (sscanf(timestamp, "%4d%2d%2d", &ts_year, &ts_month, &ts_day) == 3)
 101             dn = day_num(ts_year, ts_month, ts_day);
 102         else
 103             dn = 0;
 104 
 105         day_delta = day_now - dn;
 106 
 107         /*
 108          * if day_delta is negative, we assume there was a clock skew 
 109          * and re-run any affected jobs
 110          * otherwise we check if the job's time has come
 111          */
 112         if (day_delta >= 0 && day_delta < jr->period)
 113         {
 114             /* yes, skip job */
 115             xclose(jr->timestamp_fd);
 116             return 0;
 117         }
 118 
 119         /*
 120          * Check to see if it's a named period, in which case we need 
 121          * to figure it out.
 122          */
 123         if (jr->named_period)
 124         {
 125             int period = 0, bypass = 0;
 126             switch (jr->named_period)
 127             {
 128                 case 1: /* monthly */
 129                     period = days_last_month ();
 130                     bypass = days_this_month ();
 131                     break;
 132                 case 2: /* yearly, annually */
 133                     period = days_last_year ();
 134                     bypass = days_this_year ();
 135                     break;
 136                 case 3: /* daily */
 137                         period = 1;
 138                         bypass = 1;
 139                         break;
 140                 case 4: /* weekly */
 141                         period = 7;
 142                         bypass = 7;
 143                         break;
 144                 default:
 145                     die ("Unknown named period for %s (%d)", jr->ident, jr->named_period);
 146             }
 147             printf ("Checking against %d with %d\n", day_delta, period);
 148             if (day_delta < period && day_delta != bypass)
 149             {
 150                 /* Job is still too young */
 151                 xclose (jr->timestamp_fd);
 152                 return 0;
 153             }
 154         }
 155 
 156         jobtime = start_sec + jr->delay * 60;
 157 
 158         t = localtime(&jobtime);
 159         if (!now && preferred_hour != -1 && t->tm_hour != preferred_hour) {
 160                 Debug(("The job's %s preferred hour %d was missed, skipping the job.", jr->ident, preferred_hour));
 161                 xclose (jr->timestamp_fd);
 162                 return 0;
 163         }
 164 
 165         if (!now && range_start != -1 && range_stop != -1 && 
 166                 (t->tm_hour < range_start || t->tm_hour >= range_stop))
 167         {
 168                 Debug(("The job `%s' falls out of the %02d:00-%02d:00 hours range, skipping.",
 169                         jr->ident, range_start, range_stop));
 170                 xclose (jr->timestamp_fd);
 171                 return 0;
 172         }
 173     }
 174 
 175     /* no! try to grab the lock */
 176     if (lock_file(jr->timestamp_fd)) return 1;  /* success */
 177 
 178     /* didn't get lock */
 179     xclose(jr->timestamp_fd);
 180     explain("Job `%s' locked by another anacron - skipping", jr->ident);
 181     return 0;
 182 }
 183 
 184 void
 185 unlock(job_rec *jr)
     /* [previous][next][first][last][top][bottom][index][help]  */
 186 {
 187     xclose(jr->timestamp_fd);
 188 }
 189 
 190 void
 191 update_timestamp(job_rec *jr)
     /* [previous][next][first][last][top][bottom][index][help]  */
 192 /* We write the date "now".  "Now" can be either the time when anacron
 193  * started, or the time when the job finished.
 194  * I'm not quite sure which is more "right", but I've decided on the first
 195  * option.
 196  * Note that this is not the way it was with anacron 1.0.3 to 1.0.7.  
 197  */
 198 {
 199     char stamp[10];
 200 
 201     snprintf(stamp, 10, "%04d%02d%02d\n", year, month, day_of_month);
 202     if (lseek(jr->timestamp_fd, 0, SEEK_SET))
 203         die_e("Can't lseek timestamp file for job %s", jr->ident);
 204     if (write(jr->timestamp_fd, stamp, 9) != 9)
 205         die_e("Can't write timestamp file for job %s", jr->ident);
 206     if (ftruncate(jr->timestamp_fd, 9))
 207         die_e("ftruncate error");
 208 }
 209 
 210 void
 211 fake_job(job_rec *jr)
     /* [previous][next][first][last][top][bottom][index][help]  */
 212 /* We don't bother with any locking here.  There's no point. */
 213 {
 214     open_tsfile(jr);
 215     update_timestamp(jr);
 216     xclose(jr->timestamp_fd);
 217 }

/* [previous][next][first][last][top][bottom][index][help]  */