AMD64 - Fix many compile-time warnings. int/ptr type mismatches, %llx, etc.
[dragonfly.git] / contrib / amd / amq / amq.c
blob4d90a93c5066393647d7a3a90fc0a9b9ab4cbfec
1 /*
2 * Copyright (c) 1997-1999 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.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
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 acknowledgment:
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.
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.
39 * %W% (Berkeley) %G%
41 * $Id: amq.c,v 1.6 1999/09/08 23:36:40 ezk Exp $
42 * $FreeBSD: src/contrib/amd/amq/amq.c,v 1.5 1999/09/15 05:45:14 obrien Exp $
43 * $DragonFly: src/contrib/amd/amq/amq.c,v 1.3 2004/01/23 19:49:35 joerg Exp $
48 * Automounter query tool
51 #ifndef lint
52 char copyright[] = "\
53 @(#)Copyright (c) 1997-1999 Erez Zadok\n\
54 @(#)Copyright (c) 1990 Jan-Simon Pendry\n\
55 @(#)Copyright (c) 1990 Imperial College of Science, Technology & Medicine\n\
56 @(#)Copyright (c) 1990 The Regents of the University of California.\n\
57 @(#)All rights reserved.\n";
58 #if __GNUC__ < 2
59 static char rcsid[] = "$Id: amq.c,v 1.6 1999/09/08 23:36:40 ezk Exp $";
60 static char sccsid[] = "%W% (Berkeley) %G%";
61 #endif /* __GNUC__ < 2 */
62 #endif /* not lint */
64 #ifdef HAVE_CONFIG_H
65 # include <config.h>
66 #endif /* HAVE_CONFIG_H */
67 #include <am_defs.h>
68 #include <amq.h>
70 /* locals */
71 static int flush_flag;
72 static int minfo_flag;
73 static int getpid_flag;
74 static int unmount_flag;
75 static int stats_flag;
76 static int getvers_flag;
77 static int amd_program_number = AMQ_PROGRAM;
78 static int use_tcp_flag, use_udp_flag;
79 static char *debug_opts;
80 static char *amq_logfile;
81 static char *mount_map;
82 static char *xlog_optstr;
83 static char localhost[] = "localhost";
84 static char *def_server = localhost;
86 /* externals */
87 extern int optind;
88 extern char *optarg;
90 /* forward declarations */
91 #ifdef HAVE_TRANSPORT_TYPE_TLI
92 static CLIENT *get_secure_amd_client(char *host, struct timeval *tv, int *sock);
93 static int amq_bind_resv_port(int td, u_short *pp);
94 #else /* not HAVE_TRANSPORT_TYPE_TLI */
95 static int privsock(int ty);
96 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
98 /* structures */
99 enum show_opt {
100 Full, Stats, Calc, Short, ShowDone
105 * If (e) is Calc then just calculate the sizes
106 * Otherwise display the mount node on stdout
108 static void
109 show_mti(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *twid)
111 switch (e) {
112 case Calc:
114 int mw = strlen(mt->mt_mountinfo);
115 int dw = strlen(mt->mt_directory);
116 int tw = strlen(mt->mt_type);
117 if (mw > *mwid)
118 *mwid = mw;
119 if (dw > *dwid)
120 *dwid = dw;
121 if (tw > *twid)
122 *twid = tw;
124 break;
126 case Full:
128 struct tm *tp = localtime((time_t *) &mt->mt_mounttime);
129 printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n",
130 *dwid, *dwid,
131 *mt->mt_directory ? mt->mt_directory : "/", /* XXX */
132 *twid, *twid,
133 mt->mt_type,
134 *mwid, *mwid,
135 mt->mt_mountinfo,
136 mt->mt_mountpoint,
138 mt->mt_mountuid,
139 mt->mt_getattr,
140 mt->mt_lookup,
141 mt->mt_readdir,
142 mt->mt_readlink,
143 mt->mt_statfs,
145 tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year,
146 tp->tm_mon + 1, tp->tm_mday,
147 tp->tm_hour, tp->tm_min, tp->tm_sec);
149 break;
151 case Stats:
153 struct tm *tp = localtime((time_t *) &mt->mt_mounttime);
154 printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%02d\n",
155 *dwid, *dwid,
156 *mt->mt_directory ? mt->mt_directory : "/", /* XXX */
158 mt->mt_mountuid,
159 mt->mt_getattr,
160 mt->mt_lookup,
161 mt->mt_readdir,
162 mt->mt_readlink,
163 mt->mt_statfs,
165 tp->tm_year > 99 ? tp->tm_year - 100 : tp->tm_year,
166 tp->tm_mon + 1, tp->tm_mday,
167 tp->tm_hour, tp->tm_min, tp->tm_sec);
169 break;
171 case Short:
173 printf("%-*.*s %-*.*s %-*.*s %s\n",
174 *dwid, *dwid,
175 *mt->mt_directory ? mt->mt_directory : "/",
176 *twid, *twid,
177 mt->mt_type,
178 *mwid, *mwid,
179 mt->mt_mountinfo,
180 mt->mt_mountpoint);
182 break;
184 default:
185 break;
190 * Display a mount tree.
192 static void
193 show_mt(amq_mount_tree *mt, enum show_opt e, int *mwid, int *dwid, int *pwid)
195 while (mt) {
196 show_mti(mt, e, mwid, dwid, pwid);
197 show_mt(mt->mt_next, e, mwid, dwid, pwid);
198 mt = mt->mt_child;
202 static void
203 show_mi(amq_mount_info_list *ml, enum show_opt e, int *mwid, int *dwid, int *twid)
205 int i;
207 switch (e) {
209 case Calc:
211 for (i = 0; i < ml->amq_mount_info_list_len; i++) {
212 amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
213 int mw = strlen(mi->mi_mountinfo);
214 int dw = strlen(mi->mi_mountpt);
215 int tw = strlen(mi->mi_type);
216 if (mw > *mwid)
217 *mwid = mw;
218 if (dw > *dwid)
219 *dwid = dw;
220 if (tw > *twid)
221 *twid = tw;
224 break;
226 case Full:
228 for (i = 0; i < ml->amq_mount_info_list_len; i++) {
229 amq_mount_info *mi = &ml->amq_mount_info_list_val[i];
230 printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s",
231 *mwid, *mwid, mi->mi_mountinfo,
232 *dwid, *dwid, mi->mi_mountpt,
233 *twid, *twid, mi->mi_type,
234 mi->mi_refc, mi->mi_fserver,
235 mi->mi_up > 0 ? "up" :
236 mi->mi_up < 0 ? "starting" : "down");
237 if (mi->mi_error > 0) {
238 if (mi->mi_error < sys_nerr)
239 #ifdef HAVE_STRERROR
240 printf(" (%s)", strerror(mi->mi_error));
241 #else /* not HAVE_STRERROR */
242 printf(" (%s)", sys_errlist[mi->mi_error]);
243 #endif /* not HAVE_STRERROR */
244 else
245 printf(" (Error %d)", mi->mi_error);
246 } else if (mi->mi_error < 0) {
247 fputs(" (in progress)", stdout);
249 fputc('\n', stdout);
252 break;
254 default:
255 break;
261 * Display general mount statistics
263 static void
264 show_ms(amq_mount_stats *ms)
266 printf("\
267 requests stale mount mount unmount\n\
268 deferred fhandles ok failed failed\n\
269 %-9d %-9d %-9d %-9d %-9d\n",
270 ms->as_drops, ms->as_stale, ms->as_mok, ms->as_merr, ms->as_uerr);
274 #if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT)
275 static char *
276 cluster_server(void)
278 struct cct_entry *cp;
280 if (cnodeid() == 0) {
282 * Not clustered
284 return def_server;
286 while (cp = getccent())
287 if (cp->cnode_type == 'r')
288 return cp->cnode_name;
290 return def_server;
292 #endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */
296 * MAIN
299 main(int argc, char *argv[])
301 int opt_ch;
302 int errs = 0;
303 char *server;
304 struct sockaddr_in server_addr;
305 int s; /* to pass the Amd security check, we must use a priv port */
306 CLIENT *clnt = NULL;
307 struct hostent *hp;
308 int nodefault = 0;
309 struct timeval tv;
310 char *progname = NULL;
311 #ifndef HAVE_TRANSPORT_TYPE_TLI
312 enum clnt_stat cs;
313 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
317 * Compute program name
319 if (argv[0]) {
320 progname = strrchr(argv[0], '/');
321 if (progname && progname[1])
322 progname++;
323 else
324 progname = argv[0];
326 if (!progname)
327 progname = "amq";
328 am_set_progname(progname);
331 * Parse arguments
333 #ifdef ENABLE_AMQ_MOUNT
334 while ((opt_ch = getopt(argc, argv, "fh:l:msuvx:D:M:pP:TU")) != -1)
335 #else /* not ENABLE_AMQ_MOUNT */
336 while ((opt_ch = getopt(argc, argv, "fh:l:msuvx:D:pP:TU")) != -1)
337 #endif /* not ENABLE_AMQ_MOUNT */
338 switch (opt_ch) {
339 case 'f':
340 flush_flag = 1;
341 nodefault = 1;
342 break;
344 case 'h':
345 def_server = optarg;
346 break;
348 case 'l':
349 amq_logfile = optarg;
350 nodefault = 1;
351 break;
353 case 'm':
354 minfo_flag = 1;
355 nodefault = 1;
356 break;
358 case 'p':
359 getpid_flag = 1;
360 nodefault = 1;
361 break;
363 case 's':
364 stats_flag = 1;
365 nodefault = 1;
366 break;
368 case 'u':
369 unmount_flag = 1;
370 nodefault = 1;
371 break;
373 case 'v':
374 getvers_flag = 1;
375 nodefault = 1;
376 break;
378 case 'x':
379 xlog_optstr = optarg;
380 nodefault = 1;
381 break;
383 case 'D':
384 debug_opts = optarg;
385 nodefault = 1;
386 break;
388 #ifdef ENABLE_AMQ_MOUNT
389 case 'M':
390 mount_map = optarg;
391 nodefault = 1;
392 break;
393 #endif /* ENABLE_AMQ_MOUNT */
395 case 'P':
396 amd_program_number = atoi(optarg);
397 break;
399 case 'T':
400 use_tcp_flag = 1;
401 break;
403 case 'U':
404 use_udp_flag = 1;
405 break;
407 default:
408 errs = 1;
409 break;
412 if (optind == argc) {
413 if (unmount_flag)
414 errs = 1;
416 if (errs) {
417 show_usage:
418 fprintf(stderr, "\
419 Usage: %s [-h host] [[-f] [-m] [-p] [-v] [-s]] | [[-u] directory ...]]\n\
420 \t[-l logfile|\"syslog\"] [-x log_flags] [-D dbg_opts]%s\n\
421 \t[-P prognum] [-T] [-U]\n",
422 am_get_progname(),
423 #ifdef ENABLE_AMQ_MOUNT
424 " [-M mapent]"
425 #else /* not ENABLE_AMQ_MOUNT */
427 #endif /* not ENABLE_AMQ_MOUNT */
429 exit(1);
434 /* set use_udp and use_tcp flags both to on if none are defined */
435 if (!use_tcp_flag && !use_udp_flag)
436 use_tcp_flag = use_udp_flag = 1;
438 #if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT)
440 * Figure out root server of cluster
442 if (def_server == localhost)
443 server = cluster_server();
444 else
445 #endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */
446 server = def_server;
449 * Get address of server
451 if ((hp = gethostbyname(server)) == 0 && !STREQ(server, localhost)) {
452 fprintf(stderr, "%s: Can't get address of %s\n",
453 am_get_progname(), server);
454 exit(1);
456 memset(&server_addr, 0, sizeof server_addr);
457 server_addr.sin_family = AF_INET;
458 if (hp) {
459 memmove((voidp) &server_addr.sin_addr, (voidp) hp->h_addr,
460 sizeof(server_addr.sin_addr));
461 } else {
462 /* fake "localhost" */
463 server_addr.sin_addr.s_addr = htonl(0x7f000001);
467 * Create RPC endpoint
469 tv.tv_sec = 5; /* 5 seconds for timeout or per retry */
470 tv.tv_usec = 0;
472 #ifdef HAVE_TRANSPORT_TYPE_TLI
473 clnt = get_secure_amd_client(server, &tv, &s);
474 if (!clnt && use_tcp_flag) /* try tcp first */
475 clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "tcp");
476 if (!clnt && use_udp_flag) { /* try udp next */
477 clnt = clnt_create(server, amd_program_number, AMQ_VERSION, "udp");
478 /* if ok, set timeout (valid for connectionless transports only) */
479 if (clnt)
480 clnt_control(clnt, CLSET_RETRY_TIMEOUT, (char *) &tv);
482 #else /* not HAVE_TRANSPORT_TYPE_TLI */
484 /* first check if remote portmapper is up */
485 cs = pmap_ping(&server_addr);
486 if (cs == RPC_TIMEDOUT) {
487 fprintf(stderr, "%s: failed to contact portmapper on host \"%s\". %s\n",
488 am_get_progname(), server, clnt_sperrno(cs));
489 exit(1);
492 /* portmapper exists: get remote amd info from it */
493 if (!clnt && use_tcp_flag) { /* try tcp first */
494 s = RPC_ANYSOCK;
495 clnt = clnttcp_create(&server_addr, amd_program_number,
496 AMQ_VERSION, &s, 0, 0);
498 if (!clnt && use_udp_flag) { /* try udp next */
499 /* XXX: do we need to close(s) ? */
500 s = privsock(SOCK_DGRAM);
501 clnt = clntudp_create(&server_addr, amd_program_number,
502 AMQ_VERSION, tv, &s);
504 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
505 if (!clnt) {
506 fprintf(stderr, "%s: ", am_get_progname());
507 clnt_pcreateerror(server);
508 exit(1);
512 * Control debugging
514 if (debug_opts) {
515 int *rc;
516 amq_setopt opt;
517 opt.as_opt = AMOPT_DEBUG;
518 opt.as_str = debug_opts;
519 rc = amqproc_setopt_1(&opt, clnt);
520 if (rc && *rc < 0) {
521 fprintf(stderr, "%s: daemon not compiled for debug\n",
522 am_get_progname());
523 errs = 1;
524 } else if (!rc || *rc > 0) {
525 fprintf(stderr, "%s: debug setting for \"%s\" failed\n",
526 am_get_progname(), debug_opts);
527 errs = 1;
532 * Control logging
534 if (xlog_optstr) {
535 int *rc;
536 amq_setopt opt;
537 opt.as_opt = AMOPT_XLOG;
538 opt.as_str = xlog_optstr;
539 rc = amqproc_setopt_1(&opt, clnt);
540 if (!rc || *rc) {
541 fprintf(stderr, "%s: setting log level to \"%s\" failed\n",
542 am_get_progname(), xlog_optstr);
543 errs = 1;
548 * Control log file
550 if (amq_logfile) {
551 int *rc;
552 amq_setopt opt;
553 opt.as_opt = AMOPT_LOGFILE;
554 opt.as_str = amq_logfile;
555 rc = amqproc_setopt_1(&opt, clnt);
556 if (!rc || *rc) {
557 fprintf(stderr, "%s: setting logfile to \"%s\" failed\n",
558 am_get_progname(), amq_logfile);
559 errs = 1;
564 * Flush map cache
566 if (flush_flag) {
567 int *rc;
568 amq_setopt opt;
569 opt.as_opt = AMOPT_FLUSHMAPC;
570 opt.as_str = "";
571 rc = amqproc_setopt_1(&opt, clnt);
572 if (!rc || *rc) {
573 fprintf(stderr, "%s: amd on %s cannot flush the map cache\n",
574 am_get_progname(), server);
575 errs = 1;
580 * Mount info
582 if (minfo_flag) {
583 int dummy;
584 amq_mount_info_list *ml = amqproc_getmntfs_1(&dummy, clnt);
585 if (ml) {
586 int mwid = 0, dwid = 0, twid = 0;
587 show_mi(ml, Calc, &mwid, &dwid, &twid);
588 mwid++;
589 dwid++;
590 twid++;
591 show_mi(ml, Full, &mwid, &dwid, &twid);
593 } else {
594 fprintf(stderr, "%s: amd on %s cannot provide mount info\n",
595 am_get_progname(), server);
600 * Mount map
602 if (mount_map) {
603 int *rc;
604 do {
605 rc = amqproc_mount_1(&mount_map, clnt);
606 } while (rc && *rc < 0);
607 if (!rc || *rc > 0) {
608 if (rc)
609 errno = *rc;
610 else
611 errno = ETIMEDOUT;
612 fprintf(stderr, "%s: could not start new ", am_get_progname());
613 perror("automount point");
618 * Get Version
620 if (getvers_flag) {
621 amq_string *spp = amqproc_getvers_1((voidp) 0, clnt);
622 if (spp && *spp) {
623 fputs(*spp, stdout);
624 XFREE(*spp);
625 } else {
626 fprintf(stderr, "%s: failed to get version information\n",
627 am_get_progname());
628 errs = 1;
633 * Get PID of amd
635 if (getpid_flag) {
636 int *ip = amqproc_getpid_1((voidp) 0, clnt);
637 if (ip && *ip) {
638 printf("%d\n", *ip);
639 } else {
640 fprintf(stderr, "%s: failed to get PID of amd\n", am_get_progname());
641 errs = 1;
646 * Apply required operation to all remaining arguments
648 if (optind < argc) {
649 do {
650 char *fs = argv[optind++];
651 if (unmount_flag) {
653 * Unmount request
655 amqproc_umnt_1(&fs, clnt);
656 } else {
658 * Stats request
660 amq_mount_tree_p *mtp = amqproc_mnttree_1(&fs, clnt);
661 if (mtp) {
662 amq_mount_tree *mt = *mtp;
663 if (mt) {
664 int mwid = 0, dwid = 0, twid = 0;
665 show_mt(mt, Calc, &mwid, &dwid, &twid);
666 mwid++;
667 dwid++, twid++;
668 printf("%-*.*s Uid Getattr Lookup RdDir RdLnk Statfs Mounted@\n",
669 dwid, dwid, "What");
670 show_mt(mt, Stats, &mwid, &dwid, &twid);
671 } else {
672 fprintf(stderr, "%s: %s not automounted\n", am_get_progname(), fs);
674 xdr_pri_free((XDRPROC_T_TYPE) xdr_amq_mount_tree_p, (caddr_t) mtp);
675 } else {
676 fprintf(stderr, "%s: ", am_get_progname());
677 clnt_perror(clnt, server);
678 errs = 1;
681 } while (optind < argc);
683 } else if (unmount_flag) {
684 goto show_usage;
686 } else if (stats_flag) {
687 amq_mount_stats *ms = amqproc_stats_1((voidp) 0, clnt);
688 if (ms) {
689 show_ms(ms);
690 } else {
691 fprintf(stderr, "%s: ", am_get_progname());
692 clnt_perror(clnt, server);
693 errs = 1;
696 } else if (!nodefault) {
697 amq_mount_tree_list *mlp = amqproc_export_1((voidp) 0, clnt);
698 if (mlp) {
699 enum show_opt e = Calc;
700 int mwid = 0, dwid = 0, pwid = 0;
701 while (e != ShowDone) {
702 int i;
703 for (i = 0; i < mlp->amq_mount_tree_list_len; i++) {
704 show_mt(mlp->amq_mount_tree_list_val[i],
705 e, &mwid, &dwid, &pwid);
707 mwid++;
708 dwid++, pwid++;
709 if (e == Calc)
710 e = Short;
711 else if (e == Short)
712 e = ShowDone;
715 } else {
716 fprintf(stderr, "%s: ", am_get_progname());
717 clnt_perror(clnt, server);
718 errs = 1;
721 exit(errs);
722 return errs; /* should never reach here */
726 #ifdef HAVE_TRANSPORT_TYPE_TLI
729 * How to bind to reserved ports.
730 * TLI handle (socket) and port version.
732 /* defined here so that it does not have to resolve it with libamu.a */
733 static int
734 amq_bind_resv_port(int td, u_short *pp)
736 int rc = -1, port;
737 struct t_bind *treq, *tret;
738 struct sockaddr_in *sin;
740 treq = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR);
741 if (!treq) {
742 plog(XLOG_ERROR, "t_alloc 1");
743 return -1;
745 tret = (struct t_bind *) t_alloc(td, T_BIND, T_ADDR);
746 if (!tret) {
747 t_free((char *) treq, T_BIND);
748 plog(XLOG_ERROR, "t_alloc 2");
749 return -1;
751 memset((char *) treq->addr.buf, 0, treq->addr.len);
752 sin = (struct sockaddr_in *) treq->addr.buf;
753 sin->sin_family = AF_INET;
754 treq->qlen = 0;
755 treq->addr.len = treq->addr.maxlen;
756 errno = EADDRINUSE;
757 port = IPPORT_RESERVED;
759 do {
760 --port;
761 sin->sin_port = htons(port);
762 rc = t_bind(td, treq, tret);
763 if (rc < 0) {
764 } else {
765 if (memcmp(treq->addr.buf, tret->addr.buf, tret->addr.len) == 0)
766 break;
767 else
768 t_unbind(td);
770 } while ((rc < 0 || errno == EADDRINUSE) && (int) port > IPPORT_RESERVED / 2);
772 if (pp) {
773 if (rc == 0)
774 *pp = port;
775 else
776 plog(XLOG_ERROR, "could not t_bind to any reserved port");
778 t_free((char *) tret, T_BIND);
779 t_free((char *) treq, T_BIND);
780 return rc;
785 * Create a secure rpc client attached to the amd daemon.
787 static CLIENT *
788 get_secure_amd_client(char *host, struct timeval *tv, int *sock)
790 CLIENT *client;
791 struct netbuf nb;
792 struct netconfig *nc, *pm_nc;
793 struct sockaddr_in sin;
796 nb.maxlen = sizeof(sin);
797 nb.buf = (char *) &sin;
800 * Ensure that remote portmapper is alive
801 * (must use connectionless netconfig).
803 if ((pm_nc = getnetconfigent(NC_UDP)) != NULL) {
804 enum clnt_stat cs;
806 cs = rpcb_rmtcall(pm_nc,
807 host,
808 amd_program_number,
809 AMQ_VERSION,
810 AMQPROC_NULL,
811 (XDRPROC_T_TYPE) xdr_void,
812 NULL,
813 (XDRPROC_T_TYPE) xdr_void,
814 NULL,
815 *tv,
816 NULL);
817 if (cs == RPC_TIMEDOUT) {
818 fprintf(stderr, "%s: failed to contact portmapper on host \"%s\". %s\n",
819 am_get_progname(), host, clnt_sperrno(cs));
820 exit(1);
825 * First transport type to try: TCP
827 if (use_tcp_flag) {
828 /* Find amd address on TCP */
829 nc = getnetconfigent(NC_TCP);
830 if (!nc) {
831 fprintf(stderr, "getnetconfig for tcp failed: %s\n", nc_sperror());
832 goto tryudp;
835 if (!rpcb_getaddr(amd_program_number, AMQ_VERSION, nc, &nb, host)) {
837 * don't print error messages here, since amd might legitimately
838 * serve udp only
840 goto tryudp;
842 /* Create privileged TCP socket */
843 *sock = t_open(nc->nc_device, O_RDWR, 0);
845 if (*sock < 0) {
846 fprintf(stderr, "t_open %s: %m\n", nc->nc_device);
847 goto tryudp;
849 if (amq_bind_resv_port(*sock, (u_short *) 0) < 0)
850 goto tryudp;
852 client = clnt_vc_create(*sock, &nb, amd_program_number, AMQ_VERSION, 0, 0);
853 if (!client) {
854 fprintf(stderr, "clnt_vc_create failed");
855 t_close(*sock);
856 goto tryudp;
858 /* tcp succeeded */
859 return client;
862 tryudp:
864 * TCP failed so try UDP
866 if (use_udp_flag) {
867 /* find amd address on UDP */
868 nc = getnetconfigent(NC_UDP);
869 if (!nc) {
870 fprintf(stderr, "getnetconfig for udp failed: %s\n", nc_sperror());
871 return NULL;
873 if (!rpcb_getaddr(amd_program_number, AMQ_VERSION, nc, &nb, host)) {
874 fprintf(stderr, "%s\n",
875 clnt_spcreateerror("couldn't get amd address on udp"));
876 return NULL;
878 /* create privileged UDP socket */
879 *sock = t_open(nc->nc_device, O_RDWR, 0);
881 if (*sock < 0) {
882 fprintf(stderr, "t_open %s: %m\n", nc->nc_device);
883 return NULL; /* neither tcp not udp succeeded */
885 if (amq_bind_resv_port(*sock, (u_short *) 0) < 0)
886 return NULL;
888 client = clnt_dg_create(*sock, &nb, amd_program_number, AMQ_VERSION, 0, 0);
889 if (!client) {
890 fprintf(stderr, "clnt_dg_create failed\n");
891 t_close(*sock);
892 return NULL; /* neither tcp not udp succeeded */
894 if (clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) tv) == FALSE) {
895 fprintf(stderr, "clnt_control CLSET_RETRY_TIMEOUT for udp failed\n");
896 clnt_destroy(client);
897 return NULL; /* neither tcp not udp succeeded */
899 /* udp succeeded */
900 return client;
903 /* should never get here */
904 return NULL;
907 #else /* not HAVE_TRANSPORT_TYPE_TLI */
910 * inetresport creates a datagram socket and attempts to bind it to a
911 * secure port.
912 * returns: The bound socket, or -1 to indicate an error.
914 static int
915 inetresport(int ty)
917 int alport;
918 struct sockaddr_in addr;
919 int fd;
921 /* Use internet address family */
922 addr.sin_family = AF_INET;
923 addr.sin_addr.s_addr = INADDR_ANY;
924 if ((fd = socket(AF_INET, ty, 0)) < 0)
925 return -1;
927 for (alport = IPPORT_RESERVED - 1; alport > IPPORT_RESERVED / 2 + 1; alport--) {
928 addr.sin_port = htons((u_short) alport);
929 if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) >= 0)
930 return fd;
931 if (errno != EADDRINUSE) {
932 close(fd);
933 return -1;
936 close(fd);
937 errno = EAGAIN;
938 return -1;
943 * Privsock() calls inetresport() to attempt to bind a socket to a secure
944 * port. If inetresport() fails, privsock returns a magic socket number which
945 * indicates to RPC that it should make its own socket.
946 * returns: A privileged socket # or RPC_ANYSOCK.
948 static int
949 privsock(int ty)
951 int sock = inetresport(ty);
953 if (sock < 0) {
954 errno = 0;
955 /* Couldn't get a secure port, let RPC make an insecure one */
956 sock = RPC_ANYSOCK;
958 return sock;
961 #endif /* not HAVE_TRANSPORT_TYPE_TLI */