source: trunk/athena/etc/larvnetd/config.c @ 13769

Revision 13769, 14.0 KB checked in by danw, 25 years ago (diff)
compile with warnings
Line 
1/* Copyright 1998 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
16/* This file is part of larvnetd, a monitoring server.  It implements
17 * functions to read and reread the configuration file.
18 */
19
20static const char rcsid[] = "$Id: config.c,v 1.4 1999-10-19 20:23:31 danw Exp $";
21
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <netinet/in.h>
25#include <arpa/inet.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <ctype.h>
30#include <unistd.h>
31#include <syslog.h>
32#include <netdb.h>
33#include <hesiod.h>
34#include "larvnetd.h"
35#include "timer.h"
36
37static int read_config(const char *configfile, struct config *config);
38static int find_numeric_range(const char *name, const char **start,
39                              const char **end, int *first, int *last);
40static void add_machine(struct config *config, int *machsize, const char *name,
41                        int cluster_index);
42static void freeconfig(struct config *config);
43static char *skip_spaces(char *p);
44static char *skip_nonspaces(char *p);
45
46void read_initial_config(struct serverstate *state)
47{
48  if (read_config(state->configfile, &state->config) == -1)
49    {
50      syslog(LOG_ALERT, "read_initial_config: can't read initial "
51             "configuration, aborting");
52      exit(1);
53    }
54}
55
56void reread_config(struct serverstate *state)
57{
58  struct config newconf;
59  struct machine *machine;
60  struct printer *printer;
61  int i, j, status;
62  char *errmem;
63
64  syslog(LOG_DEBUG, "reread_config");
65
66  /* Read from configfile into a new config structure. */
67  if (read_config(state->configfile, &newconf) == -1)
68    return;
69
70  /* Copy over workstation state to newconf. */
71  for (i = 0; i < state->config.nmachines; i++)
72    {
73      machine = ws_find(&newconf, state->config.machines[i].name);
74      if (machine)
75        {
76          syslog(LOG_DEBUG, "reread_config: ws %s copying state",
77                 machine->name);
78          machine->busy = state->config.machines[i].busy;
79          machine->laststatus = state->config.machines[i].laststatus;
80          machine->lastpoll = state->config.machines[i].lastpoll;
81          machine->numpolls = state->config.machines[i].numpolls;
82          if (state->config.machines[i].arch)
83            machine->arch = estrdup(state->config.machines[i].arch);
84          else
85            machine->arch = NULL;
86        }
87    }
88
89  /* Copy over printer state to newconf. */
90  for (i = 0; i < state->config.nprinters; i++)
91    {
92      for (j = 0; j < newconf.nprinters; j++)
93        {
94          printer = &newconf.printers[j];
95          if (strcmp(state->config.printers[i].name, printer->name) == 0)
96            {
97              syslog(LOG_DEBUG, "reread_config: printer %s copying state",
98                     printer->name);
99              printer->up = state->config.printers[i].up;
100              printer->jobs = state->config.printers[i].jobs;
101            }
102        }
103    }
104
105  /* Recreate the resolver channel, since any pending queries have
106   * invalid pointers as their arguments.
107   */
108  ares_destroy(state->channel);
109  status = ares_init(&state->channel);
110  if (status != ARES_SUCCESS)
111    {
112      syslog(LOG_ALERT, "reread_config: can't reinitialize resolver channel, "
113             "aborting: %s", ares_strerror(status, &errmem));
114      ares_free_errmem(errmem);
115      exit(1);
116    }
117
118  /* Now free the old config structure and copy the new one in. */
119  freeconfig(&state->config);
120  state->config = newconf;
121}
122
123static int read_config(const char *configfile, struct config *config)
124{
125  FILE *fp;
126  char *line = NULL, *p, *q, *name;
127  const char *range_start, *range_end;
128  int i, linesize, status, clsize, archsize, machsize, prsize, cgsize;
129  int cluster_index, retval = -1, range_first, range_last;
130  struct archname *arch;
131  struct cluster *cluster;
132  struct printer *printer;
133  struct cgroup *cgroup;
134
135  fp = fopen(configfile, "r");
136  if (!fp)
137    {
138      syslog(LOG_ERR, "read_config: can't open config file %s: %m",
139             configfile);
140      return -1;
141    }
142
143  /* Initialize the configuration lists. */
144  clsize = archsize = machsize = prsize = cgsize = 10;
145  config->clusters = emalloc(clsize * sizeof(struct cluster));
146  config->arches = emalloc(archsize * sizeof(struct archname));
147  config->machines = emalloc(machsize * sizeof(struct machine));
148  config->printers = emalloc(prsize * sizeof(struct printer));
149  config->cgroups = emalloc(cgsize * sizeof(struct cgroup));
150  config->nclusters = config->narch = config->nmachines = 0;
151  config->nprinters = config->ncgroups = 0;
152  config->report_other = NULL;
153  config->report_unknown = NULL;
154
155  /* Read in the architecture order.  Each line is an architecture
156   * name followed by an optional report name; a line beginning with
157   * a hyphen terminates the list.
158   */
159  while ((status = read_line(fp, &line, &linesize)) == 0)
160    {
161      p = skip_spaces(line);
162      q = skip_nonspaces(p);
163      if (*p == '#' || !*p)
164        continue;
165      if (*p == '-')
166        break;
167      if (config->narch == archsize)
168        {
169          archsize *= 2;
170          config->arches = erealloc(config->arches,
171                                    archsize * sizeof(struct archname));
172        }
173      arch = &config->arches[config->narch];
174      arch->reportname = estrndup(p, q - p);
175
176      /* Read in the net names for this architecture type. */
177      arch->netnames = NULL;
178      arch->nnetnames = 0;
179      p = skip_spaces(q);
180      while (*p)
181        {
182          q = skip_nonspaces(p);
183          arch->netnames = erealloc(arch->netnames,
184                                    (arch->nnetnames + 1) * sizeof(char *));
185          arch->netnames[arch->nnetnames] = estrndup(p, q - p);
186          arch->nnetnames++;
187          p = skip_spaces(q);
188        }
189
190      /* If no net names were specified, default to the report name. */
191      if (!arch->nnetnames)
192        {
193          arch->netnames = emalloc(sizeof(char *));
194          arch->netnames[0] = estrdup(arch->reportname);
195          arch->nnetnames = 1;
196        }
197
198      config->narch++;
199    }
200  if (status == -1)
201    {
202      syslog(LOG_ERR, "read_config: error reading config file %s: %m",
203             configfile);
204      goto cleanup;
205    }
206
207  /* Read in the clusters.  Possible line formats are:
208   *
209   *    cluster <name> <phone>
210   *    printer <name>
211   *    ws <hostname>
212   *    cgroup <name> <x> <y> <cluster> ...
213   *    option report-other <name>
214   *    option report-unknown <name>
215   *
216   * A ws or printer line must come after a cluster line.
217   */
218  cluster_index = -1;
219  while ((status = read_line(fp, &line, &linesize)) == 0)
220    {
221      /* Chop off the line at the comment delimiter, if any, and
222       * ignore leading whitespace.  If the line is empty except for
223       * whitespace and/or comments, ignore it.  Also eliminate
224       * trailing whitespace.
225       */
226      p = strchr(line, '#');
227      if (p)
228        *p = 0;
229      p = skip_spaces(line);
230      if (!*p)
231        continue;
232      q = p + strlen(p) - 1;
233      while (q > p && isspace((unsigned char)*q))
234        *q-- = 0;
235
236      if (strncmp(p, "cluster", 7) == 0 && isspace((unsigned char)p[7]))
237        {
238          if (config->nclusters == clsize)
239            {
240              clsize *= 2;
241              config->clusters = erealloc(config->clusters,
242                                          clsize * sizeof(struct cluster));
243            }
244          cluster = &config->clusters[config->nclusters];
245
246          /* Get the cluster name. */
247          p = skip_spaces(p + 8);
248          q = skip_nonspaces(p);
249          cluster->name = estrndup(p, q - p);
250
251          /* Read the cluster phone number. */
252          p = skip_spaces(q);
253          q = skip_nonspaces(p);
254          cluster->phone = estrndup(p, q - p);
255
256          /* Put the cluster in no cgroup to start with. */
257          cluster->cgroup = -1;
258
259          cluster_index = config->nclusters;
260          config->nclusters++;
261        }
262      else if (strncmp(p, "printer", 7) == 0 && isspace((unsigned char)p[7]))
263        {
264          if (cluster_index == -1)
265            {
266              syslog(LOG_ERR, "read_config: printer before cluster in %s: %s",
267                     configfile, line);
268              goto cleanup;
269            }
270          if (config->nprinters == prsize)
271            {
272              prsize *= 2;
273              config->printers = erealloc(config->printers,
274                                          prsize * sizeof(struct printer));
275            }
276          printer = &config->printers[config->nprinters];
277          p = skip_spaces(p + 7);
278          q = skip_nonspaces(p);
279          printer->name = estrndup(p, q - p);
280          p = skip_spaces(q);
281          q = skip_nonspaces(p);
282          printer->location = (*p) ? estrndup(p, q - p)
283              : estrdup(config->clusters[cluster_index].name);
284          printer->cluster = cluster_index;
285
286          /* Initialize state variables. */
287          printer->up = 0;
288          printer->jobs = 0;
289          printer->s = -1;
290          printer->timer = NULL;
291
292          config->nprinters++;
293        }
294      else if (strncmp(p, "ws", 2) == 0 && isspace((unsigned char)p[2]))
295        {
296          if (cluster_index == -1)
297            {
298              syslog(LOG_ERR, "read_config: workstation before cluster in "
299                     "%s: %s", configfile, line);
300              goto cleanup;
301            }
302
303          p = skip_spaces(p + 2);
304          q = skip_nonspaces(p);
305          *q = 0;
306
307          if (find_numeric_range(p, &range_start, &range_end, &range_first,
308                                 &range_last))
309            {
310              name = emalloc(strlen(p) + 100);
311              memcpy(name, p, range_start - p);
312              q = name + (range_start - p);
313              for (i = range_first; i <= range_last; i++)
314                {
315                  sprintf(q, "%d%s", i, range_end);
316                  add_machine(config, &machsize, name, cluster_index);
317                }
318              free(name);
319            }
320          else
321            add_machine(config, &machsize, p, cluster_index);
322        }
323      else if (strncmp(p, "cgroup", 6) == 0 && isspace((unsigned char)p[6]))
324        {
325          if (config->ncgroups == cgsize)
326            {
327              cgsize *= 2;
328              config->cgroups = erealloc(config->cgroups,
329                                         cgsize * sizeof(struct cgroup));
330            }
331          cgroup = &config->cgroups[config->ncgroups];
332          p = skip_spaces(p + 6);
333          q = skip_nonspaces(p);
334          cgroup->name = estrndup(p, q - p);
335          p = skip_spaces(q);
336          q = skip_nonspaces(p);
337          cgroup->x = atoi(p);
338          p = skip_spaces(q);
339          q = skip_nonspaces(p);
340          cgroup->y = atoi(p);
341          config->ncgroups++;
342          while (*q)
343            {
344              p = skip_spaces(q);
345              q = skip_nonspaces(p);
346              for (i = 0; i < config->nclusters; i++)
347                {
348                  if (strlen(config->clusters[i].name) == q - p
349                      && strncmp(config->clusters[i].name, p, q - p) == 0)
350                    break;
351                }
352              if (i == config->nclusters)
353                {
354                  syslog(LOG_ERR, "read_config: unknown cluster name %.*s in "
355                         "%s: %s", q - p, p, configfile, line);
356                  goto cleanup;
357                }
358              if (config->clusters[i].cgroup != -1)
359                {
360                  syslog(LOG_ERR, "read_config: cluster %.*s already in "
361                         "cluster group in %s: %s", q - p, p, configfile,
362                         line);
363                  goto cleanup;
364                }
365              config->clusters[i].cgroup = config->ncgroups - 1;
366            }
367        }
368      else if (strncmp(p, "option", 6) == 0 && isspace((unsigned char)p[6]))
369        {
370          p = skip_spaces(p + 6);
371          if (strncmp(p, "report-other", 12) == 0 &&
372              isspace((unsigned char)p[12]))
373            config->report_other = estrdup(skip_spaces(p + 12));
374          else if (strncmp(p, "report-unknown", 14) == 0 &&
375                   isspace((unsigned char)p[14]))
376            config->report_unknown = estrdup(skip_spaces(p + 14));
377          else
378            {
379              syslog(LOG_ERR, "read_config: unrecognized option %s", p);
380              goto cleanup;
381            }
382        }
383      else
384        {
385          syslog(LOG_ERR, "read_config: unrecognized line %s", line);
386          goto cleanup;
387        }
388    }
389  if (status == -1)
390    {
391      syslog(LOG_ERR, "read_config: error reading config file %s: %m",
392             configfile);
393      goto cleanup;
394    }
395
396  ws_sort(config);
397  retval = 0;
398
399cleanup:
400  if (retval == -1)
401    freeconfig(config);
402  fclose(fp);
403  free(line);
404  return retval;
405}
406
407static int find_numeric_range(const char *name, const char **start,
408                              const char **end, int *first, int *last)
409{
410  const char *p;
411
412  /* Find the opening bracket. */
413  p = strchr(name, '[');
414  if (!p)
415    return 0;
416  *start = p;
417
418  /* Read the range beginning. */
419  p++;
420  if (!isdigit((unsigned char)*p))
421    return 0;
422  *first = strtol(p, (char **) &p, 0);
423
424  /* Skip the dash in the middle. */
425  if (*p != '-')
426    return 0;
427  p++;
428
429  /* Read the range end. */
430  if (!isdigit((unsigned char)*p))
431    return 0;
432  *last = strtol(p, (char **) &p, 0);
433
434  /* Make sure we close with a square bracket. */
435  if (*p != ']')
436    return 0;
437  *end = p + 1;
438
439  return 1;
440}
441
442static void add_machine(struct config *config, int *machsize, const char *name,
443                        int cluster_index)
444{
445  struct machine *machine;
446
447  if (config->nmachines == *machsize)
448    {
449      *machsize *= 2;
450      config->machines = erealloc(config->machines,
451                                  *machsize * sizeof(struct machine));
452    }
453
454  machine = &config->machines[config->nmachines];
455  machine->name = estrdup(name);
456  machine->cluster = cluster_index;
457
458  /* Initialize state variables. */
459  machine->busy = UNKNOWN_BUSYSTATE;
460  machine->arch = NULL;
461  machine->laststatus = 0;
462  machine->lastpoll = 0;
463  machine->numpolls = 0;
464
465  config->nmachines++;
466}
467
468static void freeconfig(struct config *config)
469{
470  int i, j;
471
472  for (i = 0; i < config->nmachines; i++)
473    {
474      free(config->machines[i].name);
475      free(config->machines[i].arch);
476    }
477  for (i = 0; i < config->nprinters; i++)
478    {
479      free(config->printers[i].name);
480      free(config->printers[i].location);
481      if (config->printers[i].s != -1)
482        close(config->printers[i].s);
483      if (config->printers[i].timer)
484        free(timer_reset(config->printers[i].timer));
485    }
486  for (i = 0; i < config->nclusters; i++)
487    {
488      free(config->clusters[i].name);
489      free(config->clusters[i].phone);
490    }
491  for (i = 0; i < config->narch; i++)
492    {
493      free(config->arches[i].reportname);
494      for (j = 0; j < config->arches[i].nnetnames; j++)
495        free(config->arches[i].netnames[j]);
496      free(config->arches[i].netnames);
497    }
498  for (i = 0; i < config->ncgroups; i++)
499    free(config->cgroups[i].name);
500  free(config->clusters);
501  free(config->arches);
502  free(config->machines);
503  free(config->printers);
504  free(config->cgroups);
505  free(config->report_other);
506  free(config->report_unknown);
507}
508
509static char *skip_spaces(char *p)
510{
511  while (isspace((unsigned char)*p))
512    p++;
513  return p;
514}
515
516static char *skip_nonspaces(char *p)
517{
518  while (*p && !isspace((unsigned char)*p))
519    p++;
520  return p;
521}
Note: See TracBrowser for help on using the repository browser.