1
2#include <sys/param.h>
3#include <sys/mount.h>
4#include <sys/errno.h>
5#include <sys/wait.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <err.h>
10#include <stdbool.h>
11#include <unistd.h>
12
13#include "autofs.h"
14
15static char usage[] = "usage: %s [-d] mount_point opts map subdir key";
16
17static char gKextLoadCommand[] = "/sbin/kextload";
18static char gKextLoadPath[] = "/System/Library/Extensions/autofs.kext";
19
20static int LoadAutoFS(void);
21
22int
23main(int argc, char **argv)
24{
25	int ch;
26	int error;
27	bool retried;
28	struct autofs_args mnt_args;
29	char mount_path[PATH_MAX];
30	char *path;
31	int32_t direct = 0;
32
33	while ((ch = getopt(argc, argv, "dt:")) != EOF) {
34		switch (ch) {
35
36		case 'd':
37			direct = 1;
38			break;
39
40		default:
41			fprintf(stderr, "%s: unknown option '-%c'.\n", getprogname(), ch);
42			fprintf(stderr, usage, getprogname());
43			return (EXIT_FAILURE);
44		}
45	}
46	argc -= optind;
47	argv += optind;
48
49	if (argc < 5)
50		errx(1, usage, getprogname());
51
52	path = realpath(argv[0], mount_path);
53	if (path == NULL) {
54		err(1, "couldn't resolve mount path: %s", strerror(errno));
55		/* NOT REACHED */
56		return 1;
57	};
58
59	mnt_args.version = AUTOFS_ARGSVERSION;
60	mnt_args.path = path;
61	mnt_args.opts = argv[1];
62	mnt_args.map = argv[2];
63	mnt_args.subdir = argv[3];
64	mnt_args.key = argv[4];
65	mnt_args.direct = direct;
66	mnt_args.mount_type = MOUNT_TYPE_MAP;	/* top-level autofs mount */
67
68	retried = false;
69	while (true) {
70		error = mount("autofs", mount_path,
71		    MNT_DONTBROWSE|MNT_AUTOMOUNTED, &mnt_args);
72		if (error == 0) {
73			break;
74		} else if (retried) {
75			perror("mount");
76			break;
77		} else {
78			retried = true;
79			(void)LoadAutoFS();
80		}
81	}
82
83	return (error == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
84}
85
86static int
87LoadAutoFS(void)
88{
89	pid_t pid, terminated_pid;
90	int result;
91	union wait status;
92
93	pid = fork();
94	if (pid == 0) {
95		result = execl(gKextLoadCommand, gKextLoadCommand, "-q", gKextLoadPath, NULL);
96		/* IF WE ARE HERE, WE WERE UNSUCCESSFUL */
97		return result ? result : ECHILD;
98	}
99
100	if (pid == -1) {
101		result = -1;
102		goto Err_Exit;
103	}
104
105	/* Success! Wait for completion in-line here */
106	while ( (terminated_pid = wait4(pid, (int *)&status, 0, NULL)) < 0 ) {
107		/* retry if EINTR, else break out with error */
108		if ( errno != EINTR ) {
109			break;
110		}
111	}
112
113	if ((terminated_pid == pid) && (WIFEXITED(status))) {
114		result = WEXITSTATUS(status);
115	} else {
116		result = -1;
117	}
118#if DEBUG_TRACE
119	syslog(LOG_INFO, "LoadAutoFS: result of fork / exec = %d.\n", result);
120#endif
121
122Err_Exit:
123	return result;
124}
125