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

Revision 12051, 13.6 KB checked in by ghudson, 26 years ago (diff)
Support grouping of net names into a single report name. To properly handle reloading of the config file, this means remembering the reported net name and translating it to a report name at report time.
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.2 1998-10-13 17:12:57 ghudson 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(*q))
234        *q-- = 0;
235
236      if (strncmp(p, "cluster", 7) == 0 && isspace(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(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          printer->cluster = cluster_index;
281
282          /* Initialize state variables. */
283          printer->up = 0;
284          printer->jobs = 0;
285          printer->s = -1;
286          printer->timer = NULL;
287
288          config->nprinters++;
289        }
290      else if (strncmp(p, "ws", 2) == 0 && isspace(p[2]))
291        {
292          if (cluster_index == -1)
293            {
294              syslog(LOG_ERR, "read_config: workstation before cluster in "
295                     "%s: %s", configfile, line);
296              goto cleanup;
297            }
298
299          p = skip_spaces(p + 2);
300          q = skip_nonspaces(p);
301          *q = 0;
302
303          if (find_numeric_range(p, &range_start, &range_end, &range_first,
304                                 &range_last))
305            {
306              name = emalloc(strlen(p) + 100);
307              memcpy(name, p, range_start - p);
308              q = name + (range_start - p);
309              for (i = range_first; i <= range_last; i++)
310                {
311                  sprintf(q, "%d%s", i, range_end);
312                  add_machine(config, &machsize, name, cluster_index);
313                }
314              free(name);
315            }
316          else
317            add_machine(config, &machsize, p, cluster_index);
318        }
319      else if (strncmp(p, "cgroup", 6) == 0 && isspace(p[6]))
320        {
321          if (config->ncgroups == cgsize)
322            {
323              cgsize *= 2;
324              config->cgroups = erealloc(config->cgroups,
325                                         cgsize * sizeof(struct cgroup));
326            }
327          cgroup = &config->cgroups[config->ncgroups];
328          p = skip_spaces(p + 6);
329          q = skip_nonspaces(p);
330          cgroup->name = estrndup(p, q - p);
331          p = skip_spaces(q);
332          q = skip_nonspaces(p);
333          cgroup->x = atoi(p);
334          p = skip_spaces(q);
335          q = skip_nonspaces(p);
336          cgroup->y = atoi(p);
337          config->ncgroups++;
338          while (*q)
339            {
340              p = skip_spaces(q);
341              q = skip_nonspaces(p);
342              for (i = 0; i < config->nclusters; i++)
343                {
344                  if (strlen(config->clusters[i].name) == q - p
345                      && strncmp(config->clusters[i].name, p, q - p) == 0)
346                    break;
347                }
348              if (i == config->nclusters)
349                {
350                  syslog(LOG_ERR, "read_config: unknown cluster name %.*s in "
351                         "%s: %s", q - p, p, configfile, line);
352                  goto cleanup;
353                }
354              if (config->clusters[i].cgroup != -1)
355                {
356                  syslog(LOG_ERR, "read_config: cluster %.*s already in "
357                         "cluster group in %s: %s", q - p, p, configfile,
358                         line);
359                  goto cleanup;
360                }
361              config->clusters[i].cgroup = config->ncgroups - 1;
362            }
363        }
364      else if (strncmp(p, "option", 6) == 0 && isspace(p[6]))
365        {
366          p = skip_spaces(p + 6);
367          if (strncmp(p, "report-other", 12) == 0 && isspace(p[12]))
368            config->report_other = estrdup(skip_spaces(p + 12));
369          else if (strncmp(p, "report-unknown", 14) == 0 && isspace(p[14]))
370            config->report_unknown = estrdup(skip_spaces(p + 14));
371          else
372            {
373              syslog(LOG_ERR, "read_config: unrecognized option %s", p);
374              goto cleanup;
375            }
376        }
377      else
378        {
379          syslog(LOG_ERR, "read_config: unrecognized line %s", line);
380          goto cleanup;
381        }
382    }
383  if (status == -1)
384    {
385      syslog(LOG_ERR, "read_config: error reading config file %s: %m",
386             configfile);
387      goto cleanup;
388    }
389
390  ws_sort(config);
391  retval = 0;
392
393cleanup:
394  if (retval == -1)
395    freeconfig(config);
396  fclose(fp);
397  free(line);
398  return retval;
399}
400
401static int find_numeric_range(const char *name, const char **start,
402                              const char **end, int *first, int *last)
403{
404  const char *p;
405
406  /* Find the opening bracket. */
407  p = strchr(name, '[');
408  if (!p)
409    return 0;
410  *start = p;
411
412  /* Read the range beginning. */
413  p++;
414  if (!isdigit(*p))
415    return 0;
416  *first = strtol(p, (char **) &p, 0);
417
418  /* Skip the dash in the middle. */
419  if (*p != '-')
420    return 0;
421  p++;
422
423  /* Read the range end. */
424  if (!isdigit(*p))
425    return 0;
426  *last = strtol(p, (char **) &p, 0);
427
428  /* Make sure we close with a square bracket. */
429  if (*p != ']')
430    return 0;
431  *end = p + 1;
432
433  return 1;
434}
435
436static void add_machine(struct config *config, int *machsize, const char *name,
437                        int cluster_index)
438{
439  struct machine *machine;
440
441  if (config->nmachines == *machsize)
442    {
443      *machsize *= 2;
444      config->machines = erealloc(config->machines,
445                                  *machsize * sizeof(struct machine));
446    }
447
448  machine = &config->machines[config->nmachines];
449  machine->name = estrdup(name);
450  machine->cluster = cluster_index;
451
452  /* Initialize state variables. */
453  machine->busy = UNKNOWN_BUSYSTATE;
454  machine->arch = NULL;
455  machine->laststatus = 0;
456  machine->lastpoll = 0;
457  machine->numpolls = 0;
458
459  config->nmachines++;
460}
461
462static void freeconfig(struct config *config)
463{
464  int i, j;
465
466  for (i = 0; i < config->nmachines; i++)
467    {
468      free(config->machines[i].name);
469      free(config->machines[i].arch);
470    }
471  for (i = 0; i < config->nprinters; i++)
472    {
473      free(config->printers[i].name);
474      if (config->printers[i].s != -1)
475        close(config->printers[i].s);
476      if (config->printers[i].timer)
477        free(timer_reset(config->printers[i].timer));
478    }
479  for (i = 0; i < config->nclusters; i++)
480    {
481      free(config->clusters[i].name);
482      free(config->clusters[i].phone);
483    }
484  for (i = 0; i < config->narch; i++)
485    {
486      free(config->arches[i].reportname);
487      for (j = 0; j < config->arches[i].nnetnames; j++)
488        free(config->arches[i].netnames[j]);
489      free(config->arches[i].netnames);
490    }
491  for (i = 0; i < config->ncgroups; i++)
492    free(config->cgroups[i].name);
493  free(config->clusters);
494  free(config->arches);
495  free(config->machines);
496  free(config->printers);
497  free(config->cgroups);
498  free(config->report_other);
499  free(config->report_unknown);
500}
501
502static char *skip_spaces(char *p)
503{
504  while (isspace(*p))
505    p++;
506  return p;
507}
508
509static char *skip_nonspaces(char *p)
510{
511  while (*p && !isspace(*p))
512    p++;
513  return p;
514}
Note: See TracBrowser for help on using the repository browser.