amq.c revision 38494
11638Srgrimes/*
21638Srgrimes * Copyright (c) 1997-1998 Erez Zadok
31638Srgrimes * Copyright (c) 1990 Jan-Simon Pendry
41638Srgrimes * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
51638Srgrimes * Copyright (c) 1990 The Regents of the University of California.
61638Srgrimes * All rights reserved.
71638Srgrimes *
81638Srgrimes * This code is derived from software contributed to Berkeley by
91638Srgrimes * Jan-Simon Pendry at Imperial College, London.
101638Srgrimes *
111638Srgrimes * Redistribution and use in source and binary forms, with or without
121638Srgrimes * modification, are permitted provided that the following conditions
131638Srgrimes * are met:
141638Srgrimes * 1. Redistributions of source code must retain the above copyright
151638Srgrimes *    notice, this list of conditions and the following disclaimer.
161638Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
171638Srgrimes *    notice, this list of conditions and the following disclaimer in the
181638Srgrimes *    documentation and/or other materials provided with the distribution.
191638Srgrimes * 3. All advertising materials mentioning features or use of this software
201638Srgrimes *    must display the following acknowledgement:
211638Srgrimes *      This product includes software developed by the University of
221638Srgrimes *      California, Berkeley and its contributors.
231638Srgrimes * 4. Neither the name of the University nor the names of its contributors
241638Srgrimes *    may be used to endorse or promote products derived from this software
251638Srgrimes *    without specific prior written permission.
261638Srgrimes *
271638Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
281638Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
291638Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
301638Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
311638Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
321638Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3350476Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
341638Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35201118Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
361638Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3779538Sru * SUCH DAMAGE.
381638Srgrimes *
391638Srgrimes *      %W% (Berkeley) %G%
401638Srgrimes *
411638Srgrimes * $Id: amq.c,v 5.2.2.1 1992/02/09 15:09:16 jsp beta $
4284306Sru *
431638Srgrimes */
441638Srgrimes
451638Srgrimes/*
461638Srgrimes * Automounter query tool
471638Srgrimes */
481638Srgrimes
491638Srgrimes#ifndef lint
501638Srgrimeschar copyright[] = "\
511638Srgrimes@(#)Copyright (c) 1997-1998 Erez Zadok\n\
521638Srgrimes@(#)Copyright (c) 1990 Jan-Simon Pendry\n\
531638Srgrimes@(#)Copyright (c) 1990 Imperial College of Science, Technology & Medicine\n\
5471101Sru@(#)Copyright (c) 1990 The Regents of the University of California.\n\
551638Srgrimes@(#)All rights reserved.\n";
561638Srgrimes#if __GNUC__ < 2
571638Srgrimesstatic char rcsid[] = "$Id: amq.c,v 6.0 1997-1998/01/01 15:09:16 ezk $";
581638Srgrimesstatic char sccsid[] = "%W% (Berkeley) %G%";
591638Srgrimes#endif /* __GNUC__ < 2 */
601638Srgrimes#endif /* not lint */
611638Srgrimes
621638Srgrimes#ifdef HAVE_CONFIG_H
631638Srgrimes# include <config.h>
64117011Sru#endif /* HAVE_CONFIG_H */
65117011Sru#include <am_defs.h>
661638Srgrimes#include <amq.h>
671638Srgrimes
681638Srgrimes/* locals */
69117011Sruchar *progname;
70117011Srustatic int flush_flag;
711638Srgrimesstatic int minfo_flag;
721638Srgrimesstatic int getpid_flag;
731638Srgrimesstatic int unmount_flag;
7471101Srustatic int stats_flag;
751638Srgrimesstatic int getvers_flag;
761638Srgrimesstatic int amd_program_number = AMQ_PROGRAM;
771638Srgrimesstatic int use_tcp_flag, use_udp_flag;
781638Srgrimesstatic char *debug_opts;
791638Srgrimesstatic char *amq_logfile;
801638Srgrimesstatic char *mount_map;
811638Srgrimesstatic char *xlog_optstr;
821638Srgrimesstatic char localhost[] = "localhost";
83117011Srustatic char *def_server = localhost;
84117011Sru
851638Srgrimes/* externals */
86117011Sruextern int optind;
87117011Sruextern char *optarg;
881638Srgrimes
891638Srgrimes/* forward decalrations */
901638Srgrimes#ifdef HAVE_TRANSPORT_TYPE_TLI
911638Srgrimesstatic CLIENT *get_secure_amd_client(char *host, struct timeval *tv, int *sock);
921638Srgrimesstatic int amq_bind_resv_port(int td, u_short *pp);
931638Srgrimes#else /* not HAVE_TRANSPORT_TYPE_TLI */
94117011Srustatic int privsock(int ty);
95117011Sru#endif /* not HAVE_TRANSPORT_TYPE_TLI */
961638Srgrimes
971638Srgrimes/* dummy variables */
981638Srgrimeschar hostname[MAXHOSTNAMELEN];
991638Srgrimesint orig_umask, foreground, debug_flags;
1001638Srgrimespid_t mypid;
1011638Srgrimesserv_state amd_state;
1021638Srgrimes
1031638Srgrimes/* structures */
1041638Srgrimesenum show_opt {
1051638Srgrimes  Full, Stats, Calc, Short, ShowDone
1061638Srgrimes};
1071638Srgrimes
1081638Srgrimes
109117011Sru/*
110117011Sru * If (e) is Calc then just calculate the sizes
1111638Srgrimes * Otherwise display the mount node on stdout
1121638Srgrimes */
113131530Srustatic void
114131530Srushow_mti(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *twid)
1151638Srgrimes{
116201115Strasz  switch (e) {
1171638Srgrimes  case Calc:
1181638Srgrimes    {
1191638Srgrimes      int mw = strlen(mt->mt_mountinfo);
1201638Srgrimes      int dw = strlen(mt->mt_directory);
121201115Strasz      int tw = strlen(mt->mt_type);
1221638Srgrimes      if (mw > *mwid)
123201115Strasz	*mwid = mw;
124201115Strasz      if (dw > *dwid)
1251638Srgrimes	*dwid = dw;
1261638Srgrimes      if (tw > *twid)
1271638Srgrimes	*twid = tw;
1281638Srgrimes    }
129201115Strasz  break;
130201115Strasz
131201115Strasz  case Full:
132201115Strasz    {
1331638Srgrimes      struct tm *tp = localtime((time_t *) &mt->mt_mounttime);
1341638Srgrimes      printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n",
1351638Srgrimes	     *dwid, *dwid,
1361638Srgrimes	     *mt->mt_directory ? mt->mt_directory : "/",	/* XXX */
1371638Srgrimes	     *twid, *twid,
1381638Srgrimes	     mt->mt_type,
1391638Srgrimes	     *mwid, *mwid,
1401638Srgrimes	     mt->mt_mountinfo,
1411638Srgrimes	     mt->mt_mountpoint,
1421638Srgrimes
1431638Srgrimes	     mt->mt_mountuid,
1441638Srgrimes	     mt->mt_getattr,
1451638Srgrimes	     mt->mt_lookup,
1461638Srgrimes	     mt->mt_readdir,
14781296Ssheldonh	     mt->mt_readlink,
14881296Ssheldonh	     mt->mt_statfs,
1491638Srgrimes
1501638Srgrimes	     tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year,
1511638Srgrimes	     tp->tm_mon + 1, tp->tm_mday,
1521638Srgrimes	     tp->tm_hour, tp->tm_min, tp->tm_sec);
1531638Srgrimes    }
1541638Srgrimes  break;
1551638Srgrimes
1561638Srgrimes  case Stats:
1571638Srgrimes    {
1581638Srgrimes      struct tm *tp = localtime((time_t *) &mt->mt_mounttime);
1591638Srgrimes      printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n",
1601638Srgrimes	     *dwid, *dwid,
1611638Srgrimes	     *mt->mt_directory ? mt->mt_directory : "/",	/* XXX */
1621638Srgrimes
1631638Srgrimes	     mt->mt_mountuid,
1641638Srgrimes	     mt->mt_getattr,
1651638Srgrimes	     mt->mt_lookup,
1661638Srgrimes	     mt->mt_readdir,
1671638Srgrimes	     mt->mt_readlink,
1681638Srgrimes	     mt->mt_statfs,
1691638Srgrimes
1701638Srgrimes	     tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year,
1711638Srgrimes	     tp->tm_mon + 1, tp->tm_mday,
1721638Srgrimes	     tp->tm_hour, tp->tm_min, tp->tm_sec);
1731638Srgrimes    }
1741638Srgrimes  break;
1751638Srgrimes
1761638Srgrimes  case Short:
1771638Srgrimes    {
1781638Srgrimes      printf("%-*.*s %-*.*s %-*.*s %s\n",
1791638Srgrimes	     *dwid, *dwid,
1801638Srgrimes	     *mt->mt_directory ? mt->mt_directory : "/",
1811638Srgrimes	     *twid, *twid,
1821638Srgrimes	     mt->mt_type,
1831638Srgrimes	     *mwid, *mwid,
1841638Srgrimes	     mt->mt_mountinfo,
1851638Srgrimes	     mt->mt_mountpoint);
1861638Srgrimes    }
1871638Srgrimes  break;
1881638Srgrimes
1891638Srgrimes  default:
1901638Srgrimes    break;
1911638Srgrimes  }
1921638Srgrimes}
1931638Srgrimes
1941638Srgrimes/*
1951638Srgrimes * Display a mount tree.
1961638Srgrimes */
1971638Srgrimesstatic void
1981638Srgrimesshow_mt(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *pwid)
1991638Srgrimes{
200117011Sru  while (mt) {
201117011Sru    show_mti(mt, e, mwid, dwid, pwid);
2021638Srgrimes    show_mt(mt->mt_next, e, mwid, dwid, pwid);
2031638Srgrimes    mt = mt->mt_child;
204117011Sru  }
205141846Sru}
2061638Srgrimes
2071638Srgrimesstatic void
2081638Srgrimesshow_mi(amq_mount_info_list *ml, enum show_opt e, int *mwid, int *dwid, int *twid)
2091638Srgrimes{
210117011Sru  int i;
211117011Sru
212141846Sru  switch (e) {
2131638Srgrimes
214117011Sru  case Calc:
215117011Sru    {
2161638Srgrimes      for (i = 0; i < ml->amq_mount_info_list_len; i++) {
2171638Srgrimes	amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
2181638Srgrimes	int mw = strlen(mi->mi_mountinfo);
2191638Srgrimes	int dw = strlen(mi->mi_mountpt);
2201638Srgrimes	int tw = strlen(mi->mi_type);
2211638Srgrimes	if (mw > *mwid)
2221638Srgrimes	  *mwid = mw;
2231638Srgrimes	if (dw > *dwid)
2241638Srgrimes	  *dwid = dw;
2251638Srgrimes	if (tw > *twid)
2261638Srgrimes	  *twid = tw;
227171065Sremko      }
2281638Srgrimes    }
2291638Srgrimes  break;
2301638Srgrimes
2311638Srgrimes  case Full:
2321638Srgrimes    {
2331638Srgrimes      for (i = 0; i < ml->amq_mount_info_list_len; i++) {
2341638Srgrimes	amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
235117011Sru	printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s",
236117011Sru	       *mwid, *mwid, mi->mi_mountinfo,
2371638Srgrimes	       *dwid, *dwid, mi->mi_mountpt,
2381638Srgrimes	       *twid, *twid, mi->mi_type,
2391638Srgrimes	       mi->mi_refc, mi->mi_fserver,
2401638Srgrimes	       mi->mi_up > 0 ? "up" :
2411638Srgrimes	       mi->mi_up < 0 ? "starting" : "down");
2421638Srgrimes	if (mi->mi_error > 0) {
2431638Srgrimes	  extern int sys_nerr;
2441638Srgrimes	  if (mi->mi_error < sys_nerr)
2451638Srgrimes	    printf(" (%s)", sys_errlist[mi->mi_error]);
2461638Srgrimes	  else
2471638Srgrimes	    printf(" (Error %d)", mi->mi_error);
248117011Sru	} else if (mi->mi_error < 0) {
249117011Sru	  fputs(" (in progress)", stdout);
250117011Sru	}
2511638Srgrimes	fputc('\n', stdout);
2521638Srgrimes      }
2531638Srgrimes    }
254117011Sru  break;
255117011Sru
2561638Srgrimes  default:
2571638Srgrimes    break;
2581638Srgrimes  }
2591638Srgrimes}
2601638Srgrimes
2611638Srgrimes
262119893Sru/*
263117011Sru * Display general mount statistics
264117011Sru */
2651638Srgrimesstatic void
266117011Srushow_ms(amq_mount_stats *ms)
267117011Sru{
2681638Srgrimes  printf("\
2691638Srgrimesrequests  stale     mount     mount     unmount\n\
2701638Srgrimesdeferred  fhandles  ok        failed    failed\n\
271131530Sru%-9d %-9d %-9d %-9d %-9d\n",
2721638Srgrimes	 ms->as_drops, ms->as_stale, ms->as_mok, ms->as_merr, ms->as_uerr);
2731638Srgrimes}
2741638Srgrimes
2751638Srgrimes
2761638Srgrimes#if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT)
2771638Srgrimesstatic char *
278117011Srucluster_server(void)
279117011Sru{
2801638Srgrimes  struct cct_entry *cp;
281117011Sru
282117011Sru  if (cnodeid() == 0) {
2831638Srgrimes    /*
2841638Srgrimes     * Not clustered
285119893Sru     */
2861638Srgrimes    return def_server;
2871638Srgrimes  }
2881638Srgrimes  while (cp = getccent())
2891638Srgrimes    if (cp->cnode_type == 'r')
2901638Srgrimes      return cp->cnode_name;
2911638Srgrimes
2921638Srgrimes  return def_server;
2931638Srgrimes}
2941638Srgrimes#endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */
2951638Srgrimes
2961638Srgrimes
2971638Srgrimes/*
2981638Srgrimes * MAIN
2991638Srgrimes */
3001638Srgrimesint
301117011Srumain(int argc, char *argv[])
302117011Sru{
3031638Srgrimes  int opt_ch;
3041638Srgrimes  int errs = 0;
3051638Srgrimes  char *server;
3061638Srgrimes  struct sockaddr_in server_addr;
307117011Sru  int s;	/* to pass the Amd security check, we must use a priv port */
308117011Sru  CLIENT *clnt = NULL;
3091638Srgrimes  struct hostent *hp;
3101638Srgrimes  int nodefault = 0;
3111638Srgrimes  struct timeval tv;
3121638Srgrimes#ifndef HAVE_TRANSPORT_TYPE_TLI
3131638Srgrimes  enum clnt_stat cs;
3141638Srgrimes#endif /* not HAVE_TRANSPORT_TYPE_TLI */
3151638Srgrimes
3161638Srgrimes
3171638Srgrimes  /*
3181638Srgrimes   * Compute program name
3191638Srgrimes   */
3201638Srgrimes  if (argv[0]) {
3211638Srgrimes    progname = strrchr(argv[0], '/');
3221638Srgrimes    if (progname && progname[1])
3231638Srgrimes      progname++;
3241638Srgrimes    else
3251638Srgrimes      progname = argv[0];
32613744Smpp  }
3271638Srgrimes  if (!progname)
3281638Srgrimes    progname = "amq";
3291638Srgrimes
3301638Srgrimes  /*
3311638Srgrimes   * Parse arguments
3321638Srgrimes   */
3331638Srgrimes  while ((opt_ch = getopt(argc, argv, "fh:l:msuvx:D:M:pP:TU")) != EOF)
3341638Srgrimes    switch (opt_ch) {
3351638Srgrimes    case 'f':
3361638Srgrimes      flush_flag = 1;
3371638Srgrimes      nodefault = 1;
3381638Srgrimes      break;
3391638Srgrimes
3401638Srgrimes    case 'h':
3411638Srgrimes      def_server = optarg;
3421638Srgrimes      break;
3431638Srgrimes
3441638Srgrimes    case 'l':
3451638Srgrimes      amq_logfile = optarg;
3461638Srgrimes      nodefault = 1;
3471638Srgrimes      break;
3481638Srgrimes
3491638Srgrimes    case 'm':
3501638Srgrimes      minfo_flag = 1;
3511638Srgrimes      nodefault = 1;
3521638Srgrimes      break;
3531638Srgrimes
3541638Srgrimes    case 'p':
35581158Ssheldonh      getpid_flag = 1;
35681158Ssheldonh      nodefault = 1;
35781158Ssheldonh      break;
35881158Ssheldonh
35981158Ssheldonh    case 's':
36081158Ssheldonh      stats_flag = 1;
36181158Ssheldonh      nodefault = 1;
36281158Ssheldonh      break;
36381158Ssheldonh
36481158Ssheldonh    case 'u':
3651638Srgrimes      unmount_flag = 1;
36620920Swosch      nodefault = 1;
3671638Srgrimes      break;
36879217Sru
3691638Srgrimes    case 'v':
37020920Swosch      getvers_flag = 1;
37120920Swosch      nodefault = 1;
372      break;
373
374    case 'x':
375      xlog_optstr = optarg;
376      nodefault = 1;
377      break;
378
379    case 'D':
380      debug_opts = optarg;
381      nodefault = 1;
382      break;
383
384    case 'M':
385      mount_map = optarg;
386      nodefault = 1;
387      break;
388
389    case 'P':
390      amd_program_number = atoi(optarg);
391      break;
392
393    case 'T':
394      use_tcp_flag = 1;
395      break;
396
397    case 'U':
398      use_udp_flag = 1;
399      break;
400
401    default:
402      errs = 1;
403      break;
404    }
405
406  if (optind == argc) {
407    if (unmount_flag)
408      errs = 1;
409  }
410  if (errs) {
411  show_usage:
412    fprintf(stderr, "\
413Usage: %s [-h host] [[-f] [-m] [-p] [-v] [-s]] | [[-u] directory ...]]\n\
414\t[-l logfile|\"syslog\"] [-x log_flags] [-D dbg_opts] [-M mapent]\n\
415\t[-P prognum] [-T] [-U]\n", progname);
416    exit(1);
417  }
418
419  /* set use_udp and use_tcp flags both to on if none are defined */
420  if (!use_tcp_flag && !use_udp_flag)
421    use_tcp_flag = use_udp_flag = 1;
422
423#if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT)
424  /*
425   * Figure out root server of cluster
426   */
427  if (def_server == localhost)
428    server = cluster_server();
429  else
430#endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */
431    server = def_server;
432
433  /*
434   * Get address of server
435   */
436  if ((hp = gethostbyname(server)) == 0 && !STREQ(server, localhost)) {
437    fprintf(stderr, "%s: Can't get address of %s\n", progname, server);
438    exit(1);
439  }
440  memset(&server_addr, 0, sizeof server_addr);
441  server_addr.sin_family = AF_INET;
442  if (hp) {
443    memmove((voidp) &server_addr.sin_addr, (voidp) hp->h_addr,
444	    sizeof(server_addr.sin_addr));
445  } else {
446    /* fake "localhost" */
447    server_addr.sin_addr.s_addr = htonl(0x7f000001);
448  }
449
450  /*
451   * Create RPC endpoint
452   */
453  tv.tv_sec = 5;		/* 5 seconds for timeout or per retry */
454  tv.tv_usec = 0;
455
456#ifdef HAVE_TRANSPORT_TYPE_TLI
457  clnt = get_secure_amd_client(server, &tv, &s);
458  if (!clnt && use_tcp_flag)	/* try tcp first */
459    clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "tcp");
460  if (!clnt && use_udp_flag) {	/* try udp next */
461    clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "udp");
462    /* if ok, set timeout (valid for connectionless transports only) */
463    if (clnt)
464      clnt_control(clnt, CLSET_RETRY_TIMEOUT, (char *) &tv);
465  }
466#else /* not HAVE_TRANSPORT_TYPE_TLI */
467
468  /* first check if remote portmapper is up */
469  cs = pmap_ping(&server_addr);
470  if (cs == RPC_TIMEDOUT) {
471    fprintf(stderr, "%s: failed to contact portmapper on host \"%s\". %s\n",
472	    progname, server, clnt_sperrno(cs));
473    exit(1);
474  }
475
476  /* portmapper exists: get remote amd info from it */
477  if (!clnt && use_tcp_flag) {	/* try tcp first */
478    s = RPC_ANYSOCK;
479    clnt = clnttcp_create(&server_addr, amd_program_number,
480			  AMQ_VERSION, &s, 0, 0);
481  }
482  if (!clnt && use_udp_flag) {	/* try udp next */
483    /* XXX: do we need to close(s) ? */
484    s = privsock(SOCK_DGRAM);
485    clnt = clntudp_create(&server_addr, amd_program_number,
486			  AMQ_VERSION, tv, &s);
487  }
488#endif /* not HAVE_TRANSPORT_TYPE_TLI */
489  if (!clnt) {
490    fprintf(stderr, "%s: ", progname);
491    clnt_pcreateerror(server);
492    exit(1);
493  }
494
495  /*
496   * Control debugging
497   */
498  if (debug_opts) {
499    int *rc;
500    amq_setopt opt;
501    opt.as_opt = AMOPT_DEBUG;
502    opt.as_str = debug_opts;
503    rc = amqproc_setopt_1(&opt, clnt);
504    if (rc && *rc < 0) {
505      fprintf(stderr, "%s: daemon not compiled for debug\n", progname);
506      errs = 1;
507    } else if (!rc || *rc > 0) {
508      fprintf(stderr, "%s: debug setting for \"%s\" failed\n", progname, debug_opts);
509      errs = 1;
510    }
511  }
512
513  /*
514   * Control logging
515   */
516  if (xlog_optstr) {
517    int *rc;
518    amq_setopt opt;
519    opt.as_opt = AMOPT_XLOG;
520    opt.as_str = xlog_optstr;
521    rc = amqproc_setopt_1(&opt, clnt);
522    if (!rc || *rc) {
523      fprintf(stderr, "%s: setting log level to \"%s\" failed\n", progname, xlog_optstr);
524      errs = 1;
525    }
526  }
527
528  /*
529   * Control log file
530   */
531  if (amq_logfile) {
532    int *rc;
533    amq_setopt opt;
534    opt.as_opt = AMOPT_LOGFILE;
535    opt.as_str = amq_logfile;
536    rc = amqproc_setopt_1(&opt, clnt);
537    if (!rc || *rc) {
538      fprintf(stderr, "%s: setting logfile to \"%s\" failed\n", progname, amq_logfile);
539      errs = 1;
540    }
541  }
542
543  /*
544   * Flush map cache
545   */
546  if (flush_flag) {
547    int *rc;
548    amq_setopt opt;
549    opt.as_opt = AMOPT_FLUSHMAPC;
550    opt.as_str = "";
551    rc = amqproc_setopt_1(&opt, clnt);
552    if (!rc || *rc) {
553      fprintf(stderr, "%s: amd on %s cannot flush the map cache\n", progname, server);
554      errs = 1;
555    }
556  }
557
558  /*
559   * Mount info
560   */
561  if (minfo_flag) {
562    int dummy;
563    amq_mount_info_list *ml = amqproc_getmntfs_1(&dummy, clnt);
564    if (ml) {
565      int mwid = 0, dwid = 0, twid = 0;
566      show_mi(ml, Calc, &mwid, &dwid, &twid);
567      mwid++;
568      dwid++;
569      twid++;
570      show_mi(ml, Full, &mwid, &dwid, &twid);
571
572    } else {
573      fprintf(stderr, "%s: amd on %s cannot provide mount info\n", progname, server);
574    }
575  }
576
577  /*
578   * Mount map
579   */
580  if (mount_map) {
581    int *rc;
582    do {
583      rc = amqproc_mount_1(&mount_map, clnt);
584    } while (rc && *rc < 0);
585    if (!rc || *rc > 0) {
586      if (rc)
587	errno = *rc;
588      else
589	errno = ETIMEDOUT;
590      fprintf(stderr, "%s: could not start new ", progname);
591      perror("autmount point");
592    }
593  }
594
595  /*
596   * Get Version
597   */
598  if (getvers_flag) {
599    amq_string *spp = amqproc_getvers_1((voidp) 0, clnt);
600    if (spp && *spp) {
601      fputs(*spp, stdout);
602      XFREE(*spp);
603    } else {
604      fprintf(stderr, "%s: failed to get version information\n", progname);
605      errs = 1;
606    }
607  }
608
609  /*
610   * Get PID of amd
611   */
612  if (getpid_flag) {
613    int *ip = amqproc_getpid_1((voidp) 0, clnt);
614    if (ip && *ip) {
615      printf("%d\n", *ip);
616    } else {
617      fprintf(stderr, "%s: failed to get PID of amd\n", progname);
618      errs = 1;
619    }
620  }
621
622  /*
623   * Apply required operation to all remaining arguments
624   */
625  if (optind < argc) {
626    do {
627      char *fs = argv[optind++];
628      if (unmount_flag) {
629	/*
630	 * Unmount request
631	 */
632	amqproc_umnt_1(&fs, clnt);
633      } else {
634	/*
635	 * Stats request
636	 */
637	amq_mount_tree_p *mtp = amqproc_mnttree_1(&fs, clnt);
638	if (mtp) {
639	  amq_mount_tree *mt = *mtp;
640	  if (mt) {
641	    int mwid = 0, dwid = 0, twid = 0;
642	    show_mt(mt, Calc, &mwid, &dwid, &twid);
643	    mwid++;
644	    dwid++, twid++;
645	    printf("%-*.*s Uid   Getattr Lookup RdDir   RdLnk   Statfs Mounted@\n",
646		   dwid, dwid, "What");
647	    show_mt(mt, Stats, &mwid, &dwid, &twid);
648	  } else {
649	    fprintf(stderr, "%s: %s not automounted\n", progname, fs);
650	  }
651	  xdr_pri_free((XDRPROC_T_TYPE) xdr_amq_mount_tree_p, (caddr_t) mtp);
652	} else {
653	  fprintf(stderr, "%s: ", progname);
654	  clnt_perror(clnt, server);
655	  errs = 1;
656	}
657      }
658    } while (optind < argc);
659
660  } else if (unmount_flag) {
661    goto show_usage;
662
663  } else if (stats_flag) {
664    amq_mount_stats *ms = amqproc_stats_1((voidp) 0, clnt);
665    if (ms) {
666      show_ms(ms);
667    } else {
668      fprintf(stderr, "%s: ", progname);
669      clnt_perror(clnt, server);
670      errs = 1;
671    }
672
673  } else if (!nodefault) {
674    amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt);
675    if (mlp) {
676      enum show_opt e = Calc;
677      int mwid = 0, dwid = 0, pwid = 0;
678      while (e != ShowDone) {
679	int i;
680	for (i = 0; i < mlp->amq_mount_tree_list_len; i++) {
681	  show_mt(mlp->amq_mount_tree_list_val[i],
682		  e, &mwid, &dwid, &pwid);
683	}
684	mwid++;
685	dwid++, pwid++;
686	if (e == Calc)
687	  e = Short;
688	else if (e == Short)
689	  e = ShowDone;
690      }
691
692    } else {
693      fprintf(stderr, "%s: ", progname);
694      clnt_perror(clnt, server);
695      errs = 1;
696    }
697  }
698  exit(errs);
699  return errs; /* should never reache here */
700}
701
702
703#ifdef HAVE_TRANSPORT_TYPE_TLI
704
705/*
706 * How to bind to reserved ports.
707 * TLI handle (socket) and port version.
708 */
709/* defined here so that it does not have to resolve it with libamu.a */
710static int
711amq_bind_resv_port(int td, u_short *pp)
712{
713  int rc = -1, port;
714  struct t_bind *treq, *tret;
715  struct sockaddr_in *sin;
716
717  treq = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR);
718  if (!treq) {
719    plog(XLOG_ERROR, "t_alloc 1");
720    return -1;
721  }
722  tret = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR);
723  if (!tret) {
724    t_free((char *) treq, T_BIND);
725    plog(XLOG_ERROR, "t_alloc 2");
726    return -1;
727  }
728  memset((char *) treq->addr.buf, 0, treq->addr.len);
729  sin = (struct sockaddr_in *) treq->addr.buf;
730  sin->sin_family = AF_INET;
731  treq->qlen = 0;
732  treq->addr.len = treq->addr.maxlen;
733  errno = EADDRINUSE;
734  port = IPPORT_RESERVED;
735
736  do {
737    --port;
738    sin->sin_port = htons(port);
739    rc = t_bind(td, treq, tret);
740    if (rc < 0) {
741    } else {
742      if (memcmp(treq->addr.buf, tret->addr.buf, tret->addr.len) == 0)
743	break;
744      else
745	t_unbind(td);
746    }
747  } while ((rc < 0 || errno == EADDRINUSE) && (int) port > IPPORT_RESERVED / 2);
748
749  if (pp) {
750    if (rc == 0)
751      *pp = port;
752    else
753      plog(XLOG_ERROR, "could not t_bind to any reserved port");
754  }
755  t_free((char *) tret, T_BIND);
756  t_free((char *) treq, T_BIND);
757  return rc;
758}
759
760
761/*
762 * Create a secure rpc client attached to the amd daemon.
763 */
764static CLIENT *
765get_secure_amd_client(char *host, struct timeval *tv, int *sock)
766{
767  CLIENT *client;
768  struct netbuf nb;
769  struct netconfig *nc, *pm_nc;
770  struct sockaddr_in sin;
771
772
773  nb.maxlen = sizeof(sin);
774  nb.buf = (char *) &sin;
775
776  /*
777   * Ensure that remote portmapper is alive
778   * (must use connectionless netconfig).
779   */
780  if ((pm_nc = getnetconfigent(NC_UDP)) != NULL) {
781    enum clnt_stat cs;
782
783    cs = rpcb_rmtcall(pm_nc,
784		      host,
785		      amd_program_number,
786		      AMQ_VERSION,
787		      AMQPROC_NULL,
788		      (XDRPROC_T_TYPE) xdr_void,
789		      NULL,
790		      (XDRPROC_T_TYPE) xdr_void,
791		      NULL,
792		      *tv,
793		      NULL);
794    if (cs == RPC_TIMEDOUT) {
795      fprintf(stderr, "%s: failed to contact portmapper on host \"%s\". %s\n",
796	      progname, host, clnt_sperrno(cs));
797      exit(1);
798    }
799  }
800
801  /*
802   * First transport type to try: TCP
803   */
804  if (use_tcp_flag) {
805    /* Find amd address on TCP */
806    nc = getnetconfigent(NC_TCP);
807    if (!nc) {
808      fprintf(stderr, "getnetconfig for tcp failed: %s\n", nc_sperror());
809      goto tryudp;
810    }
811
812    if (!rpcb_getaddr(amd_program_number, AMQ_VERSION, nc, &nb, host)) {
813      /*
814       * don't pring error messages here, since amd might legitimately
815       * serve udp only
816       */
817      goto tryudp;
818    }
819    /* Create priviledged TCP socket */
820    *sock = t_open(nc->nc_device, O_RDWR, 0);
821
822    if (*sock < 0) {
823      fprintf(stderr, "t_open %s: %m\n", nc->nc_device);
824      goto tryudp;
825    }
826    if (amq_bind_resv_port(*sock, (u_short *) 0) < 0)
827      goto tryudp;
828
829    client = clnt_vc_create(*sock, &nb, amd_program_number, AMQ_VERSION, 0, 0);
830    if (!client) {
831      fprintf(stderr, "clnt_vc_create failed");
832      t_close(*sock);
833      goto tryudp;
834    }
835    /* tcp succeeded */
836    return client;
837  }
838
839tryudp:
840  /*
841   * TCP failed so try UDP
842   */
843  if (use_udp_flag) {
844    /* find amd address on UDP */
845    nc = getnetconfigent(NC_UDP);
846    if (!nc) {
847      fprintf(stderr, "getnetconfig for udp failed: %s\n", nc_sperror());
848      return NULL;
849    }
850    if (!rpcb_getaddr(amd_program_number, AMQ_VERSION, nc, &nb, host)) {
851      fprintf(stderr, "%s\n",
852	      clnt_spcreateerror("couldn't get amd address on udp"));
853      return NULL;
854    }
855    /* create priviledged UDP socket */
856    *sock = t_open(nc->nc_device, O_RDWR, 0);
857
858    if (*sock < 0) {
859      fprintf(stderr, "t_open %s: %m\n", nc->nc_device);
860      return NULL;		/* neither tcp not udp succeeded */
861    }
862    if (amq_bind_resv_port(*sock, (u_short *) 0) < 0)
863      return NULL;
864
865    client = clnt_dg_create(*sock, &nb, amd_program_number, AMQ_VERSION, 0, 0);
866    if (!client) {
867      fprintf(stderr, "clnt_dg_create failed\n");
868      t_close(*sock);
869      return NULL;		/* neither tcp not udp succeeded */
870    }
871    if (clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) tv) == FALSE) {
872      fprintf(stderr, "clnt_control CLSET_RETRY_TIMEOUT for udp failed\n");
873      clnt_destroy(client);
874      return NULL;		/* neither tcp not udp succeeded */
875    }
876    /* udp succeeded */
877    return client;
878  }
879
880  /* should never get here */
881  return NULL;
882}
883
884#else /* not HAVE_TRANSPORT_TYPE_TLI */
885
886/*
887 * inetresport creates a datagram socket and attempts to bind it to a
888 * secure port.
889 * returns: The bound socket, or -1 to indicate an error.
890 */
891static int
892inetresport(int ty)
893{
894  int alport;
895  struct sockaddr_in addr;
896  int fd;
897
898  /* Use internet address family */
899  addr.sin_family = AF_INET;
900  addr.sin_addr.s_addr = INADDR_ANY;
901  if ((fd = socket(AF_INET, ty, 0)) < 0)
902    return -1;
903
904  for (alport = IPPORT_RESERVED - 1; alport > IPPORT_RESERVED / 2 + 1; alport--) {
905    addr.sin_port = htons((u_short) alport);
906    if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) >= 0)
907      return fd;
908    if (errno != EADDRINUSE) {
909      close(fd);
910      return -1;
911    }
912  }
913  close(fd);
914  errno = EAGAIN;
915  return -1;
916}
917
918
919/*
920 * Privsock() calls inetresport() to attempt to bind a socket to a secure
921 * port.  If inetresport() fails, privsock returns a magic socket number which
922 * indicates to RPC that it should make its own socket.
923 * returns: A privileged socket # or RPC_ANYSOCK.
924 */
925static int
926privsock(int ty)
927{
928  int sock = inetresport(ty);
929
930  if (sock < 0) {
931    errno = 0;
932    /* Couldn't get a secure port, let RPC make an insecure one */
933    sock = RPC_ANYSOCK;
934  }
935  return sock;
936}
937
938#endif /* not HAVE_TRANSPORT_TYPE_TLI */
939