4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
24 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
41 #include <sys/param.h>
44 #include <sys/types.h>
46 #include <sys/mnttab.h>
47 #include <sys/mntent.h>
48 #include <sys/mount.h>
49 #include <sys/utsname.h>
50 #include <sys/tiuser.h>
52 #include <rpcsvc/nfs_prot.h>
55 #include <rpcsvc/daemon_utils.h>
56 #include "automount.h"
59 static int mkdir_r(char *);
60 struct autodir
*dir_head
;
61 struct autodir
*dir_tail
;
62 static struct extmnttab
*find_mount();
67 static int compare_opts(char *, char *);
68 static void do_unmounts();
70 static int mount_timeout
= AUTOFS_MOUNT_TIMEOUT
;
72 static char *service_list
[] = { AUTOMOUNTD
, NULL
};
76 * The following are needed because they're used in auto_subr.c and
77 * we link with it. Should avoid this.
80 cond_t cleanup_start_cv
;
81 cond_t cleanup_done_cv
;
84 main(int argc
, char *argv
[])
87 struct autofs_args ai
;
88 struct utsname utsname
;
89 char autofs_addr
[MAXADDRLEN
];
90 struct autodir
*dir
, *d
;
92 char *master_map
= "auto_master";
94 struct extmnttab mnt
, *mntp
;
96 char mntopts
[MAX_MNTOPT_STR
];
99 char *stack
[STACKSIZ
];
102 struct sigaction sigintact
;
103 int ret
= 0, bufsz
= 0;
107 * protect this command from session termination when run in background
108 * we test background by whether SIGINT is ignored
110 (void) sigaction(SIGINT
, NULL
, &sigintact
);
111 if (sigintact
.sa_sigaction
== SIG_IGN
) {
112 (void) signal(SIGHUP
, SIG_IGN
);
117 * Read in the values from SMF first before we check
118 * commandline options so the options override the SMF values.
121 ret
= autofs_smf_get_prop("timeout", valbuf
, DEFAULT_INSTANCE
,
122 SCF_TYPE_INTEGER
, AUTOMOUNTD
, &bufsz
);
125 * Ignore errno. In event of failure, mount_timeout is
126 * already initialized to the correct value.
128 mount_timeout
= strtol(valbuf
, (char **)NULL
, 10);
131 ret
= autofs_smf_get_prop("automount_verbose", valbuf
, DEFAULT_INSTANCE
,
132 SCF_TYPE_BOOLEAN
, AUTOMOUNTD
, &bufsz
);
134 if (strncasecmp("true", valbuf
, 4) == 0)
138 put_automountd_env();
140 while ((c
= getopt(argc
, argv
, "mM:D:f:t:v?")) != EOF
) {
143 pr_msg("Warning: -m option not supported");
146 pr_msg("Warning: -M option not supported");
149 pr_msg("Warning: -D option not supported");
152 pr_msg("Error: -f option no longer supported");
156 if (strchr(optarg
, '=')) {
157 pr_msg("Error: invalid value for -t");
160 mount_timeout
= atoi(optarg
);
172 pr_msg("%s: command line mountpoints/maps "
173 "no longer supported", argv
[optind
]);
177 current_mounts
= getmntlist();
178 if (current_mounts
== NULL
) {
179 pr_msg("Couldn't establish current mounts");
184 ns_setup(stack
, &stkptr
);
186 openlog("automount", LOG_PID
, LOG_DAEMON
);
187 (void) loadmaster_map(master_map
, "", stack
, &stkptr
);
188 if (dir_head
!= NULL
) {
190 * automount maps found. enable services as needed.
192 _check_services(service_list
);
197 if (uname(&utsname
) < 0) {
201 (void) strcpy(autofs_addr
, utsname
.nodename
);
202 (void) strcat(autofs_addr
, ".autofs");
203 ai
.addr
.buf
= autofs_addr
;
204 ai
.addr
.len
= strlen(ai
.addr
.buf
);
205 ai
.addr
.maxlen
= ai
.addr
.len
;
207 ai
.mount_to
= mount_timeout
;
208 ai
.rpc_to
= AUTOFS_RPC_TIMEOUT
;
211 * Mount the daemon at its mount points.
213 for (dir
= dir_head
; dir
; dir
= dir
->dir_next
) {
218 if (strcmp(dir
->dir_map
, "-null") == 0)
222 * Skip null'ed entries
225 for (d
= dir
->dir_prev
; d
; d
= d
->dir_prev
) {
226 if (strcmp(dir
->dir_name
, d
->dir_name
) == 0)
233 * Check whether there's already an entry
234 * in the mnttab for this mountpoint.
236 if (mntp
= find_mount(dir
->dir_name
, 1)) {
238 * If it's not an autofs mount - don't
241 if (strcmp(mntp
->mnt_fstype
, MNTTYPE_AUTOFS
) != 0) {
242 pr_msg("%s: already mounted",
248 * Compare the mnttab entry with the master map
249 * entry. If the map or mount options are
250 * different, then update this information
253 if (strcmp(mntp
->mnt_special
, dir
->dir_map
) == 0 &&
254 compare_opts(dir
->dir_opts
,
255 mntp
->mnt_mntopts
) == 0) {
256 continue; /* no change */
260 * Check for an overlaid direct autofs mount.
261 * Cannot remount since it's inaccessible.
263 omntp
= (struct mnttab
*)mntp
;
264 if (hasmntopt(omntp
, "direct") != NULL
) {
265 mntp
= find_mount(dir
->dir_name
, 0);
266 omntp
= (struct mnttab
*)mntp
;
267 if (hasmntopt(omntp
, "direct") == NULL
) {
269 pr_msg("%s: cannot remount",
275 dir
->dir_remount
= 1;
279 * Create a mount point if necessary
280 * If the path refers to an existing symbolic
281 * link, refuse to mount on it. This avoids
284 if (lstat(dir
->dir_name
, &stbuf
) == 0) {
285 if ((stbuf
.st_mode
& S_IFMT
) != S_IFDIR
) {
286 pr_msg("%s: Not a directory", dir
->dir_name
);
290 if (mkdir_r(dir
->dir_name
)) {
291 pr_msg("%s: %m", dir
->dir_name
);
296 ai
.path
= dir
->dir_name
;
297 ai
.opts
= dir
->dir_opts
;
298 ai
.map
= dir
->dir_map
;
300 ai
.direct
= dir
->dir_direct
;
302 ai
.key
= dir
->dir_name
;
306 (void) sprintf(mntopts
, "ignore,%s",
307 dir
->dir_direct
? "direct" : "indirect");
308 if (dir
->dir_opts
&& *dir
->dir_opts
) {
309 (void) strcat(mntopts
, ",");
310 (void) strcat(mntopts
, dir
->dir_opts
);
312 mntflgs
= MS_OPTIONSTR
| (dir
->dir_remount
? MS_REMOUNT
: 0);
313 if (mount(dir
->dir_map
, dir
->dir_name
, MS_DATA
| mntflgs
,
314 MNTTYPE_AUTOFS
, &ai
, sizeof (ai
), mntopts
,
315 MAX_MNTOPT_STR
) < 0) {
316 pr_msg("mount %s: %m", dir
->dir_name
);
323 if (dir
->dir_remount
)
324 pr_msg("%s remounted", dir
->dir_name
);
326 pr_msg("%s mounted", dir
->dir_name
);
330 if (verbose
&& count
== 0)
334 * Now compare the /etc/mnttab with the master
335 * map. Any autofs mounts in the /etc/mnttab
336 * that are not in the master map must be
345 * Find a mount entry given
346 * the mountpoint path.
347 * Optionally return the first
350 static struct extmnttab
*
351 find_mount(mntpnt
, first
)
355 struct mntlist
*mntl
;
356 struct extmnttab
*found
= NULL
;
358 for (mntl
= current_mounts
; mntl
; mntl
= mntl
->mntl_next
) {
360 if (strcmp(mntpnt
, mntl
->mntl_mnt
->mnt_mountp
) == 0) {
361 found
= mntl
->mntl_mnt
;
370 static char *ignore_opts
[] = {"ignore", "direct", "indirect", "dev", NULL
};
373 * Compare mount options
374 * ignoring "ignore", "direct", "indirect"
378 compare_opts(opts
, mntopts
)
379 char *opts
, *mntopts
;
381 char optbuf1
[MAX_MNTOPT_STR
], *s
= optbuf1
;
382 char optbuf2
[MAX_MNTOPT_STR
];
383 char **opttbl1
, **opttbl2
;
385 char *ostart
, *optr
, *valp
;
388 opttbl1
= opttbl2
= NULL
;
390 * Parse the two option strings to split them both into
391 * lists of individual options.
394 (void) strcpy(s
, mntopts
);
401 for (s
= strchr(s
, ','); s
!= NULL
; s
= strchr(s
, ',')) {
406 if ((opttbl1
= memalign(sizeof (char *),
407 nopts1
* sizeof (char *))) == NULL
)
411 for (ostart
= optr
= s
; *optr
!= '\0'; ostart
= optr
) {
412 if (getsubopt(&optr
, ignore_opts
, &valp
) == -1) {
413 opttbl1
[nopts1
++] = ostart
;
418 (void) strcpy(s
, opts
);
425 for (s
= strchr(s
, ','); s
!= NULL
; s
= strchr(s
, ',')) {
430 if ((opttbl2
= memalign(sizeof (char *),
431 nopts2
* sizeof (char *))) == NULL
) {
437 for (ostart
= optr
= s
; *optr
!= '\0'; ostart
= optr
) {
438 if (getsubopt(&optr
, ignore_opts
, &valp
) == -1) {
439 opttbl2
[nopts2
++] = ostart
;
442 if (nopts2
!= nopts1
) {
447 for (i
= 0; i
< nopts1
; i
++) {
449 for (j
= 0; j
< nopts2
; j
++) {
450 if (strcmp(opttbl1
[i
], opttbl2
[j
]) == 0) {
470 pr_msg("Usage: automount [ -v ] [ -t duration ]");
476 * Unmount any autofs mounts that
477 * aren't in the master map
482 struct mntlist
*mntl
;
483 struct extmnttab
*mnt
;
488 struct zone_summary
*zsp
;
490 zsp
= fs_get_zone_summaries();
492 pr_msg("Couldn't establish active zones");
495 for (mntl
= current_mounts
; mntl
; mntl
= mntl
->mntl_next
) {
496 mnt
= mntl
->mntl_mnt
;
497 omnt
= (struct mnttab
*)mnt
;
498 if (strcmp(mnt
->mnt_fstype
, MNTTYPE_AUTOFS
) != 0)
500 if (fs_mount_in_other_zone(zsp
, mnt
->mnt_mountp
))
503 * Don't unmount autofs mounts done
504 * from the autofs mount command.
505 * How do we tell them apart ?
506 * Autofs mounts not eligible for auto-unmount
507 * have the "nest" pseudo-option.
509 if (hasmntopt(omnt
, "nest") != NULL
)
513 for (dir
= dir_head
; dir
; dir
= dir
->dir_next
) {
514 if (strcmp(dir
->dir_name
, mnt
->mnt_mountp
) == 0) {
515 current
= strcmp(dir
->dir_map
, "-null");
523 if (umount(mnt
->mnt_mountp
) == 0) {
525 pr_msg("%s unmounted",
531 if (verbose
&& count
== 0)
532 pr_msg("no unmounts");
542 if (mkdir(dir
, 0555) == 0 || errno
== EEXIST
)
546 slash
= strrchr(dir
, '/');
554 return (mkdir(dir
, 0555));
559 * Works like printf (fmt string and variable args)
560 * except that it will subsititute an error message
561 * for a "%m" string (like syslog).
565 pr_msg(const char *fmt
, ...)
568 char buf
[BUFSIZ
], *p2
;
572 (void) strcpy(buf
, "automount: ");
573 p2
= buf
+ strlen(buf
);
577 for (p1
= nfmt
; *p1
; p1
++) {
578 if (*p1
== '%' && *(p1
+1) == 'm') {
579 (void) strcpy(p2
, strerror(errno
));
586 if (p2
> buf
&& *(p2
-1) != '\n')
591 (void) vfprintf(stderr
, buf
, ap
);