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