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

Revision 15156, 4.3 KB checked in by rbasch, 24 years ago (diff)
Add -n option to output the time the program would sleep (or the time remaining in the timefile in the -t case), and -h <name> to specify an alternate host name to hash.
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
38extern int optind;
39extern char *optarg;
40
41static char *progname;
42
43static unsigned long get_hash(const char *str);
44
45static void usage(void);
46
47int main(int argc, char **argv)
48{
49  const char *timefile = NULL, *hostname = NULL;
50  char buf[128];
51  int range, interval, c, noop = 0;
52  unsigned long tval;
53  time_t timenow;
54  FILE *fp;
55
56  /* Save the program name. */
57  progname = argv[0];
58
59  /* Parse command-line flags. */
60  while ((c = getopt(argc, argv, "h:nt:")) != -1)
61    {
62      switch (c) {
63      case 'h':
64        hostname = optarg;
65        break;
66      case 'n':
67        noop = 1;
68        break;
69      case 't':
70        timefile = optarg;
71        break;
72      default:
73        usage();
74        return 2;
75      }
76    }
77
78  /* Get the time interval from the remaining argument, if there is one. */
79  argc -= optind;
80  argv += optind;
81  range = (argc == 1) ? atoi(argv[0]) : 3600;
82  if (range == 0)
83    {
84      fprintf(stderr, "%s: Invalid range value\n", progname);
85      usage();
86      return 2;
87    }
88
89  /* Get a random number in the given range as the interval.  Seed the
90   * random number generator with a hash of the current host name, or
91   * the name given via the -h option.
92   */
93  if (hostname == NULL)
94    {
95      if (gethostname(buf, sizeof(buf)) != 0)
96        {
97          fprintf(stderr, "%s: Unable to obtain hostname: %s\n",
98                  progname, strerror(errno));
99          return 2;
100        }
101      buf[sizeof(buf) - 1] = '\0';
102      hostname = buf;
103    }
104  srand(get_hash(hostname));
105  interval = rand() % range;
106
107  if (timefile)
108    {
109      time(&timenow);
110      fp = fopen(timefile, "r");
111      if (fp)
112        {
113          if (fscanf(fp, "%lu", &tval) != 1)
114            {
115              fprintf(stderr, "%s: Invalid time file %s\n", progname,
116                      timefile);
117              return 2;
118            }
119          fclose(fp);
120          if (timenow >= tval)
121            {
122              if (noop)
123                puts("0");
124              else
125                unlink(timefile);
126              return 0;
127            }
128          else
129            {
130              if (noop)
131                printf("%lu\n", (unsigned long) (tval - timenow));
132              return 1;
133            }
134        }
135      else if (noop)
136        {
137          fprintf(stderr, "%s: Warning: Cannot open %s (%s)\n", progname,
138                  timefile, strerror(errno));
139          printf("%lu\n", (unsigned long) (interval));
140          return (interval == 0 ? 0 : 1);
141        }
142      else
143        {
144          if (interval == 0)
145            return 0;
146          fp = fopen(timefile, "w");
147          if (fp == NULL)
148            {
149              fprintf(stderr, "%s: Couldn't open %s for writing: %s\n",
150                      progname, timefile, strerror(errno));
151              return 2;
152            }
153          fprintf(fp, "%lu\n", (unsigned long)(timenow + interval));
154          fclose(fp);
155          return 1;
156        }
157    }
158  else if (noop)
159    printf("%lu\n", (unsigned long) interval);
160  else
161    sleep(interval);
162
163  return 0;
164}
165
166static unsigned long get_hash(const char *str)
167{
168  const char *p;
169  unsigned long g, hashval = 0;
170
171  for (p = str; *p; p++)
172    {
173      hashval = (hashval << 4) + *p;
174      g = hashval & 0xf0000000;
175      if (g != 0) {
176        hashval ^= g >> 24;
177        hashval ^= g;
178      }
179    }
180
181  if (hashval == 0)
182    hashval = 1;
183
184  return hashval;
185}
186
187static void usage()
188{
189  fprintf(stderr,
190          "Usage: %s [-h name] [-n] [-t timefile] [range]\n",
191          progname);
192}
Note: See TracBrowser for help on using the repository browser.