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
mount_autofs(struct mapent * me,char * mntpnt,action_list * alp,char * rootp,char * subdir,char * key)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
process_opts(char * options,int * directp,int * sawnestp)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
free_autofs_args(autofs_args * p)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
free_mounta(struct mounta * m)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