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.
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
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
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
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";
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 */
66 #endif /* HAVE_CONFIG_H */
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
;
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 */
100 Full
, Stats
, Calc
, Short
, ShowDone
105 * If (e) is Calc then just calculate the sizes
106 * Otherwise display the mount node on stdout
109 show_mti(amq_mount_tree
*mt
, enum show_opt e
, int *mwid
, int *dwid
, int *twid
)
114 int mw
= strlen(mt
->mt_mountinfo
);
115 int dw
= strlen(mt
->mt_directory
);
116 int tw
= strlen(mt
->mt_type
);
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",
131 *mt
->mt_directory
? mt
->mt_directory
: "/", /* XXX */
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
);
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",
156 *mt
->mt_directory
? mt
->mt_directory
: "/", /* XXX */
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
);
173 printf("%-*.*s %-*.*s %-*.*s %s\n",
175 *mt
->mt_directory
? mt
->mt_directory
: "/",
190 * Display a mount tree.
193 show_mt(amq_mount_tree
*mt
, enum show_opt e
, int *mwid
, int *dwid
, int *pwid
)
196 show_mti(mt
, e
, mwid
, dwid
, pwid
);
197 show_mt(mt
->mt_next
, e
, mwid
, dwid
, pwid
);
203 show_mi(amq_mount_info_list
*ml
, enum show_opt e
, int *mwid
, int *dwid
, int *twid
)
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
);
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
)
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 */
245 printf(" (Error %d)", mi
->mi_error
);
246 } else if (mi
->mi_error
< 0) {
247 fputs(" (in progress)", stdout
);
261 * Display general mount statistics
264 show_ms(amq_mount_stats
*ms
)
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)
278 struct cct_entry
*cp
;
280 if (cnodeid() == 0) {
286 while (cp
= getccent())
287 if (cp
->cnode_type
== 'r')
288 return cp
->cnode_name
;
292 #endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */
299 main(int argc
, char *argv
[])
304 struct sockaddr_in server_addr
;
305 int s
; /* to pass the Amd security check, we must use a priv port */
310 char *progname
= NULL
;
311 #ifndef HAVE_TRANSPORT_TYPE_TLI
313 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
317 * Compute program name
320 progname
= strrchr(argv
[0], '/');
321 if (progname
&& progname
[1])
328 am_set_progname(progname
);
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 */
349 amq_logfile
= optarg
;
379 xlog_optstr
= optarg
;
388 #ifdef ENABLE_AMQ_MOUNT
393 #endif /* ENABLE_AMQ_MOUNT */
396 amd_program_number
= atoi(optarg
);
412 if (optind
== argc
) {
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",
423 #ifdef ENABLE_AMQ_MOUNT
425 #else /* not ENABLE_AMQ_MOUNT */
427 #endif /* not ENABLE_AMQ_MOUNT */
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();
445 #endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */
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
);
456 memset(&server_addr
, 0, sizeof server_addr
);
457 server_addr
.sin_family
= AF_INET
;
459 memmove((voidp
) &server_addr
.sin_addr
, (voidp
) hp
->h_addr
,
460 sizeof(server_addr
.sin_addr
));
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 */
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) */
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
));
492 /* portmapper exists: get remote amd info from it */
493 if (!clnt
&& use_tcp_flag
) { /* try tcp first */
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 */
506 fprintf(stderr
, "%s: ", am_get_progname());
507 clnt_pcreateerror(server
);
517 opt
.as_opt
= AMOPT_DEBUG
;
518 opt
.as_str
= debug_opts
;
519 rc
= amqproc_setopt_1(&opt
, clnt
);
521 fprintf(stderr
, "%s: daemon not compiled for debug\n",
524 } else if (!rc
|| *rc
> 0) {
525 fprintf(stderr
, "%s: debug setting for \"%s\" failed\n",
526 am_get_progname(), debug_opts
);
537 opt
.as_opt
= AMOPT_XLOG
;
538 opt
.as_str
= xlog_optstr
;
539 rc
= amqproc_setopt_1(&opt
, clnt
);
541 fprintf(stderr
, "%s: setting log level to \"%s\" failed\n",
542 am_get_progname(), xlog_optstr
);
553 opt
.as_opt
= AMOPT_LOGFILE
;
554 opt
.as_str
= amq_logfile
;
555 rc
= amqproc_setopt_1(&opt
, clnt
);
557 fprintf(stderr
, "%s: setting logfile to \"%s\" failed\n",
558 am_get_progname(), amq_logfile
);
569 opt
.as_opt
= AMOPT_FLUSHMAPC
;
571 rc
= amqproc_setopt_1(&opt
, clnt
);
573 fprintf(stderr
, "%s: amd on %s cannot flush the map cache\n",
574 am_get_progname(), server
);
584 amq_mount_info_list
*ml
= amqproc_getmntfs_1(&dummy
, clnt
);
586 int mwid
= 0, dwid
= 0, twid
= 0;
587 show_mi(ml
, Calc
, &mwid
, &dwid
, &twid
);
591 show_mi(ml
, Full
, &mwid
, &dwid
, &twid
);
594 fprintf(stderr
, "%s: amd on %s cannot provide mount info\n",
595 am_get_progname(), server
);
605 rc
= amqproc_mount_1(&mount_map
, clnt
);
606 } while (rc
&& *rc
< 0);
607 if (!rc
|| *rc
> 0) {
612 fprintf(stderr
, "%s: could not start new ", am_get_progname());
613 perror("automount point");
621 amq_string
*spp
= amqproc_getvers_1((voidp
) 0, clnt
);
626 fprintf(stderr
, "%s: failed to get version information\n",
636 int *ip
= amqproc_getpid_1((voidp
) 0, clnt
);
640 fprintf(stderr
, "%s: failed to get PID of amd\n", am_get_progname());
646 * Apply required operation to all remaining arguments
650 char *fs
= argv
[optind
++];
655 amqproc_umnt_1(&fs
, clnt
);
660 amq_mount_tree_p
*mtp
= amqproc_mnttree_1(&fs
, clnt
);
662 amq_mount_tree
*mt
= *mtp
;
664 int mwid
= 0, dwid
= 0, twid
= 0;
665 show_mt(mt
, Calc
, &mwid
, &dwid
, &twid
);
668 printf("%-*.*s Uid Getattr Lookup RdDir RdLnk Statfs Mounted@\n",
670 show_mt(mt
, Stats
, &mwid
, &dwid
, &twid
);
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
);
676 fprintf(stderr
, "%s: ", am_get_progname());
677 clnt_perror(clnt
, server
);
681 } while (optind
< argc
);
683 } else if (unmount_flag
) {
686 } else if (stats_flag
) {
687 amq_mount_stats
*ms
= amqproc_stats_1((voidp
) 0, clnt
);
691 fprintf(stderr
, "%s: ", am_get_progname());
692 clnt_perror(clnt
, server
);
696 } else if (!nodefault
) {
697 amq_mount_tree_list
*mlp
= amqproc_export_1((voidp
) 0, clnt
);
699 enum show_opt e
= Calc
;
700 int mwid
= 0, dwid
= 0, pwid
= 0;
701 while (e
!= ShowDone
) {
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
);
716 fprintf(stderr
, "%s: ", am_get_progname());
717 clnt_perror(clnt
, server
);
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 */
734 amq_bind_resv_port(int td
, u_short
*pp
)
737 struct t_bind
*treq
, *tret
;
738 struct sockaddr_in
*sin
;
740 treq
= (struct t_bind
*) t_alloc(td
, T_BIND
, T_ADDR
);
742 plog(XLOG_ERROR
, "t_alloc 1");
745 tret
= (struct t_bind
*) t_alloc(td
, T_BIND
, T_ADDR
);
747 t_free((char *) treq
, T_BIND
);
748 plog(XLOG_ERROR
, "t_alloc 2");
751 memset((char *) treq
->addr
.buf
, 0, treq
->addr
.len
);
752 sin
= (struct sockaddr_in
*) treq
->addr
.buf
;
753 sin
->sin_family
= AF_INET
;
755 treq
->addr
.len
= treq
->addr
.maxlen
;
757 port
= IPPORT_RESERVED
;
761 sin
->sin_port
= htons(port
);
762 rc
= t_bind(td
, treq
, tret
);
765 if (memcmp(treq
->addr
.buf
, tret
->addr
.buf
, tret
->addr
.len
) == 0)
770 } while ((rc
< 0 || errno
== EADDRINUSE
) && (int) port
> IPPORT_RESERVED
/ 2);
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
);
785 * Create a secure rpc client attached to the amd daemon.
788 get_secure_amd_client(char *host
, struct timeval
*tv
, int *sock
)
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
) {
806 cs
= rpcb_rmtcall(pm_nc
,
811 (XDRPROC_T_TYPE
) xdr_void
,
813 (XDRPROC_T_TYPE
) xdr_void
,
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
));
825 * First transport type to try: TCP
828 /* Find amd address on TCP */
829 nc
= getnetconfigent(NC_TCP
);
831 fprintf(stderr
, "getnetconfig for tcp failed: %s\n", nc_sperror());
835 if (!rpcb_getaddr(amd_program_number
, AMQ_VERSION
, nc
, &nb
, host
)) {
837 * don't print error messages here, since amd might legitimately
842 /* Create privileged TCP socket */
843 *sock
= t_open(nc
->nc_device
, O_RDWR
, 0);
846 fprintf(stderr
, "t_open %s: %m\n", nc
->nc_device
);
849 if (amq_bind_resv_port(*sock
, (u_short
*) 0) < 0)
852 client
= clnt_vc_create(*sock
, &nb
, amd_program_number
, AMQ_VERSION
, 0, 0);
854 fprintf(stderr
, "clnt_vc_create failed");
864 * TCP failed so try UDP
867 /* find amd address on UDP */
868 nc
= getnetconfigent(NC_UDP
);
870 fprintf(stderr
, "getnetconfig for udp failed: %s\n", nc_sperror());
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"));
878 /* create privileged UDP socket */
879 *sock
= t_open(nc
->nc_device
, O_RDWR
, 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)
888 client
= clnt_dg_create(*sock
, &nb
, amd_program_number
, AMQ_VERSION
, 0, 0);
890 fprintf(stderr
, "clnt_dg_create failed\n");
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 */
903 /* should never get here */
907 #else /* not HAVE_TRANSPORT_TYPE_TLI */
910 * inetresport creates a datagram socket and attempts to bind it to a
912 * returns: The bound socket, or -1 to indicate an error.
918 struct sockaddr_in addr
;
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)
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)
931 if (errno
!= EADDRINUSE
) {
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.
951 int sock
= inetresport(ty
);
955 /* Couldn't get a secure port, let RPC make an insecure one */
961 #endif /* not HAVE_TRANSPORT_TYPE_TLI */