4 * Copyright (c) 1997-2009 Erez Zadok
5 * Copyright (c) 1990 Jan-Simon Pendry
6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
7 * Copyright (c) 1990 The Regents of the University of California.
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgment:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * File: am-utils/amq/amq.c
47 * Automounter query tool
52 #endif /* HAVE_CONFIG_H */
57 static int flush_flag
;
58 static int getpid_flag
;
59 static int getpwd_flag
;
60 static int getvers_flag
;
61 static int minfo_flag
;
62 static int quiet_flag
;
63 static int stats_flag
;
64 static int unmount_flag
;
65 static int use_tcp_flag
;
66 static int use_udp_flag
;
67 static u_long amd_program_number
= AMQ_PROGRAM
;
68 static char *debug_opts
;
69 static char *amq_logfile
;
70 static char *xlog_optstr
;
71 static char localhost
[] = "localhost";
72 static char *def_server
= localhost
;
80 Full
, Stats
, Calc
, Short
, ShowDone
85 * If (e) is Calc then just calculate the sizes
86 * Otherwise display the mount node on stdout
89 show_mti(amq_mount_tree
*mt
, enum show_opt e
, int *mwid
, int *dwid
, int *twid
)
94 int mw
= strlen(mt
->mt_mountinfo
);
95 int dw
= strlen(mt
->mt_directory
);
96 int tw
= strlen(mt
->mt_type
);
108 struct tm
*tp
= localtime((time_t *) ((voidp
) &mt
->mt_mounttime
));
109 printf("%-*.*s %-*.*s %-*.*s %s\n\t%-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%04d %02d:%02d:%02d\n",
111 *mt
->mt_directory
? mt
->mt_directory
: "/", /* XXX */
125 tp
->tm_mon
+ 1, tp
->tm_mday
,
126 tp
->tm_year
< 1900 ? tp
->tm_year
+ 1900 : tp
->tm_year
,
127 tp
->tm_hour
, tp
->tm_min
, tp
->tm_sec
);
133 struct tm
*tp
= localtime((time_t *) ((voidp
) &mt
->mt_mounttime
));
134 printf("%-*.*s %-5d %-7d %-6d %-7d %-7d %-6d %02d/%02d/%02d %02d:%02d:%04d\n",
136 *mt
->mt_directory
? mt
->mt_directory
: "/", /* XXX */
145 tp
->tm_mon
+ 1, tp
->tm_mday
,
146 tp
->tm_year
< 1900 ? tp
->tm_year
+ 1900 : tp
->tm_year
,
147 tp
->tm_hour
, tp
->tm_min
, tp
->tm_sec
);
153 printf("%-*.*s %-*.*s %-*.*s %s\n",
155 *mt
->mt_directory
? mt
->mt_directory
: "/",
174 show_pwd(amq_mount_tree
*mt
, char *path
, size_t l
, int *flag
)
179 len
= strlen(mt
->mt_mountpoint
);
180 if (NSTREQ(path
, mt
->mt_mountpoint
, len
) &&
181 !STREQ(mt
->mt_directory
, mt
->mt_mountpoint
)) {
182 char buf
[MAXPATHLEN
+1]; /* must be same size as 'path' */
183 xstrlcpy(buf
, mt
->mt_directory
, sizeof(buf
));
184 xstrlcat(buf
, &path
[len
], sizeof(buf
));
185 xstrlcpy(path
, buf
, l
);
188 show_pwd(mt
->mt_next
, path
, l
, flag
);
195 * Display a mount tree.
198 show_mt(amq_mount_tree
*mt
, enum show_opt e
, int *mwid
, int *dwid
, int *pwid
)
201 show_mti(mt
, e
, mwid
, dwid
, pwid
);
202 show_mt(mt
->mt_next
, e
, mwid
, dwid
, pwid
);
209 show_mi(amq_mount_info_list
*ml
, enum show_opt e
, int *mwid
, int *dwid
, int *twid
)
217 for (i
= 0; i
< ml
->amq_mount_info_list_len
; i
++) {
218 amq_mount_info
*mi
= &ml
->amq_mount_info_list_val
[i
];
219 int mw
= strlen(mi
->mi_mountinfo
);
220 int dw
= strlen(mi
->mi_mountpt
);
221 int tw
= strlen(mi
->mi_type
);
234 for (i
= 0; i
< ml
->amq_mount_info_list_len
; i
++) {
235 amq_mount_info
*mi
= &ml
->amq_mount_info_list_val
[i
];
236 printf("%-*.*s %-*.*s %-*.*s %-3d %s is %s",
237 *mwid
, *mwid
, mi
->mi_mountinfo
,
238 *dwid
, *dwid
, mi
->mi_mountpt
,
239 *twid
, *twid
, mi
->mi_type
,
240 mi
->mi_refc
, mi
->mi_fserver
,
241 mi
->mi_up
> 0 ? "up" :
242 mi
->mi_up
< 0 ? "starting" : "down");
243 if (mi
->mi_error
> 0) {
244 printf(" (%s)", strerror(mi
->mi_error
));
245 } else if (mi
->mi_error
< 0) {
246 fputs(" (in progress)", stdout
);
260 * Display general mount statistics
263 show_ms(amq_mount_stats
*ms
)
266 requests stale mount mount unmount\n\
267 deferred fhandles ok failed failed\n\
268 %-9d %-9d %-9d %-9d %-9d\n",
269 ms
->as_drops
, ms
->as_stale
, ms
->as_mok
, ms
->as_merr
, ms
->as_uerr
);
273 #if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT)
277 struct cct_entry
*cp
;
279 if (cnodeid() == 0) {
285 while (cp
= getccent())
286 if (cp
->cnode_type
== 'r')
287 return cp
->cnode_name
;
291 #endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */
295 print_umnt_error(amq_sync_umnt
*rv
, const char *fs
)
298 switch (rv
->au_etype
) {
301 case AMQ_UMNT_FAILED
:
302 printf("unmount failed: %s\n", strerror(rv
->au_errno
));
305 if (rv
->au_errno
== 0)
306 printf("%s is not mounted\n", fs
);
308 printf("falling back to asynchronous unmount: %s\n",
309 strerror(rv
->au_errno
));
312 printf("pipe read error: %s\n", strerror(rv
->au_errno
));
314 case AMQ_UMNT_SERVER
:
315 printf("amd server down\n");
317 case AMQ_UMNT_SIGNAL
:
318 printf("got signal: %d\n", rv
->au_signal
);
321 * Omit default so the compiler can check for missing cases.
331 amu_sync_umnt_to_retval(amq_sync_umnt
*rv
)
333 switch (rv
->au_etype
) {
335 if (rv
->au_errno
== 0) {
337 * We allow this error so that things like:
338 * amq -uu /l/cd0d && eject cd0
339 * will work when /l/cd0d is not mounted.
340 * XXX - We still print an error message.
351 clnt_failed(CLIENT
*clnt
, char *server
)
353 fprintf(stderr
, "%s: ", am_get_progname());
354 clnt_perror(clnt
, server
);
363 main(int argc
, char *argv
[])
368 struct sockaddr_in server_addr
;
373 char *progname
= NULL
;
376 * Compute program name
379 progname
= strrchr(argv
[0], '/');
380 if (progname
&& progname
[1])
387 am_set_progname(progname
);
392 while ((opt_ch
= getopt(argc
, argv
, "Hfh:l:mqsuvx:D:pP:TUw")) != -1)
408 amq_logfile
= optarg
;
443 xlog_optstr
= optarg
;
453 amd_program_number
= atoi(optarg
);
473 if (optind
== argc
) {
480 Usage: %s [-fmpqsvwHTU] [-h hostname] [-l log_file|\"syslog\"]\n\
481 \t[-x log_options] [-D debug_options]\n\
482 \t[-P program_number] [[-u[u]] directory ...]\n",
489 /* set use_udp and use_tcp flags both to on if none are defined */
490 if (!use_tcp_flag
&& !use_udp_flag
)
491 use_tcp_flag
= use_udp_flag
= 1;
493 #if defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT)
495 * Figure out root server of cluster
497 if (def_server
== localhost
)
498 server
= cluster_server();
500 #endif /* defined(HAVE_CLUSTER_H) && defined(HAVE_CNODEID) && defined(HAVE_GETCCENT) */
504 * Get address of server
506 if ((hp
= gethostbyname(server
)) == 0 && !STREQ(server
, localhost
)) {
507 fprintf(stderr
, "%s: Can't get address of %s\n",
508 am_get_progname(), server
);
511 memset(&server_addr
, 0, sizeof(server_addr
));
512 /* as per POSIX, sin_len need not be set (used internally by kernel) */
513 server_addr
.sin_family
= AF_INET
;
515 memmove((voidp
) &server_addr
.sin_addr
, (voidp
) hp
->h_addr
,
516 sizeof(server_addr
.sin_addr
));
518 /* fake "localhost" */
519 server_addr
.sin_addr
.s_addr
= htonl(0x7f000001);
523 * Create RPC endpoint
525 tv
.tv_sec
= 5; /* 5 seconds for timeout or per retry */
528 if (use_tcp_flag
) /* try tcp first */
529 clnt
= clnt_create(server
, amd_program_number
, AMQ_VERSION
, "tcp");
530 if (!clnt
&& use_udp_flag
) { /* try udp next */
531 clnt
= clnt_create(server
, amd_program_number
, AMQ_VERSION
, "udp");
532 /* if ok, set timeout (valid for connectionless transports only) */
534 clnt_control(clnt
, CLSET_RETRY_TIMEOUT
, (char *) &tv
);
537 fprintf(stderr
, "%s: ", am_get_progname());
538 clnt_pcreateerror(server
);
548 opt
.as_opt
= AMOPT_DEBUG
;
549 opt
.as_str
= debug_opts
;
550 rc
= amqproc_setopt_1(&opt
, clnt
);
552 fprintf(stderr
, "%s: daemon not compiled for debug\n",
555 } else if (!rc
|| *rc
> 0) {
556 fprintf(stderr
, "%s: debug setting for \"%s\" failed\n",
557 am_get_progname(), debug_opts
);
568 opt
.as_opt
= AMOPT_XLOG
;
569 opt
.as_str
= xlog_optstr
;
570 rc
= amqproc_setopt_1(&opt
, clnt
);
572 fprintf(stderr
, "%s: setting log level to \"%s\" failed\n",
573 am_get_progname(), xlog_optstr
);
584 opt
.as_opt
= AMOPT_LOGFILE
;
585 opt
.as_str
= amq_logfile
;
586 rc
= amqproc_setopt_1(&opt
, clnt
);
588 fprintf(stderr
, "%s: setting logfile to \"%s\" failed\n",
589 am_get_progname(), amq_logfile
);
600 opt
.as_opt
= AMOPT_FLUSHMAPC
;
602 rc
= amqproc_setopt_1(&opt
, clnt
);
604 fprintf(stderr
, "%s: amd on %s cannot flush the map cache\n",
605 am_get_progname(), server
);
614 char path
[MAXPATHLEN
+1];
615 char *wd
= getcwd(path
, MAXPATHLEN
+1);
616 amq_mount_tree_list
*mlp
= amqproc_export_1((voidp
) 0, clnt
);
625 for (i
= 0; mlp
&& i
< mlp
->amq_mount_tree_list_len
; i
++) {
626 mt
= mlp
->amq_mount_tree_list_val
[i
];
629 show_pwd(mt
, path
, sizeof(path
), &flag
);
631 printf("%s\n", path
);
644 amq_mount_info_list
*ml
= amqproc_getmntfs_1(&dummy
, clnt
);
646 int mwid
= 0, dwid
= 0, twid
= 0;
647 show_mi(ml
, Calc
, &mwid
, &dwid
, &twid
);
651 show_mi(ml
, Full
, &mwid
, &dwid
, &twid
);
654 fprintf(stderr
, "%s: amd on %s cannot provide mount info\n",
655 am_get_progname(), server
);
663 amq_string
*spp
= amqproc_getvers_1((voidp
) 0, clnt
);
668 fprintf(stderr
, "%s: failed to get version information\n",
678 int *ip
= amqproc_getpid_1((voidp
) 0, clnt
);
682 fprintf(stderr
, "%s: failed to get PID of amd\n", am_get_progname());
688 * Apply required operation to all remaining arguments
692 char *fs
= argv
[optind
++];
693 if (unmount_flag
> 1) {
696 * Synchronous unmount request
698 sup
= amqproc_sync_umnt_1(&fs
, clnt
);
701 print_umnt_error(sup
, fs
);
702 errs
= amu_sync_umnt_to_retval(sup
);
704 errs
= clnt_failed(clnt
, server
);
706 } else if (unmount_flag
) {
710 amqproc_umnt_1(&fs
, clnt
);
715 amq_mount_tree_p
*mtp
= amqproc_mnttree_1(&fs
, clnt
);
717 amq_mount_tree
*mt
= *mtp
;
719 int mwid
= 0, dwid
= 0, twid
= 0;
720 show_mt(mt
, Calc
, &mwid
, &dwid
, &twid
);
723 printf("%-*.*s Uid Getattr Lookup RdDir RdLnk Statfs Mounted@\n",
725 show_mt(mt
, Stats
, &mwid
, &dwid
, &twid
);
727 fprintf(stderr
, "%s: %s not automounted\n", am_get_progname(), fs
);
729 xdr_pri_free((XDRPROC_T_TYPE
) xdr_amq_mount_tree_p
, (caddr_t
) mtp
);
731 errs
= clnt_failed(clnt
, server
);
734 } while (optind
< argc
);
736 } else if (unmount_flag
) {
739 } else if (stats_flag
) {
740 amq_mount_stats
*ms
= amqproc_stats_1((voidp
) 0, clnt
);
744 errs
= clnt_failed(clnt
, server
);
747 } else if (!nodefault
) {
748 amq_mount_tree_list
*mlp
= amqproc_export_1((voidp
) 0, clnt
);
750 enum show_opt e
= Calc
;
751 int mwid
= 0, dwid
= 0, pwid
= 0;
753 while (e
!= ShowDone
) {
755 for (i
= 0; i
< mlp
->amq_mount_tree_list_len
; i
++) {
756 show_mt(mlp
->amq_mount_tree_list_val
[i
],
757 e
, &mwid
, &dwid
, &pwid
);
768 errs
= clnt_failed(clnt
, server
);
772 return errs
; /* should never reach here */