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