source: trunk/athena/bin/desync/desync.c @ 25710

Revision 25710, 5.4 KB checked in by jdreed, 12 years ago (diff)
Update usage and enforce limits in crontab mode
Line 
1/* Copyright 1996, 1997 by the Massachusetts Institute of Technology.
2 *
3 * Permission to use, copy, modify, and distribute this
4 * software and its documentation for any purpose and without
5 * fee is hereby granted, provided that the above copyright
6 * notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting
8 * documentation, and that the name of M.I.T. not be used in
9 * advertising or publicity pertaining to distribution of the
10 * software without specific, written prior permission.
11 * M.I.T. makes no representations about the suitability of
12 * this software for any purpose.  It is provided "as is"
13 * without express or implied warranty.
14 */
15
16static const char rcsid[] = "$Id: desync.c,v 1.9 2000-09-30 21:08:32 rbasch Exp $";
17
18/*
19 * desync - desynchronize cron jobs on networks
20 *
21 * This program is a tool which sleeps an ip-address dependent period
22 * of time in order to skew over the course of a set time cron jobs
23 * that would otherwise be synchronized. It should reside on local disk
24 * so as not to cause a fileserver load at its own invocation.
25 */
26
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <fcntl.h>
30#include <ctype.h>
31#include <string.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <errno.h>
35#include <unistd.h>
36#include <time.h>
37#include <limits.h>
38
39extern int optind;
40extern char *optarg;
41
42static char *progname;
43
44static unsigned long get_hash(const char *str);
45
46static void usage(void);
47
48int main(int argc, char **argv)
49{
50  const char *timefile = NULL, *hostname = NULL, *crontabhour = NULL;
51  char buf[128];
52  int range, interval, c, noop = 0;
53  unsigned long tval;
54  time_t timenow;
55  FILE *fp;
56
57  /* Save the program name. */
58  progname = argv[0];
59
60  /* Parse command-line flags. */
61  while ((c = getopt(argc, argv, "h:nc:t:")) != -1)
62    {
63      switch (c) {
64      case 'h':
65        hostname = optarg;
66        break;
67      case 'n':
68        noop = 1;
69        break;
70      case 'c':
71        crontabhour = optarg;
72        break;
73      case 't':
74        timefile = optarg;
75        break;
76      default:
77        usage();
78        return 2;
79      }
80    }
81
82  if (crontabhour && ((timefile != NULL) || (noop == 1))) {
83    usage();
84    return 2;
85  }
86  /* Get the time interval from the remaining argument, if there is one. */
87  argc -= optind;
88  argv += optind;
89  if ((argc > 1) && ! crontabhour) {
90    usage();
91    return 2;
92  }
93  if (argc >= 1) {
94    range = atoi(argv[0]);
95    argc -= 1;
96    argv += 1;
97  } else {
98    range = crontabhour == NULL ? 3600 : 60;
99  }
100  if ((range == 0) ||
101      (crontabhour && (range >= 1440)))
102    {
103      fprintf(stderr, "%s: Invalid range value\n", progname);
104      usage();
105      return 2;
106    }
107
108  /* Get a random number in the given range as the interval.  Seed the
109   * random number generator with a hash of the current host name, or
110   * the name given via the -h option.
111   */
112  if (hostname == NULL)
113    {
114      if (gethostname(buf, sizeof(buf)) != 0)
115        {
116          fprintf(stderr, "%s: Unable to obtain hostname: %s\n",
117                  progname, strerror(errno));
118          return 2;
119        }
120      buf[sizeof(buf) - 1] = '\0';
121      hostname = buf;
122    }
123  srand(get_hash(hostname));
124  interval = rand() % range;
125
126  if (timefile)
127    {
128      time(&timenow);
129      fp = fopen(timefile, "r");
130      if (fp)
131        {
132          if (fscanf(fp, "%lu", &tval) != 1)
133            {
134              fprintf(stderr, "%s: Invalid time file %s\n", progname,
135                      timefile);
136              return 2;
137            }
138          fclose(fp);
139          if (timenow >= tval)
140            {
141              if (noop)
142                puts("0");
143              else
144                unlink(timefile);
145              return 0;
146            }
147          else
148            {
149              if (noop)
150                printf("%lu\n", (unsigned long) (tval - timenow));
151              return 1;
152            }
153        }
154      else if (noop)
155        {
156          fprintf(stderr, "%s: Warning: Cannot open %s (%s)\n", progname,
157                  timefile, strerror(errno));
158          printf("%lu\n", (unsigned long) (interval));
159          return (interval == 0 ? 0 : 1);
160        }
161      else
162        {
163          if (interval == 0)
164            return 0;
165          fp = fopen(timefile, "w");
166          if (fp == NULL)
167            {
168              fprintf(stderr, "%s: Couldn't open %s for writing: %s\n",
169                      progname, timefile, strerror(errno));
170              return 2;
171            }
172          fprintf(fp, "%lu\n", (unsigned long)(timenow + interval));
173          fclose(fp);
174          return 1;
175        }
176    }
177  else if (crontabhour)
178    {
179      char *endptr;
180      int mins, hours = 0;
181      int j;
182      errno = 0;
183      hours = strtol(crontabhour, &endptr, 10);
184      if ((errno == ERANGE && (hours == LONG_MAX || hours == LONG_MIN))
185          || (errno != 0 && hours == 0)
186          || (endptr == crontabhour))
187        {
188          fprintf(stderr, "%s: Could not convert %s to integer\n", progname,
189                  crontabhour);
190        return 1;
191      }
192      if ((hours > 23) || (hours < 0 ))
193        {
194          fprintf(stderr,
195                  "%s: in crontab mode, hours must be between 0 and 23\n",
196                  progname);
197        return 1;
198      }
199      mins = interval % 60;
200      hours = (hours + (interval / 60)) % 24;
201      printf("%d %d * * *", mins, hours);
202      for (j = 0; j < argc; j++)
203        printf(" %s", argv[j]);
204      printf("\n");
205    }
206  else if (noop)
207    printf("%lu\n", (unsigned long) interval);
208  else
209    sleep(interval);
210
211  return 0;
212}
213
214static unsigned long get_hash(const char *str)
215{
216  const char *p;
217  unsigned long g, hashval = 0;
218
219  for (p = str; *p; p++)
220    {
221      hashval = (hashval << 4) + *p;
222      g = hashval & 0xf0000000;
223      if (g != 0) {
224        hashval ^= g >> 24;
225        hashval ^= g;
226      }
227    }
228
229  if (hashval == 0)
230    hashval = 1;
231
232  return hashval;
233}
234
235static void usage()
236{
237  fprintf(stderr,
238          "Usage: %s [-h name] [-n] [-t timefile] [range]\n       %s -c hour [range [crontab arguments]]\n",
239          progname, progname);
240}
Note: See TracBrowser for help on using the repository browser.