1/*	$NetBSD$	*/
2
3/*
4 * Copyright (c) 1997-2014 Erez Zadok
5 * Copyright (c) 1990 Jan-Simon Pendry
6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
7 * Copyright (c) 1990 The Regents of the University of California.
8 * All rights reserved.
9 *
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 *    notice, this list of conditions and the following disclaimer in the
20 *    documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 *    may be used to endorse or promote products derived from this software
23 *    without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 *
38 * File: am-utils/amd/get_args.c
39 *
40 */
41
42/*
43 * Argument decode
44 */
45
46#ifdef HAVE_CONFIG_H
47# include <config.h>
48#endif /* HAVE_CONFIG_H */
49#include <am_defs.h>
50#include <amd.h>
51
52/* include auto-generated version file */
53#include <build_version.h>
54
55char *amu_conf_file = "/etc/amd.conf"; /* default amd configuration file */
56char *conf_tag = NULL;		/* default conf file tags to use */
57int usage = 0;
58int use_conf_file = 0;		/* default don't use amd.conf file */
59char *mnttab_file_name = NULL;	/* symbol must be available always */
60
61
62/*
63 * Return the version string (dynamic buffer)
64 */
65char *
66get_version_string(void)
67{
68  char *vers = NULL;
69  char tmpbuf[1024];
70  char *wire_buf;
71  int wire_buf_len = 0;
72  size_t len;		  /* max allocated length (to avoid buf overflow) */
73
74  /*
75   * First get dynamic string listing all known networks.
76   * This could be a long list, if host has lots of interfaces.
77   */
78  wire_buf = print_wires();
79  if (wire_buf)
80    wire_buf_len = strlen(wire_buf);
81
82  len = 2048 + wire_buf_len;
83  vers = xmalloc(len);
84  xsnprintf(vers, len, "%s\n%s\n%s\n%s\n",
85	    "Copyright (c) 1997-2014 Erez Zadok",
86	    "Copyright (c) 1990 Jan-Simon Pendry",
87	    "Copyright (c) 1990 Imperial College of Science, Technology & Medicine",
88	    "Copyright (c) 1990 The Regents of the University of California.");
89  xsnprintf(tmpbuf, sizeof(tmpbuf), "%s version %s (build %d).\n",
90	    PACKAGE_NAME, PACKAGE_VERSION, AMU_BUILD_VERSION);
91  xstrlcat(vers, tmpbuf, len);
92  xsnprintf(tmpbuf, sizeof(tmpbuf), "Report bugs to %s.\n", PACKAGE_BUGREPORT);
93  xstrlcat(vers, tmpbuf, len);
94  xsnprintf(tmpbuf, sizeof(tmpbuf), "Configured by %s@%s on date %s.\n",
95	    USER_NAME, HOST_NAME, CONFIG_DATE);
96  xstrlcat(vers, tmpbuf, len);
97  xsnprintf(tmpbuf, sizeof(tmpbuf), "Built by %s@%s on date %s.\n",
98	    BUILD_USER, BUILD_HOST, BUILD_DATE);
99  xstrlcat(vers, tmpbuf, len);
100  xsnprintf(tmpbuf, sizeof(tmpbuf), "cpu=%s (%s-endian), arch=%s, karch=%s.\n",
101	    cpu, endian, gopt.arch, gopt.karch);
102  xstrlcat(vers, tmpbuf, len);
103  xsnprintf(tmpbuf, sizeof(tmpbuf), "full_os=%s, os=%s, osver=%s, vendor=%s, distro=%s.\n",
104	    gopt.op_sys_full, gopt.op_sys, gopt.op_sys_ver, gopt.op_sys_vendor, DISTRO_NAME);
105  xstrlcat(vers, tmpbuf, len);
106  xsnprintf(tmpbuf, sizeof(tmpbuf), "domain=%s, host=%s, hostd=%s.\n",
107	    hostdomain, am_get_hostname(), hostd);
108  xstrlcat(vers, tmpbuf, len);
109
110  xstrlcat(vers, "Map support for: ", len);
111  mapc_showtypes(tmpbuf, sizeof(tmpbuf));
112  xstrlcat(vers, tmpbuf, len);
113  xstrlcat(vers, ".\nAMFS: ", len);
114  ops_showamfstypes(tmpbuf, sizeof(tmpbuf));
115  xstrlcat(vers, tmpbuf, len);
116  xstrlcat(vers, ", inherit.\nFS: ", len); /* hack: "show" that we support type:=inherit */
117  ops_showfstypes(tmpbuf, sizeof(tmpbuf));
118  xstrlcat(vers, tmpbuf, len);
119
120  /* append list of networks if available */
121  if (wire_buf) {
122    xstrlcat(vers, wire_buf, len);
123    XFREE(wire_buf);
124  }
125
126  return vers;
127}
128
129
130static void
131show_usage(void)
132{
133  fprintf(stderr,
134	  "Usage: %s [-nprvHS] [-a mount_point] [-c cache_time] [-d domain]\n\
135\t[-k kernel_arch] [-l logfile%s\n\
136\t[-t timeout.retrans] [-w wait_timeout] [-A arch] [-C cluster_name]\n\
137\t[-o op_sys_ver] [-O op_sys_name]\n\
138\t[-F conf_file] [-T conf_tag]", am_get_progname(),
139#ifdef HAVE_SYSLOG
140# ifdef LOG_DAEMON
141	  "|\"syslog[:facility]\"]"
142# else /* not LOG_DAEMON */
143	  "|\"syslog\"]"
144# endif /* not LOG_DAEMON */
145#else /* not HAVE_SYSLOG */
146	  "]"
147#endif /* not HAVE_SYSLOG */
148	  );
149
150#ifdef HAVE_MAP_NIS
151  fputs(" [-y nis-domain]\n", stderr);
152#else /* not HAVE_MAP_NIS */
153  fputc('\n', stderr);
154#endif /* HAVE_MAP_NIS */
155
156  show_opts('x', xlog_opt);
157#ifdef DEBUG
158  show_opts('D', dbg_opt);
159#endif /* DEBUG */
160  fprintf(stderr, "\t[directory mapname [-map_options]] ...\n");
161}
162
163
164void
165get_args(int argc, char *argv[])
166{
167  int opt_ch, i;
168  FILE *fp = stdin;
169  char getopt_arguments[] = "+nprvSa:c:d:k:l:o:t:w:x:y:C:D:F:T:O:HA:";
170  char *getopt_args;
171  int print_version = 0;	/* 1 means we should print version info */
172
173#ifdef HAVE_GNU_GETOPT
174  getopt_args = getopt_arguments;
175#else /* ! HAVE_GNU_GETOPT */
176  getopt_args = &getopt_arguments[1];
177#endif /* HAVE_GNU_GETOPT */
178
179  /* if no arguments were passed, try to use /etc/amd.conf file */
180  if (argc <= 1)
181    use_conf_file = 1;
182
183  while ((opt_ch = getopt(argc, argv, getopt_args)) != -1)
184    switch (opt_ch) {
185
186    case 'a':
187      if (*optarg != '/') {
188	fprintf(stderr, "%s: -a option must begin with a '/'\n",
189		am_get_progname());
190	exit(1);
191      }
192      gopt.auto_dir = optarg;
193      break;
194
195    case 'c':
196      gopt.am_timeo = atoi(optarg);
197      if (gopt.am_timeo <= 0)
198	gopt.am_timeo = AM_TTL;
199      break;
200
201    case 'd':
202      gopt.sub_domain = optarg;
203      break;
204
205    case 'k':
206      gopt.karch = optarg;
207      break;
208
209    case 'l':
210      gopt.logfile = optarg;
211      break;
212
213    case 'n':
214      gopt.flags |= CFM_NORMALIZE_HOSTNAMES;
215      break;
216
217    case 'o':
218      gopt.op_sys_ver = optarg;
219      break;
220
221    case 'p':
222     gopt.flags |= CFM_PRINT_PID;
223      break;
224
225    case 'r':
226      gopt.flags |= CFM_RESTART_EXISTING_MOUNTS;
227      break;
228
229    case 't':
230      /* timeo.retrans (also affects toplvl mounts) */
231      {
232	char *dot = strchr(optarg, '.');
233	int i;
234	if (dot)
235	  *dot = '\0';
236	if (*optarg) {
237	  for (i=0; i<AMU_TYPE_MAX; ++i)
238	    gopt.amfs_auto_timeo[i] = atoi(optarg);
239	}
240	if (dot) {
241	  for (i=0; i<AMU_TYPE_MAX; ++i)
242	    gopt.amfs_auto_retrans[i] = atoi(dot + 1);
243	  *dot = '.';
244	}
245      }
246      break;
247
248    case 'v':
249      /*
250       * defer to print version info after every variable had been
251       * initialized.
252       */
253      print_version++;
254      break;
255
256    case 'w':
257      gopt.am_timeo_w = atoi(optarg);
258      if (gopt.am_timeo_w <= 0)
259	gopt.am_timeo_w = AM_TTL_W;
260      break;
261
262    case 'x':
263      usage += switch_option(optarg);
264      break;
265
266    case 'y':
267#ifdef HAVE_MAP_NIS
268      gopt.nis_domain = optarg;
269#else /* not HAVE_MAP_NIS */
270      plog(XLOG_USER, "-y: option ignored.  No NIS support available.");
271#endif /* not HAVE_MAP_NIS */
272      break;
273
274    case 'A':
275      gopt.arch = optarg;
276      break;
277
278    case 'C':
279      gopt.cluster = optarg;
280      break;
281
282    case 'D':
283#ifdef DEBUG
284      usage += debug_option(optarg);
285#else /* not DEBUG */
286      fprintf(stderr, "%s: not compiled with DEBUG option -- sorry.\n",
287	      am_get_progname());
288#endif /* not DEBUG */
289      break;
290
291    case 'F':
292      amu_conf_file = optarg;
293      use_conf_file = 1;
294      break;
295
296    case 'H':
297      show_usage();
298      exit(1);
299      break;
300
301    case 'O':
302      gopt.op_sys = optarg;
303      break;
304
305    case 'S':
306      gopt.flags &= ~CFM_PROCESS_LOCK; /* turn process locking off */
307      break;
308
309    case 'T':
310      conf_tag = optarg;
311      break;
312
313    default:
314      usage = 1;
315      break;
316    }
317
318  /*
319   * amd.conf file: if not command-line arguments were used, or if -F was
320   * specified, then use that amd.conf file.  If the file cannot be opened,
321   * abort amd.  If it can be found, open it, parse it, and then close it.
322   */
323  if (use_conf_file && amu_conf_file) {
324    fp = fopen(amu_conf_file, "r");
325    if (!fp) {
326      char buf[128];
327      xsnprintf(buf, sizeof(buf), "Amd configuration file (%s)",
328		amu_conf_file);
329      perror(buf);
330      exit(1);
331    }
332    conf_in = fp;
333    conf_parse();
334    fclose(fp);
335    if (process_all_regular_maps() != 0)
336      exit(1);
337  }
338
339#ifdef DEBUG
340  usage += switch_option("debug");
341  /* initialize debug options */
342  if (!debug_flags)
343    debug_flags = D_CONTROL;	/* CONTROL = "daemon,amq,fork" */
344#endif /* DEBUG */
345
346  /* log information regarding amd.conf file */
347  if (use_conf_file && amu_conf_file)
348    plog(XLOG_INFO, "using configuration file %s", amu_conf_file);
349
350#ifdef HAVE_MAP_LDAP
351  /* ensure that if ldap_base is specified, that also ldap_hostports is */
352  if (gopt.ldap_hostports && !gopt.ldap_base) {
353    fprintf(stderr, "must specify both ldap_hostports and ldap_base\n");
354    exit(1);
355  }
356#endif /* HAVE_MAP_LDAP */
357
358  if (usage) {
359    show_usage();
360    exit(1);
361  }
362
363  while (optind <= argc - 2) {
364    char *dir = argv[optind++];
365    char *map = argv[optind++];
366    char *opts = "";
367    if (argv[optind] && *argv[optind] == '-')
368      opts = &argv[optind++][1];
369
370    root_newmap(dir, opts, map, NULL);
371  }
372
373  if (optind == argc) {
374    /*
375     * Append domain name to hostname.
376     * sub_domain overrides hostdomain
377     * if given.
378     */
379    if (gopt.sub_domain)
380      hostdomain = gopt.sub_domain;
381    if (*hostdomain == '.')
382      hostdomain++;
383    xstrlcat(hostd, ".", sizeof(hostd));
384    xstrlcat(hostd, hostdomain, sizeof(hostd));
385
386#ifdef MOUNT_TABLE_ON_FILE
387    if (amuDebug(D_MTAB))
388      if (gopt.debug_mtab_file)
389        mnttab_file_name = gopt.debug_mtab_file; /* user supplied debug mtab path */
390      else
391	mnttab_file_name = DEBUG_MNTTAB_FILE; /* default debug mtab path */
392    else
393      mnttab_file_name = MNTTAB_FILE_NAME;
394#else /* not MOUNT_TABLE_ON_FILE */
395    if (amuDebug(D_MTAB))
396      dlog("-D mtab option ignored");
397# ifdef MNTTAB_FILE_NAME
398    mnttab_file_name = MNTTAB_FILE_NAME;
399# endif /* MNTTAB_FILE_NAME */
400#endif /* not MOUNT_TABLE_ON_FILE */
401
402    /*
403     * If the kernel architecture was not specified
404     * then use the machine architecture.
405     */
406    if (gopt.karch == NULL)
407      gopt.karch = gopt.arch;
408
409    if (gopt.cluster == NULL)
410      gopt.cluster = hostdomain;
411
412    /* sanity checking, normalize values just in case (toplvl too) */
413    for (i=0; i<AMU_TYPE_MAX; ++i) {
414      if (gopt.amfs_auto_timeo[i] == 0)
415	gopt.amfs_auto_timeo[i] = AMFS_AUTO_TIMEO;
416      if (gopt.amfs_auto_retrans[i] == 0)
417	gopt.amfs_auto_retrans[i] = AMFS_AUTO_RETRANS(i);
418      if (gopt.amfs_auto_retrans[i] == 0)
419	gopt.amfs_auto_retrans[i] = 3;	/* under very unusual circumstances, could be zero */
420    }
421  }
422
423  /* finally print version string and exit, if asked for */
424  if (print_version) {
425    fputs(get_version_string(), stderr);
426    exit(0);
427  }
428
429  if (switch_to_logfile(gopt.logfile, orig_umask,
430			(gopt.flags & CFM_TRUNCATE_LOG)) != 0)
431    plog(XLOG_USER, "Cannot switch logfile");
432
433  return;
434}
435