amq.c revision 38495
1/*
2 * Copyright (c) 1997-1998 Erez Zadok
3 * Copyright (c) 1990 Jan-Simon Pendry
4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1990 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgement:
21 *      This product includes software developed by the University of
22 *      California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 *    may be used to endorse or promote products derived from this software
25 *    without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
38 *
39 *      %W% (Berkeley) %G%
40 *
41 * $Id: amq.c,v 5.2.2.1 1992/02/09 15:09:16 jsp beta $
42 *
43 */
44
45/*
46 * Automounter query tool
47 */
48
49#ifndef lint
50char copyright[] = "\
51@(#)Copyright (c) 1997-1998 Erez Zadok\n\
52@(#)Copyright (c) 1990 Jan-Simon Pendry\n\
53@(#)Copyright (c) 1990 Imperial College of Science, Technology & Medicine\n\
54@(#)Copyright (c) 1990 The Regents of the University of California.\n\
55@(#)All rights reserved.\n";
56#if __GNUC__ < 2
57static char rcsid[] = "$Id: amq.c,v 6.0 1997-1998/01/01 15:09:16 ezk $";
58static char sccsid[] = "%W% (Berkeley) %G%";
59#endif /* __GNUC__ < 2 */
60#endif /* not lint */
61
62#ifdef HAVE_CONFIG_H
63# include <config.h>
64#endif /* HAVE_CONFIG_H */
65#include <am_defs.h>
66#include <amq.h>
67
68/* locals */
69char *progname;
70static int flush_flag;
71static int minfo_flag;
72static int getpid_flag;
73static int unmount_flag;
74static int stats_flag;
75static int getvers_flag;
76static int amd_program_number = AMQ_PROGRAM;
77static int use_tcp_flag, use_udp_flag;
78static char *debug_opts;
79static char *amq_logfile;
80static char *mount_map;
81static char *xlog_optstr;
82static char localhost[] = "localhost";
83static char *def_server = localhost;
84
85/* externals */
86extern int optind;
87extern char *optarg;
88
89/* forward decalrations */
90#ifdef HAVE_TRANSPORT_TYPE_TLI
91static CLIENT *get_secure_amd_client(char *host, struct timeval *tv, int *sock);
92static int amq_bind_resv_port(int td, u_short *pp);
93#else /* not HAVE_TRANSPORT_TYPE_TLI */
94static int privsock(int ty);
95#endif /* not HAVE_TRANSPORT_TYPE_TLI */
96
97/* dummy variables */
98char hostname[MAXHOSTNAMELEN];
99int orig_umask, foreground, debug_flags;
100pid_t mypid;
101serv_state amd_state;
102
103/* structures */
104enum show_opt {
105  Full, Stats, Calc, Short, ShowDone
106};
107
108
109/*
110 * If (e) is Calc then just calculate the sizes
111 * Otherwise display the mount node on stdout
112 */
113static void
114show_mti(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *twid)
115{
116  switch (e) {
117  case Calc:
118    {
119      int mw = strlen(mt->mt_mountinfo);
120      int dw = strlen(mt->mt_directory);
121      int tw = strlen(mt->mt_type);
122      if (mw > *mwid)
123	*mwid = mw;
124      if (dw > *dwid)
125	*dwid = dw;
126      if (tw > *twid)
127	*twid = tw;
128    }
129  break;
130
131  case Full:
132    {
133      struct tm *tp = localtime((time_t *) &mt->mt_mounttime);
134      printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n",
135	     *dwid, *dwid,
136	     *mt->mt_directory ? mt->mt_directory : "/",	/* XXX */
137	     *twid, *twid,
138	     mt->mt_type,
139	     *mwid, *mwid,
140	     mt->mt_mountinfo,
141	     mt->mt_mountpoint,
142
143	     mt->mt_mountuid,
144	     mt->mt_getattr,
145	     mt->mt_lookup,
146	     mt->mt_readdir,
147	     mt->mt_readlink,
148	     mt->mt_statfs,
149
150	     tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year,
151	     tp->tm_mon + 1, tp->tm_mday,
152	     tp->tm_hour, tp->tm_min, tp->tm_sec);
153    }
154  break;
155
156  case Stats:
157    {
158      struct tm *tp = localtime((time_t *) &mt->mt_mounttime);
159      printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n",
160	     *dwid, *dwid,
161	     *mt->mt_directory ? mt->mt_directory : "/",	/* XXX */
162
163	     mt->mt_mountuid,
164	     mt->mt_getattr,
165	     mt->mt_lookup,
166	     mt->mt_readdir,
167	     mt->mt_readlink,
168	     mt->mt_statfs,
169
170	     tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year,
171	     tp->tm_mon + 1, tp->tm_mday,
172	     tp->tm_hour, tp->tm_min, tp->tm_sec);
173    }
174  break;
175
176  case Short:
177    {
178      printf("%-*.*s %-*.*s %-*.*s %s\n",
179	     *dwid, *dwid,
180	     *mt->mt_directory ? mt->mt_directory : "/",
181	     *twid, *twid,
182	     mt->mt_type,
183	     *mwid, *mwid,
184	     mt->mt_mountinfo,
185	     mt->mt_mountpoint);
186    }
187  break;
188
189  default:
190    break;
191  }
192}
193
194/*
195 * Display a mount tree.
196 */
197static void
198show_mt(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *pwid)
199{
200  while (mt) {
201    show_mti(mt, e, mwid, dwid, pwid);
202    show_mt(mt->mt_next, e, mwid, dwid, pwid);
203    mt = mt->mt_child;
204  }
205}
206
207static void
208show_mi(amq_mount_info_list *ml, enum show_opt e, int *mwid, int *dwid, int *twid)
209{
210  int i;
211
212  switch (e) {
213
214  case Calc:
215    {
216      for (i = 0; i < ml->amq_mount_info_list_len; i++) {
217	amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
218	int mw = strlen(mi->mi_mountinfo);
219	int dw = strlen(mi->mi_mountpt);
220	int tw = strlen(mi->mi_type);
221	if (mw > *mwid)
222	  *mwid = mw;
223	if (dw > *dwid)
224	  *dwid = dw;
225	if (tw > *twid)
226	  *twid = tw;
227      }
228    }
229  break;
230
231  case Full:
232    {
233      for (i = 0; i < ml->amq_mount_info_list_len; i++) {
234	amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
235	printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s",
236	       *mwid, *mwid, mi->mi_mountinfo,
237	       *dwid, *dwid, mi->mi_mountpt,
238	       *twid, *twid, mi->mi_type,
239	       mi->mi_refc, mi->mi_fserver,
240	       mi->mi_up > 0 ? "up" :
241	       mi->mi_up < 0 ? "starting" : "down");
242	if (mi->mi_error > 0) {
243	  extern int sys_nerr;
244	  if (mi->mi_error < sys_nerr)
245	    printf(" (%s)", sys_errlist[mi->mi_error]);
246	  else
247	    printf(" (Error %d)", mi->mi_error);
248	} else if (mi->mi_error < 0) {
249	  fputs(" (in progress)", stdout);
250	}
251	fputc('\n', stdout);
252      }
253    }
254  break;
255
256  default:
257    break;
258  }
259}
260
261
262/*
263 * Display general mount statistics
264 */
265static void
266show_ms(amq_mount_stats *ms)
267{
268  printf("\
269requests  stale     mount     mount     unmount\n\
270deferred  fhandles  ok        failed    failed\n\
271%-9d %-9d %-9d %-9d %-9d\n",
272	 ms->as_drops, ms->as_stale, ms->as_mok, ms->as_merr, ms->as_uerr);
273}
274
275
276#if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT)
277static char *
278cluster_server(void)
279{
280  struct cct_entry *cp;
281
282  if (cnodeid() == 0) {
283    /*
284     * Not clustered
285     */
286    return def_server;
287  }
288  while (cp = getccent())
289    if (cp->cnode_type == 'r')
290      return cp->cnode_name;
291
292  return def_server;
293}
294#endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */
295
296
297/*
298 * MAIN
299 */
300int
301main(int argc, char *argv[])
302{
303  int opt_ch;
304  int errs = 0;
305  char *server;
306  struct sockaddr_in server_addr;
307  int s;	/* to pass the Amd security check, we must use a priv port */
308  CLIENT *clnt = NULL;
309  struct hostent *hp;
310  int nodefault = 0;
311  struct timeval tv;
312#ifndef HAVE_TRANSPORT_TYPE_TLI
313  enum clnt_stat cs;
314#endif /* not HAVE_TRANSPORT_TYPE_TLI */
315
316
317  /*
318   * Compute program name
319   */
320  if (argv[0]) {
321    progname = strrchr(argv[0], '/');
322    if (progname && progname[1])
323      progname++;
324    else
325      progname = argv[0];
326  }
327  if (!progname)
328    progname = "amq";
329
330  /*
331   * Parse arguments
332   */
333  while ((opt_ch = getopt(argc, argv, "fh:l:msuvx:D:M:pP:TU")) != EOF)
334    switch (opt_ch) {
335    case 'f':
336      flush_flag = 1;
337      nodefault = 1;
338      break;
339
340    case 'h':
341      def_server = optarg;
342      break;
343
344    case 'l':
345      amq_logfile = optarg;
346      nodefault = 1;
347      break;
348
349    case 'm':
350      minfo_flag = 1;
351      nodefault = 1;
352      break;
353
354    case 'p':
355      getpid_flag = 1;
356      nodefault = 1;
357      break;
358
359    case 's':
360      stats_flag = 1;
361      nodefault = 1;
362      break;
363
364    case 'u':
365      unmount_flag = 1;
366      nodefault = 1;
367      break;
368
369    case 'v':
370      getvers_flag = 1;
371      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