xref: /illumos-gate/usr/src/cmd/fs.d/autofs/autod_autofs.c (revision 2a8d6eba033e4713ab12b61178f0513f1f075482)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  *	autod_autofs.c
23  *
24  *	Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25  *	Use is subject to license terms.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 #include <stdio.h>
31 #include <unistd.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34 #include <sys/param.h>
35 #include <sys/stat.h>
36 #include <sys/mntent.h>
37 #include <sys/mnttab.h>
38 #include <sys/mount.h>
39 #include <sys/utsname.h>
40 #include <sys/tiuser.h>
41 #include <syslog.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <fslib.h>
45 #include <sys/vfs.h>
46 #include <assert.h>
47 #include "automount.h"
48 
49 static int process_opts(char *options, int *directp, int *sawnestp);
50 void netbuf_free(struct netbuf *);
51 
52 int
53 mount_autofs(
54 	struct mapent *me,
55 	char *mntpnt,
56 	action_list *alp,
57 	char *rootp,
58 	char *subdir,
59 	char *key
60 )
61 {
62 	int mntflags = 0;
63 	struct utsname utsname;
64 	autofs_args *fnip = NULL;
65 	int mount_timeout = AUTOFS_MOUNT_TIMEOUT;
66 	int sawnest, len, error = 0;
67 	char *buf, rel_mntpnt[MAXPATHLEN];
68 
69 	if (trace > 1)
70 		trace_prt(1, "  mount_autofs %s on %s\n",
71 		me->map_fs->mfs_dir, mntpnt);
72 
73 	if (strcmp(mntpnt, "/-") == 0) {
74 		syslog(LOG_ERR, "invalid mountpoint: /-");
75 		return (ENOENT);
76 	}
77 
78 	/*
79 	 * get relative mountpoint
80 	 */
81 	sprintf(rel_mntpnt, ".%s", mntpnt+strlen(rootp));
82 
83 	if (trace > 2)
84 		trace_prt(1, "rel_mntpnt = %s\n", rel_mntpnt);
85 
86 	if (uname(&utsname) < 0) {
87 		error = errno;
88 		syslog(LOG_ERR, "uname %s", strerror(error));
89 		return (error);
90 	}
91 
92 	if ((fnip = (autofs_args *)
93 	    malloc(sizeof (autofs_args))) == NULL) {
94 		goto free_mem;
95 	}
96 	(void) memset((void *) fnip, 0, sizeof (*fnip));
97 
98 	if ((fnip->addr.buf = (char *)malloc(MAXADDRLEN)) == NULL)
99 		goto free_mem;
100 
101 	(void) strcpy(fnip->addr.buf, utsname.nodename);
102 	(void) strcat(fnip->addr.buf, ".autofs");
103 
104 	if ((fnip->opts = malloc(MAX_MNTOPT_STR)) == NULL)
105 		goto free_mem;
106 	strcpy(fnip->opts, me->map_mntopts);
107 
108 	if (process_opts(fnip->opts, &fnip->direct, &sawnest) != 0)
109 		goto free_mem;
110 
111 	fnip->addr.len = strlen(fnip->addr.buf);
112 	fnip->addr.maxlen = fnip->addr.len;
113 
114 	/*
115 	 * get absolute mountpoint
116 	 */
117 	if ((fnip->path = strdup(mntpnt)) == NULL)
118 		goto free_mem;
119 	if ((fnip->map = strdup(me->map_fs->mfs_dir)) == NULL)
120 		goto free_mem;
121 	if ((fnip->subdir = strdup(subdir)) == NULL)
122 		goto free_mem;
123 
124 	/*
125 	 * This timeout is really ignored by autofs, it uses the
126 	 * parent directory's timeout since it's really the one
127 	 * specified/inherited from the original mount by 'automount'
128 	 */
129 	fnip->mount_to = mount_timeout;	/* IGNORED */
130 	fnip->rpc_to = AUTOFS_RPC_TIMEOUT;
131 
132 	if (fnip->direct) {
133 		if (me->map_modified == TRUE || me->map_faked == TRUE) {
134 			if ((fnip->key = strdup(key)) == NULL)
135 				goto free_mem;
136 		} else {
137 			/* wierd case of a direct map pointer in another map */
138 			if ((fnip->key = strdup(fnip->path)) == NULL)
139 				goto free_mem;
140 		}
141 	} else {
142 		fnip->key = NULL;
143 	}
144 
145 	/*
146 	 * Fill out action list.
147 	 */
148 	alp->action.action = AUTOFS_MOUNT_RQ;
149 	if ((alp->action.action_list_entry_u.mounta.spec =
150 	    strdup(me->map_fs->mfs_dir)) == NULL)
151 		goto free_mem;
152 	if ((alp->action.action_list_entry_u.mounta.dir =
153 	    strdup(rel_mntpnt)) == NULL)
154 		goto free_mem;
155 
156 	len = strlen(fnip->opts);
157 	/*
158 	 * Get a buffer for the option string, it holds the map options plus
159 	 * space for "nest" if it isn't already in the option string
160 	 */
161 	if ((buf = (char *)malloc(MAX_MNTOPT_STR)) == NULL)
162 		goto free_mem;
163 	strcpy(buf, fnip->opts);
164 	if (!sawnest) {
165 		if (len + strlen(",nest") + 1 > MAX_MNTOPT_STR)
166 			goto free_mem;
167 		if (len)
168 			(void) strcat(buf, ",");
169 		(void) strcat(buf, "nest");
170 	}
171 	alp->action.action_list_entry_u.mounta.optptr = buf;
172 	alp->action.action_list_entry_u.mounta.optlen = strlen(buf) + 1;
173 	alp->action.action_list_entry_u.mounta.flags =
174 		mntflags | MS_DATA | MS_OPTIONSTR;
175 	if ((alp->action.action_list_entry_u.mounta.fstype =
176 	    strdup(MNTTYPE_AUTOFS)) == NULL)
177 		goto free_mem;
178 	alp->action.action_list_entry_u.mounta.dataptr = (char *)fnip;
179 	alp->action.action_list_entry_u.mounta.datalen = sizeof (*fnip);
180 
181 	return (0);
182 
183 free_mem:
184 	/*
185 	 * We got an error, free the memory we allocated.
186 	 */
187 	syslog(LOG_ERR, "mount_autofs: memory allocation failure");
188 	free_autofs_args(fnip);
189 	alp->action.action_list_entry_u.mounta.dataptr = NULL;
190 	alp->action.action_list_entry_u.mounta.datalen = 0;
191 	free_mounta(&alp->action.action_list_entry_u.mounta);
192 
193 	return (error ? error : ENOMEM);
194 }
195 
196 /*
197  * Set *directp to 1 if "direct" is found, and 0 otherwise
198  * (mounts are indirect by default).  If both "direct" and "indirect" are
199  * found, the last one wins.
200  */
201 static int
202 process_opts(char *options, int *directp, int *sawnestp)
203 {
204 	char *opt, *opts, *lasts;
205 	char buf[AUTOFS_MAXOPTSLEN];
206 
207 	assert(strlen(options)+1 < AUTOFS_MAXOPTSLEN);
208 
209 	*sawnestp = 0;
210 	strcpy(buf, options);
211 	opts = buf;
212 	options[0] = '\0';
213 	*directp = 0;
214 
215 	while ((opt = strtok_r(opts, ",", &lasts)) != NULL) {
216 		opts = NULL;
217 		while (isspace(*opt)) {
218 			opt++;
219 		}
220 		if (strcmp(opt, "direct") == 0) {
221 			*directp = 1;
222 		} else if (strcmp(opt, "indirect") == 0) {
223 			*directp = 0;
224 		} else if (strcmp(opt, "ignore") != 0) {
225 			if (strcmp(opt, "nest") == 0) {
226 				*sawnestp = 1;
227 			}
228 			if (options[0] != '\0') {
229 				(void) strcat(options, ",");
230 			}
231 			(void) strcat(options, opt);
232 		}
233 	};
234 	return (0);
235 }
236 
237 /*
238  * Free autofs_args structure
239  */
240 void
241 free_autofs_args(autofs_args *p)
242 {
243 	if (p == NULL)
244 		return;
245 	if (p->addr.buf)
246 		free(p->addr.buf);
247 	if (p->path)
248 		free(p->path);
249 	if (p->opts)
250 		free(p->opts);
251 	if (p->map)
252 		free(p->map);
253 	if (p->subdir)
254 		free(p->subdir);
255 	if (p->key)
256 		free(p->key);
257 	free(p);
258 }
259 
260 /*
261  * free mounta structure. Assumes that m->dataptr has
262  * been freed already
263  */
264 void
265 free_mounta(struct mounta *m)
266 {
267 	if (m == NULL)
268 		return;
269 	if (m->spec)
270 		free(m->spec);
271 	if (m->dir)
272 		free(m->dir);
273 	if (m->fstype)
274 		free(m->fstype);
275 	if (m->optptr)
276 		free(m->optptr);
277 	assert(m->dataptr == NULL);
278 	assert(m->datalen == 0);
279 	/*
280 	 * no need to free 'm' since it is part of the
281 	 * action_list_entry structure.
282 	 */
283 }
284