1/*
2 * Copyright (c) 1997-2014 Erez Zadok
3 * Copyright (c) 1989 Jan-Simon Pendry
4 * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1989 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 *
33 * File: am-utils/fsinfo/fsi_util.c
34 *
35 */
36
37#ifdef HAVE_CONFIG_H
38# include <config.h>
39#endif /* HAVE_CONFIG_H */
40#include <am_defs.h>
41#include <fsi_data.h>
42#include <fsinfo.h>
43
44/* static variables */
45static int show_range = 10;
46static int col = 0;
47static int total_shown = 0;
48static int total_mmm = 8;
49
50
51static int
52col_output(int len)
53{
54  int wrapped = 0;
55
56  col += len;
57  if (col > 77) {
58    fputc('\n', stdout);
59    col = len;
60    wrapped = 1;
61  }
62  return wrapped;
63}
64
65
66static void
67show_total(void)
68{
69  if (total_mmm != -show_range + 1) {
70    char n[8];
71    int len;
72
73    if (total_mmm < 0)
74      fputc('*', stdout);
75    xsnprintf(n, sizeof(n), "%d", total_shown);
76    len = strlen(n);
77    if (col_output(len))
78      fputc(' ', stdout);
79    fputs(n, stdout);
80    fflush(stdout);
81    total_mmm = -show_range;
82  }
83}
84
85
86void
87col_cleanup(int eoj)
88{
89  if (verbose < 0)
90    return;
91  if (eoj) {
92    show_total();
93    fputs(")]", stdout);
94  }
95  if (col) {
96    fputc('\n', stdout);
97    col = 0;
98  }
99}
100
101
102/*
103 * Lots of ways of reporting errors...
104 */
105void
106error(char *fmt, ...)
107{
108  va_list ap;
109
110  va_start(ap, fmt);
111  col_cleanup(0);
112  fprintf(stderr, "%s: Error, ", progname);
113  vfprintf(stderr, fmt, ap);
114  fputc('\n', stderr);
115  errors++;
116  va_end(ap);
117}
118
119
120void
121lerror(ioloc *l, char *fmt, ...)
122{
123  va_list ap;
124
125  va_start(ap, fmt);
126  col_cleanup(0);
127  fprintf(stderr, "%s:%d: ", l->i_file, l->i_line);
128  vfprintf(stderr, fmt, ap);
129  fputc('\n', stderr);
130  errors++;
131  va_end(ap);
132}
133
134
135void
136lwarning(ioloc *l, char *fmt, ...)
137{
138  va_list ap;
139
140  va_start(ap, fmt);
141  col_cleanup(0);
142  fprintf(stderr, "%s:%d: ", l->i_file, l->i_line);
143  vfprintf(stderr, fmt, ap);
144  fputc('\n', stderr);
145  va_end(ap);
146}
147
148
149void
150fatal(char *fmt, ...)
151{
152  va_list ap;
153
154  va_start(ap, fmt);
155  col_cleanup(1);
156  fprintf(stderr, "%s: Fatal, ", progname);
157  vfprintf(stderr, fmt, ap);
158  fputc('\n', stderr);
159  va_end(ap);
160  exit(1);
161}
162
163
164/*
165 * Debug log
166 */
167void
168fsi_log(char *fmt, ...)
169{
170  va_list ap;
171
172  if (verbose > 0) {
173    va_start(ap, fmt);
174    fputc('#', stdout);
175    fprintf(stdout, "%s: ", progname);
176    vfprintf(stdout, fmt, ap);
177    putc('\n', stdout);
178    va_end(ap);
179  }
180}
181
182
183void
184info_hdr(FILE *ef, char *info)
185{
186  fprintf(ef, "# *** NOTE: This file contains %s info\n", info);
187}
188
189
190void
191gen_hdr(FILE *ef, char *hn)
192{
193  fprintf(ef, "# *** NOTE: Only for use on %s\n", hn);
194}
195
196
197static void
198make_banner(FILE *fp)
199{
200  time_t t = time((time_t *) NULL);
201  char *cp = ctime(&t);
202
203  fprintf(fp,
204	  "\
205# *** This file was automatically generated -- DO NOT EDIT HERE ***\n\
206# \"%s\" run by %s@%s on %s\
207#\n\
208",
209	  progname, username, hostname, cp);
210}
211
212
213void
214show_new(char *msg)
215{
216  if (verbose < 0)
217    return;
218
219  total_shown++;
220  if (total_mmm > show_range) {
221    show_total();
222  } else if (total_mmm == 0) {
223    fputc('*', stdout);
224    fflush(stdout);
225    col += 1;
226  }
227  total_mmm++;
228}
229
230
231void
232show_area_being_processed(char *area, int n)
233{
234  static char *last_area = NULL;
235
236  if (verbose < 0)
237    return;
238  if (last_area) {
239    if (total_shown)
240      show_total();
241    fputs(")", stdout);
242    col += 1;
243  }
244
245  if (!last_area || !STREQ(area, last_area)) {
246    if (last_area) {
247      col_cleanup(0);
248      total_shown = 0;
249      total_mmm = show_range + 1;
250    }
251    (void) col_output(strlen(area) + 2);
252    fprintf(stdout, "[%s", area);
253    last_area = area;
254  }
255
256  fputs(" (", stdout);
257  col += 2;
258  show_range = n;
259  total_mmm = n + 1;
260
261  fflush(stdout);
262}
263
264
265/*
266 * Open a file with the given prefix and name
267 */
268FILE *
269pref_open(char *pref, char *hn, void (*hdr) (FILE *, char *), char *arg)
270{
271  char p[MAXPATHLEN];
272  FILE *ef;
273
274  xsnprintf(p, sizeof(p), "%s%s", pref, hn);
275  fsi_log("Writing %s info for %s to %s", pref, hn, p);
276  ef = fopen(p, "w");
277  if (ef) {
278    (*hdr) (ef, arg);
279    make_banner(ef);
280  } else {
281    error("can't open %s for writing", p);
282  }
283
284  return ef;
285}
286
287
288int
289pref_close(FILE *fp)
290{
291  return fclose(fp) == 0;
292}
293
294
295/*
296 * Determine where Amd would automount the host/volname pair
297 */
298void
299compute_automount_point(char *buf, size_t l, host *hp, char *vn)
300{
301  xsnprintf(buf, l, "%s/%s%s", autodir, hp->h_lochost, vn);
302}
303
304
305/*
306 * Data constructors..
307 */
308automount *
309new_automount(char *name)
310{
311  automount *ap = CALLOC(struct automount);
312
313  ap->a_ioloc = current_location();
314  ap->a_name = name;
315  ap->a_volname = NULL;
316  ap->a_mount = NULL;
317  ap->a_opts = NULL;
318  show_new("automount");
319  return ap;
320}
321
322
323auto_tree *
324new_auto_tree(char *def, qelem *ap)
325{
326  auto_tree *tp = CALLOC(struct auto_tree);
327
328  tp->t_ioloc = current_location();
329  tp->t_defaults = def;
330  tp->t_mount = ap;
331  show_new("auto_tree");
332  return tp;
333}
334
335
336host *
337new_host(void)
338{
339  host *hp = CALLOC(struct host);
340
341  hp->h_ioloc = current_location();
342  hp->h_mask = 0;
343  show_new("host");
344  return hp;
345}
346
347
348void
349set_host(host *hp, int k, char *v)
350{
351  int m = 1 << k;
352
353  if (hp->h_mask & m) {
354    fsi_error("host field \"%s\" already set", host_strings[k]);
355    return;
356  }
357  hp->h_mask |= m;
358
359  switch (k) {
360
361  case HF_HOST:{
362      char *p = xstrdup(v);
363      dict_ent *de = dict_locate(dict_of_hosts, v);
364
365      if (de)
366	fsi_error("duplicate host %s!", v);
367      else
368	dict_add(dict_of_hosts, v, (char *) hp);
369      hp->h_hostname = v;
370      domain_strip(p, hostname);
371      if (strchr(p, '.') != 0)
372	XFREE(p);
373      else
374	hp->h_lochost = p;
375    }
376    break;
377
378  case HF_CONFIG:{
379      qelem *q;
380      qelem *vq = (qelem *) v;
381
382      hp->h_mask &= ~m;
383      if (hp->h_config)
384	q = hp->h_config;
385      else
386	q = hp->h_config = new_que();
387      ins_que(vq, q->q_back);
388    }
389    break;
390
391  case HF_ETHER:{
392      qelem *q;
393      qelem *vq = (qelem *) v;
394
395      hp->h_mask &= ~m;
396      if (hp->h_ether)
397	q = hp->h_ether;
398      else
399	q = hp->h_ether = new_que();
400      ins_que(vq, q->q_back);
401    }
402    break;
403
404  case HF_ARCH:
405    hp->h_arch = v;
406    break;
407
408  case HF_OS:
409    hp->h_os = v;
410    break;
411
412  case HF_CLUSTER:
413    hp->h_cluster = v;
414    break;
415
416  default:
417    abort();
418    break;
419  }
420}
421
422
423ether_if *
424new_ether_if(void)
425{
426  ether_if *ep = CALLOC(struct ether_if);
427
428  ep->e_mask = 0;
429  ep->e_ioloc = current_location();
430  show_new("ether_if");
431  return ep;
432}
433
434
435void
436set_ether_if(ether_if *ep, int k, char *v)
437{
438  int m = 1 << k;
439
440  if (ep->e_mask & m) {
441    fsi_error("netif field \"%s\" already set", ether_if_strings[k]);
442    return;
443  }
444  ep->e_mask |= m;
445
446  switch (k) {
447
448  case EF_INADDR:{
449      ep->e_inaddr.s_addr = inet_addr(v);
450      if ((int) ep->e_inaddr.s_addr == (int) INADDR_NONE)
451	fsi_error("malformed IP dotted quad: %s", v);
452      XFREE(v);
453    }
454    break;
455
456  case EF_NETMASK:{
457      u_long nm = 0;
458
459      if ((sscanf(v, "0x%lx", &nm) == 1 || sscanf(v, "%lx", &nm) == 1) && nm != 0)
460	ep->e_netmask = htonl(nm);
461      else
462	fsi_error("malformed netmask: %s", v);
463      XFREE(v);
464    }
465    break;
466
467  case EF_HWADDR:
468    ep->e_hwaddr = v;
469    break;
470
471  default:
472    abort();
473    break;
474  }
475}
476
477
478void
479set_disk_fs(disk_fs *dp, int k, char *v)
480{
481  int m = 1 << k;
482
483  if (dp->d_mask & m) {
484    fsi_error("fs field \"%s\" already set", disk_fs_strings[k]);
485    return;
486  }
487  dp->d_mask |= m;
488
489  switch (k) {
490
491  case DF_FSTYPE:
492    dp->d_fstype = v;
493    break;
494
495  case DF_OPTS:
496    dp->d_opts = v;
497    break;
498
499  case DF_DUMPSET:
500    dp->d_dumpset = v;
501    break;
502
503  case DF_LOG:
504    dp->d_log = v;
505    break;
506
507  case DF_PASSNO:
508    dp->d_passno = atoi(v);
509    XFREE(v);
510    break;
511
512  case DF_FREQ:
513    dp->d_freq = atoi(v);
514    XFREE(v);
515    break;
516
517  case DF_MOUNT:
518    dp->d_mount = &((fsi_mount *) v)->m_q;
519    break;
520
521  default:
522    abort();
523    break;
524  }
525}
526
527
528disk_fs *
529new_disk_fs(void)
530{
531  disk_fs *dp = CALLOC(struct disk_fs);
532
533  dp->d_ioloc = current_location();
534  show_new("disk_fs");
535  return dp;
536}
537
538
539void
540set_mount(fsi_mount *mp, int k, char *v)
541{
542  int m = 1 << k;
543
544  if (mp->m_mask & m) {
545    fsi_error("mount tree field \"%s\" already set", mount_strings[k]);
546    return;
547  }
548  mp->m_mask |= m;
549
550  switch (k) {
551
552  case DM_VOLNAME:
553    dict_add(dict_of_volnames, v, (char *) mp);
554    mp->m_volname = v;
555    break;
556
557  case DM_EXPORTFS:
558    mp->m_exportfs = v;
559    break;
560
561  case DM_SEL:
562    mp->m_sel = v;
563    break;
564
565  default:
566    abort();
567    break;
568  }
569}
570
571
572fsi_mount *
573new_mount(void)
574{
575  fsi_mount *fp = CALLOC(struct fsi_mount);
576
577  fp->m_ioloc = current_location();
578  show_new("mount");
579  return fp;
580}
581
582
583void
584set_fsmount(fsmount *fp, int k, char *v)
585{
586  int m = 1 << k;
587
588  if (fp->f_mask & m) {
589    fsi_error("mount field \"%s\" already set", fsmount_strings[k]);
590    return;
591  }
592  fp->f_mask |= m;
593
594  switch (k) {
595
596  case FM_LOCALNAME:
597    fp->f_localname = v;
598    break;
599
600  case FM_VOLNAME:
601    fp->f_volname = v;
602    break;
603
604  case FM_FSTYPE:
605    fp->f_fstype = v;
606    break;
607
608  case FM_OPTS:
609    fp->f_opts = v;
610    break;
611
612  case FM_FROM:
613    fp->f_from = v;
614    break;
615
616  case FM_DIRECT:
617    break;
618
619  default:
620    abort();
621    break;
622  }
623}
624
625
626fsmount *
627new_fsmount(void)
628{
629  fsmount *fp = CALLOC(struct fsmount);
630
631  fp->f_ioloc = current_location();
632  show_new("fsmount");
633  return fp;
634}
635
636
637void
638init_que(qelem *q)
639{
640  q->q_forw = q->q_back = q;
641}
642
643
644qelem *
645new_que(void)
646{
647  qelem *q = CALLOC(qelem);
648
649  init_que(q);
650  return q;
651}
652
653
654void
655ins_que(qelem *elem, qelem *pred)
656{
657  qelem *p;
658
659  p = pred->q_forw;
660  elem->q_back = pred;
661  elem->q_forw = p;
662  pred->q_forw = elem;
663  p->q_back = elem;
664}
665
666
667void
668rem_que(qelem *elem)
669{
670  qelem *p, *p2;
671
672  p = elem->q_forw;
673  p2 = elem->q_back;
674
675  p2->q_forw = p;
676  p->q_back = p2;
677}
678