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

Revision 25704, 5.4 KB checked in by jdreed, 12 years ago (diff)
Fix usage in program and man page
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 = 3600;
99  }
100  if (range == 0)
101    {
102      fprintf(stderr, "%s: Invalid range value\n", progname);
103      usage();
104      return 2;
105    }
106
107  /* Get a random number in the given range as the interval.  Seed the
108   * random number generator with a hash of the current host name, or
109   * the name given via the -h option.
110   */
111  if (hostname == NULL)
112    {
113      if (gethostname(buf, sizeof(buf)) != 0)
114        {
115          fprintf(stderr, "%s: Unable to obtain hostname: %s\n",
116                  progname, strerror(errno));
117          return 2;
118        }
119      buf[sizeof(buf) - 1] = '\0';
120      hostname = buf;
121    }
122  srand(get_hash(hostname));
123  interval = rand() % range;
124
125  if (timefile)
126    {
127      time(&timenow);
128      fp = fopen(timefile, "r");
129      if (fp)
130        {
131          if (fscanf(fp, "%lu", &tval) != 1)
132            {
133              fprintf(stderr, "%s: Invalid time file %s\n", progname,
134                      timefile);
135              return 2;
136            }
137          fclose(fp);
138          if (timenow >= tval)
139            {
140              if (noop)
141                puts("0");
142              else
143                unlink(timefile);
144              return 0;
145            }
146          else
147            {
148              if (noop)
149                printf("%lu\n", (unsigned long) (tval - timenow));
150              return 1;
151            }
152        }
153      else if (noop)
154        {
155          fprintf(stderr, "%s: Warning: Cannot open %s (%s)\n", progname,
156                  timefile, strerror(errno));
157          printf("%lu\n", (unsigned long) (interval));
158          return (interval == 0 ? 0 : 1);
159        }
160      else
161        {
162          if (interval == 0)
163            return 0;
164          fp = fopen(timefile, "w");
165          if (fp == NULL)
166            {
167              fprintf(stderr, "%s: Couldn't open %s for writing: %s\n",
168                      progname, timefile, strerror(errno));
169              return 2;
170            }
171          fprintf(fp, "%lu\n", (unsigned long)(timenow + interval));
172          fclose(fp);
173          return 1;
174        }
175    }
176  else if (crontabhour)
177    {
178      char *endptr;
179      int mins, hours = 0;
180      int j;
181      errno = 0;
182      hours = strtol(crontabhour, &endptr, 10);
183      if ((errno == ERANGE && (hours == LONG_MAX || hours == LONG_MIN))
184          || (errno != 0 && hours == 0)
185          || (endptr == crontabhour))
186        {
187          fprintf(stderr, "%s: Could not convert %s to integer\n", progname,
188                  crontabhour);
189        return 1;
190      }
191      if ((hours > 23) || (hours < 0 ))
192        {
193          fprintf(stderr,
194                  "%s: in crontab mode, hours must be between 0 and 23\n",
195                  progname);
196        return 1;
197      }
198      mins = interval % 60;
199      hours = (hours + (interval / 60)) % 24;
200      printf("%d %d * * *", mins, hours);
201      for (j = 0; j < argc; j++)
202        printf(" %s", argv[j]);
203      printf("\n");
204    }
205  else if (noop)
206    printf("%lu\n", (unsigned long) interval);
207  else
208    sleep(interval);
209
210  return 0;
211}
212
213static unsigned long get_hash(const char *str)
214{
215  const char *p;
216  unsigned long g, hashval = 0;
217
218  for (p = str; *p; p++)
219    {
220      hashval = (hashval << 4) + *p;
221      g = hashval & 0xf0000000;
222      if (g != 0) {
223        hashval ^= g >> 24;
224        hashval ^= g;
225      }
226    }
227
228  if (hashval == 0)
229    hashval = 1;
230
231  return hashval;
232}
233
234static void usage()
235{
236  fprintf(stderr,
237          "Usage: %s [-h name] [-n] [-t timefile] [range]\n       %s -c hour [range] [crontab arguments]\n",
238          progname, progname);
239}
Note: See TracBrowser for help on using the repository browser.