Print this page
6198 Let's EOL cachefs
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/fs.d/autofs/autod_parse.c
+++ new/usr/src/cmd/fs.d/autofs/autod_parse.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * autod_parse.c
23 23 *
24 24 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
25 25 * Use is subject to license terms.
26 + * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
26 27 */
27 28
28 29 #include <stdio.h>
29 30 #include <ctype.h>
30 31 #include <string.h>
31 32 #include <syslog.h>
32 33 #include <sys/types.h>
33 34 #include <sys/stat.h>
34 35 #include <sys/param.h>
35 36 #include <errno.h>
36 37 #include <pwd.h>
37 38 #include <netinet/in.h>
38 39 #include <netdb.h>
39 40 #include <sys/tiuser.h>
40 41 #include <locale.h>
41 42 #include <stdlib.h>
42 43 #include <unistd.h>
43 44 #include <thread.h>
44 45 #include <rpc/rpc.h>
45 46 #include <rpcsvc/mount.h>
46 47 #include <fcntl.h>
47 48 #include <limits.h>
48 49 #include "automount.h"
49 50
50 51 /*
51 52 * This structure is used to determine the hierarchical
52 53 * relationship between directories
53 54 */
54 55 typedef struct _hiernode {
55 56 char dirname[MAXFILENAMELEN+1];
56 57 struct _hiernode *subdir;
57 58 struct _hiernode *leveldir;
58 59 struct mapent *mapent;
59 60 } hiernode;
60 61
61 62 void free_mapent(struct mapent *);
62 63
63 64 static int mapline_to_mapent(struct mapent **, struct mapline *, char *, char *,
64 65 char *, char *, uint_t);
65 66 static int hierarchical_sort(struct mapent *, hiernode **, char *, char *);
66 67 static int push_options(hiernode *, char *, char *, int);
67 68 static int set_mapent_opts(struct mapent *, char *, char *, char *);
68 69 static void get_opts(char *, char *, char *, bool_t *);
69 70 static int fstype_opts(struct mapent *, char *, char *, char *);
70 71 static int modify_mapents(struct mapent **, char *, char *, char *, hiernode *,
71 72 char *, uint_t, bool_t);
72 73 static int set_and_fake_mapent_mntlevel(hiernode *, char *, char *, char *,
73 74 struct mapent **, uint_t, char *, bool_t);
74 75 static int mark_level1_root(hiernode *, char *);
75 76 static int mark_and_fake_level1_noroot(hiernode *, char *, char *, char *,
76 77 struct mapent **, uint_t i, char *);
77 78 static int convert_mapent_to_automount(struct mapent *, char *, char *);
78 79 static int automount_opts(char **, char *);
79 80 static int parse_fsinfo(char *, struct mapent *);
80 81 static int parse_nfs(char *, struct mapent *, char *, char *, char **, char **,
81 82 int);
82 83 static int parse_special(struct mapent *, char *, char *, char **, char **,
83 84 int);
84 85 static int get_dir_from_path(char *, char **, int);
85 86 static int alloc_hiernode(hiernode **, char *);
86 87 static void free_hiernode(hiernode *);
87 88 static void trace_mapents(char *, struct mapent *);
88 89 static void trace_hierarchy(hiernode *, int);
89 90 static struct mapent *do_mapent_hosts(char *, char *, uint_t);
90 91 static void freeex_ent(struct exportnode *);
91 92 static void freeex(struct exportnode *);
92 93 static void dump_mapent_err(struct mapent *, char *, char *);
93 94
94 95 #define PARSE_OK 0
95 96 #define PARSE_ERROR -1
96 97 #define MAX_FSLEN 32
97 98
98 99 /*
99 100 * mapentry error type defininitions
100 101 */
101 102 #define MAPENT_NOERR 0
102 103 #define MAPENT_UATFS 1
103 104
104 105 /*
105 106 * parse_entry(char *key, char *mapname, char *mapopts, struct mapline *ml,
106 107 * char *subdir, uint_t isdirect, bool_t mount_access)
107 108 * Parses the data in ml to build a mapentry list containing the information
108 109 * for the mounts/lookups to be performed. Builds an intermediate mapentry list
109 110 * by processing ml, hierarchically sorts (builds a tree of) the list according
110 111 * to mountpoint. Then pushes options down the hierarchy, and fills in the mount
111 112 * file system. Finally, modifies the intermediate list depending on how far
112 113 * in the hierarchy the current request is (uses subdir). Deals with special
113 114 * case of /net map parsing.
114 115 * Returns a pointer to the head of the mapentry list.
115 116 */
116 117 struct mapent *
117 118 parse_entry(char *key, char *mapname, char *mapopts, struct mapline *ml,
118 119 char *subdir, uint_t isdirect, bool_t mount_access)
119 120 {
120 121 char *p;
121 122 char defaultopts[AUTOFS_MAXOPTSLEN];
122 123
123 124 struct mapent *mapents = NULL;
124 125 hiernode *rootnode = NULL;
125 126 char *lp = ml->linebuf;
126 127
127 128 if (trace > 1)
128 129 trace_prt(1, " mapline: %s\n", ml->linebuf);
129 130
130 131 /*
131 132 * Assure the key is only one token long.
132 133 * This prevents options from sneaking in through the
133 134 * command line or corruption of /etc/mnttab.
134 135 */
135 136 for (p = key; *p != '\0'; p++) {
136 137 if (isspace(*p)) {
137 138 syslog(LOG_ERR,
138 139 "parse_entry: bad key in map %s: %s", mapname, key);
139 140 return ((struct mapent *)NULL);
140 141 }
141 142 }
142 143
143 144 /*
144 145 * select the appropriate parser, and build the mapentry list
145 146 */
146 147 if (strcmp(lp, "-hosts") == 0) {
147 148 /*
148 149 * the /net parser - uses do_mapent_hosts to build mapents.
149 150 * The mapopts are considered default for every entry, so we
150 151 * don't push options down hierarchies.
151 152 */
152 153 mapents = do_mapent_hosts(mapopts, key, isdirect);
153 154 if (mapents == NULL) /* nothing to free */
154 155 return (mapents);
155 156
156 157 if (trace > 3)
157 158 trace_mapents("do_mapent_hosts:(return)", mapents);
158 159
159 160 if (hierarchical_sort(mapents, &rootnode, key, mapname)
160 161 != PARSE_OK)
161 162 goto parse_error;
162 163 } else {
163 164 /*
164 165 * all other parsing
165 166 */
166 167 if (mapline_to_mapent(&mapents, ml, key, mapname,
167 168 mapopts, defaultopts, isdirect) != PARSE_OK)
168 169 goto parse_error;
169 170
170 171 if (mapents == NULL)
171 172 return (mapents);
172 173
173 174 if (hierarchical_sort(mapents, &rootnode, key, mapname)
174 175 != PARSE_OK)
175 176 goto parse_error;
176 177
177 178 if (push_options(rootnode, defaultopts, mapopts,
178 179 MAPENT_NOERR) != PARSE_OK)
179 180 goto parse_error;
180 181
181 182 if (trace > 3) {
182 183 trace_prt(1, "\n\tpush_options (return)\n");
183 184 trace_prt(0, "\tdefault options=%s\n", defaultopts);
184 185 trace_hierarchy(rootnode, 0);
185 186 };
186 187
187 188 if (parse_fsinfo(mapname, mapents) != PARSE_OK)
188 189 goto parse_error;
189 190 }
190 191
191 192 /*
192 193 * Modify the mapentry list. We *must* do this only after
193 194 * the mapentry list is completely built (since we need to
194 195 * have parse_fsinfo called first).
195 196 */
196 197 if (modify_mapents(&mapents, mapname, mapopts, subdir,
197 198 rootnode, key, isdirect, mount_access) != PARSE_OK)
198 199 goto parse_error;
199 200
200 201 /*
201 202 * XXX: its dangerous to use rootnode after modify mapents as
202 203 * it may be pointing to mapents that have been freed
203 204 */
204 205 if (rootnode != NULL)
205 206 free_hiernode(rootnode);
206 207
207 208 return (mapents);
208 209
209 210 parse_error:
210 211 syslog(LOG_ERR, "parse_entry: mapentry parse error: map=%s key=%s",
211 212 mapname, key);
212 213 free_mapent(mapents);
213 214 if (rootnode != NULL)
214 215 free_hiernode(rootnode);
215 216 return ((struct mapent *)NULL);
216 217 }
217 218
218 219
219 220 /*
220 221 * mapline_to_mapent(struct mapent **mapents, struct mapline *ml,
221 222 * char *key, char *mapname, char *mapopts, char *defaultopts,
222 223 * uint_t isdirect)
223 224 * Parses the mapline information in ml word by word to build an intermediate
224 225 * mapentry list, which is passed back to the caller. The mapentries may have
225 226 * holes (example no options), as they are completed only later. The logic is
226 227 * awkward, but needed to provide the supported flexibility in the map entries.
227 228 * (especially the first line). Note that the key is the full pathname of the
228 229 * directory to be mounted in a direct map, and ml is the mapentry beyond key.
229 230 * Returns PARSE_OK or an appropriate error value.
230 231 */
231 232 static int
232 233 mapline_to_mapent(struct mapent **mapents, struct mapline *ml, char *key,
233 234 char *mapname, char *mapopts, char *defaultopts,
234 235 uint_t isdirect)
235 236 {
236 237 struct mapent *me = NULL;
237 238 struct mapent *mp;
238 239 char w[MAXPATHLEN];
239 240 char wq[MAXPATHLEN];
240 241 char w1[MAXPATHLEN];
241 242 int implied;
242 243
243 244 char *lp = ml->linebuf;
244 245 char *lq = ml->lineqbuf;
245 246
246 247 /* do any macro expansions that are required to complete ml */
247 248 if (macro_expand(key, lp, lq, LINESZ)) {
248 249 syslog(LOG_ERR,
249 250 "mapline_to_mapent: map %s: line too long (max %d chars)",
250 251 mapname, LINESZ - 1);
251 252 return (PARSE_ERROR);
252 253 }
253 254 if (trace > 3 && (strcmp(ml->linebuf, lp) != 0))
254 255 trace_prt(1,
255 256 " mapline_to_mapent: (expanded) mapline (%s,%s)\n",
256 257 ml->linebuf, ml->lineqbuf);
257 258
258 259 /* init the head of mapentry list to null */
259 260 *mapents = NULL;
260 261
261 262 /*
262 263 * Get the first word - its either a '-' if default options provided,
263 264 * a '/', if the mountroot is implicitly provided, or a mount filesystem
264 265 * if the mountroot is implicit. Note that if the first word begins with
265 266 * a '-' then the second must be read and it must be a mountpoint or a
266 267 * mount filesystem. Use mapopts if no default opts are provided.
267 268 */
268 269 if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1)
269 270 return (PARSE_ERROR);
270 271 if (*w == '-') {
271 272 strcpy(defaultopts, w);
272 273 if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1)
273 274 return (PARSE_ERROR);
274 275 } else
275 276 strcpy(defaultopts, mapopts);
276 277
277 278 /*
278 279 * implied is true if there is no '/'
279 280 * We need the same code path if we have an smbfs mount.
280 281 */
281 282 implied = (*w != '/') || (strstr(defaultopts, "fstype=smbfs") != NULL);
282 283 while (*w == '/' || implied) {
283 284 mp = me;
284 285 if ((me = (struct mapent *)malloc(sizeof (*me))) == NULL)
285 286 goto alloc_failed;
286 287 (void) memset((char *)me, 0, sizeof (*me));
287 288 if (*mapents == NULL) /* special case of head */
288 289 *mapents = me;
289 290 else
290 291 mp->map_next = me;
291 292
292 293 /*
293 294 * direct maps get an empty string as root - to be filled
294 295 * by the entire path later. Indirect maps get /key as the
295 296 * map root. Note that xfn maps don't care about the root
296 297 * - they override it in getmapent_fn().
297 298 */
298 299 if (isdirect) {
299 300 *w1 = '\0';
300 301 } else {
301 302 strcpy(w1, "/");
302 303 strcat(w1, key);
303 304 }
304 305 if ((me->map_root = strdup(w1)) == NULL)
305 306 goto alloc_failed;
306 307
307 308 /* mntpnt is empty for the mount root */
308 309 if (strcmp(w, "/") == 0 || implied)
309 310 me->map_mntpnt = strdup("");
310 311 else
311 312 me->map_mntpnt = strdup(w);
312 313 if (me->map_mntpnt == NULL)
313 314 goto alloc_failed;
314 315
315 316 /*
316 317 * If implied, the word must be a mount filesystem,
317 318 * and its already read in; also turn off implied - its
318 319 * not applicable except for the mount root. Else,
319 320 * read another (or two) words depending on if there's
320 321 * an option.
321 322 */
322 323 if (implied) /* must be a mount filesystem */
323 324 implied = 0;
324 325 else {
325 326 if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1)
326 327 return (PARSE_ERROR);
327 328 if (w[0] == '-') {
328 329 /* mount options */
329 330 if ((me->map_mntopts = strdup(w)) == NULL)
330 331 goto alloc_failed;
331 332 if (getword(w, wq, &lp, &lq, ' ',
332 333 sizeof (w)) == -1)
333 334 return (PARSE_ERROR);
334 335 }
335 336 }
336 337
337 338 /*
338 339 * must be a mount filesystem or a set of filesystems at
339 340 * this point.
340 341 */
341 342 if (w[0] == '\0' || w[0] == '-') {
342 343 syslog(LOG_ERR,
343 344 "mapline_to_mapent: bad location=%s map=%s key=%s",
344 345 w, mapname, key);
345 346 return (PARSE_ERROR);
346 347 }
347 348
348 349 /*
349 350 * map_fsw and map_fswq hold information which will be
350 351 * used to determine filesystem information at a later
351 352 * point. This is required since we can only find out
352 353 * about the mount file system after the directories
353 354 * are hierarchically sorted and options have been pushed
354 355 * down the hierarchies.
355 356 */
356 357 if (((me->map_fsw = strdup(w)) == NULL) ||
357 358 ((me->map_fswq = strdup(wq)) == NULL))
358 359 goto alloc_failed;
359 360
360 361 /*
361 362 * the next word, if any, is either another mount point or a
362 363 * mount filesystem if more than one server is listed.
363 364 */
364 365 if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1)
365 366 return (PARSE_ERROR);
366 367 while (*w && *w != '/') { /* more than 1 server listed */
367 368 int len;
368 369 char *fsw, *fswq;
369 370 len = strlen(me->map_fsw) + strlen(w) + 4;
370 371 if ((fsw = (char *)malloc(len)) == NULL)
371 372 goto alloc_failed;
372 373 sprintf(fsw, "%s %s", me->map_fsw, w);
373 374 free(me->map_fsw);
374 375 me->map_fsw = fsw;
375 376 len = strlen(me->map_fswq) + strlen(wq) + 4;
376 377 if ((fswq = (char *)malloc(len)) == NULL)
377 378 goto alloc_failed;
378 379 sprintf(fswq, "%s %s", me->map_fswq, wq);
379 380 free(me->map_fswq);
380 381 me->map_fswq = fswq;
381 382 if (getword(w, wq, &lp, &lq, ' ', sizeof (w)) == -1)
382 383 return (PARSE_ERROR);
383 384 }
384 385
385 386 /* initialize flags */
386 387 me->map_mntlevel = -1;
387 388 me->map_modified = FALSE;
388 389 me->map_faked = FALSE;
389 390 me->map_err = MAPENT_NOERR;
390 391
391 392 me->map_next = NULL;
392 393 }
393 394
394 395 if (*mapents == NULL || w[0] != '\0') { /* sanity check */
395 396 if (verbose) {
396 397 if (*mapents == NULL)
397 398 syslog(LOG_ERR,
398 399 "mapline_to_mapent: parsed with null mapents");
399 400 else
400 401 syslog(LOG_ERR,
401 402 "mapline_to_mapent: parsed nononempty w=%s", w);
402 403 }
403 404 return (PARSE_ERROR);
404 405 }
405 406
406 407 if (trace > 3)
407 408 trace_mapents("mapline_to_mapent:", *mapents);
408 409
409 410 return (PARSE_OK);
410 411
411 412 alloc_failed:
412 413 syslog(LOG_ERR, "mapline_to_mapent: Memory allocation failed");
413 414 return (ENOMEM);
414 415 }
415 416
416 417 /*
417 418 * hierarchical_sort(struct mapent *mapents, hiernode **rootnode, char *key
418 419 * char *mapname)
419 420 * sorts the mntpnts in each mapent to build a hierarchy of nodes, with
420 421 * with the rootnode being the mount root. The hierarchy is setup as
421 422 * levels, and subdirs below each level. Provides a link from node to
422 423 * the relevant mapentry.
423 424 * Returns PARSE_OK or appropriate error value
424 425 */
425 426 static int
426 427 hierarchical_sort(struct mapent *mapents, hiernode **rootnode, char *key,
427 428 char *mapname)
428 429 {
429 430 hiernode *prevnode, *currnode, *newnode;
430 431 char *path;
431 432 char dirname[MAXFILENAMELEN];
432 433
433 434 int rc = PARSE_OK;
434 435 struct mapent *me = mapents;
435 436
436 437 /* allocate the rootnode with a default path of "" */
437 438 *rootnode = NULL;
438 439 if ((rc = alloc_hiernode(rootnode, "")) != PARSE_OK)
439 440 return (rc);
440 441
441 442 /*
442 443 * walk through mapents - for each mapent, locate the position
443 444 * within the hierarchy by walking across leveldirs, and
444 445 * subdirs of matched leveldirs. Starts one level below
445 446 * the root (assumes an implicit match with rootnode).
446 447 * XXX - this could probably be done more cleanly using recursion.
447 448 */
448 449 while (me != NULL) {
449 450
450 451 path = me->map_mntpnt;
451 452
452 453 if ((rc = get_dir_from_path(dirname, &path,
453 454 sizeof (dirname))) != PARSE_OK)
454 455 return (rc);
455 456
456 457 prevnode = *rootnode;
457 458 currnode = (*rootnode)->subdir;
458 459
459 460 while (dirname[0] != '\0') {
460 461 if (currnode != NULL) {
461 462 if (strcmp(currnode->dirname, dirname) == 0) {
462 463 /*
463 464 * match found - mntpnt is a child of
464 465 * this node
465 466 */
466 467 prevnode = currnode;
467 468 currnode = currnode->subdir;
468 469 } else {
469 470 prevnode = currnode;
470 471 currnode = currnode->leveldir;
471 472
472 473 if (currnode == NULL) {
473 474 /*
474 475 * No more leveldirs to match.
475 476 * Add a new one
476 477 */
477 478 if ((rc = alloc_hiernode
478 479 (&newnode, dirname))
479 480 != PARSE_OK)
480 481 return (rc);
481 482 prevnode->leveldir = newnode;
482 483 prevnode = newnode;
483 484 currnode = newnode->subdir;
484 485 } else {
485 486 /* try this leveldir */
486 487 continue;
487 488 }
488 489 }
489 490 } else {
490 491 /* no more subdirs to match. Add a new one */
491 492 if ((rc = alloc_hiernode(&newnode,
492 493 dirname)) != PARSE_OK)
493 494 return (rc);
494 495 prevnode->subdir = newnode;
495 496 prevnode = newnode;
496 497 currnode = newnode->subdir;
497 498 }
498 499 if ((rc = get_dir_from_path(dirname, &path,
499 500 sizeof (dirname))) != PARSE_OK)
500 501 return (rc);
501 502 }
502 503
503 504 if (prevnode->mapent != NULL) {
504 505 /* duplicate mntpoint found */
505 506 syslog(LOG_ERR,
506 507 "hierarchical_sort: duplicate mntpnt map=%s key=%s",
507 508 mapname, key);
508 509 return (PARSE_ERROR);
509 510 }
510 511
511 512 /* provide a pointer from node to mapent */
512 513 prevnode->mapent = me;
513 514 me = me->map_next;
514 515 }
515 516
516 517 if (trace > 3) {
517 518 trace_prt(1, "\n\thierarchical_sort:\n");
518 519 trace_hierarchy(*rootnode, 0); /* 0 is rootnode's level */
519 520 }
520 521
521 522 return (rc);
522 523 }
523 524
524 525 /*
525 526 * push_options(hiernode *node, char *opts, char *mapopts, int err)
526 527 * Pushes the options down a hierarchical structure. Works recursively from the
527 528 * root, which is passed in on the first call. Uses a replacement policy.
528 529 * If a node points to a mapentry, and it has an option, then thats the option
529 530 * for that mapentry. Else, the node's mapent inherits the option from the
530 531 * default (which may be the global option for the entry or mapopts).
531 532 * err is useful in flagging entries with errors in pushing options.
532 533 * returns PARSE_OK or appropriate error value.
533 534 */
534 535 static int
535 536 push_options(hiernode *node, char *defaultopts, char *mapopts, int err)
536 537 {
537 538 int rc = PARSE_OK;
538 539 struct mapent *me = NULL;
539 540
540 541 /* ensure that all the dirs at a level are passed the default options */
541 542 while (node != NULL) {
542 543 me = node->mapent;
543 544 if (me != NULL) { /* not all nodes point to a mapentry */
544 545 me->map_err = err;
545 546 if ((rc = set_mapent_opts(me, me->map_mntopts,
546 547 defaultopts, mapopts)) != PARSE_OK)
547 548 return (rc);
548 549 }
549 550
550 551 /* push the options to subdirs */
551 552 if (node->subdir != NULL) {
552 553 if (node->mapent && strcmp(node->mapent->map_fstype,
553 554 MNTTYPE_AUTOFS) == 0)
↓ open down ↓ |
518 lines elided |
↑ open up ↑ |
554 555 err = MAPENT_UATFS;
555 556 if ((rc = push_options(node->subdir, defaultopts,
556 557 mapopts, err)) != PARSE_OK)
557 558 return (rc);
558 559 }
559 560 node = node->leveldir;
560 561 }
561 562 return (rc);
562 563 }
563 564
564 -#define BACKFSTYPE "backfstype" /* used in cachefs options */
565 -#define BACKFSTYPE_EQ "backfstype="
566 565 #define FSTYPE "fstype"
567 566 #define FSTYPE_EQ "fstype="
568 567 #define NO_OPTS ""
569 568
570 569 /*
571 570 * set_mapent_opts(struct mapent *me, char *opts, char *defaultopts,
572 571 * char *mapopts)
573 572 * sets the mapentry's options, fstype and mounter fields by separating
574 573 * out the fstype part from the opts. Use default options if opts is NULL.
575 574 * Note taht defaultopts may be the same as mapopts.
576 575 * Returns PARSE_OK or appropriate error value.
577 576 */
578 577 static int
579 578 set_mapent_opts(struct mapent *me, char *opts, char *defaultopts,
580 579 char *mapopts)
581 580 {
582 581 char entryopts[AUTOFS_MAXOPTSLEN];
583 582 char fstype[MAX_FSLEN], mounter[MAX_FSLEN];
584 583 int rc = PARSE_OK;
585 584 bool_t fstype_opt = FALSE;
586 585
587 586 strcpy(fstype, MNTTYPE_NFS); /* default */
588 587
589 588 /* set options to default options, if none exist for this entry */
590 589 if (opts == NULL) {
591 590 opts = defaultopts;
592 591 if (defaultopts == NULL) { /* NULL opts for entry */
593 592 strcpy(mounter, fstype);
594 593 goto done;
595 594 }
596 595 }
597 596 if (*opts == '-')
598 597 opts++;
599 598
600 599 /* separate opts into fstype and (other) entrypopts */
↓ open down ↓ |
25 lines elided |
↑ open up ↑ |
601 600 get_opts(opts, entryopts, fstype, &fstype_opt);
602 601
603 602 /* replace any existing opts */
604 603 if (me->map_mntopts != NULL)
605 604 free(me->map_mntopts);
606 605 if ((me->map_mntopts = strdup(entryopts)) == NULL)
607 606 return (ENOMEM);
608 607 strcpy(mounter, fstype);
609 608
610 609 /*
611 - * The following ugly chunk of code crept in as a result of
612 - * cachefs. If it's a cachefs mount of an nfs filesystem, then
613 - * it's important to parse the nfs special field. Otherwise,
614 - * just hand the special field to the fs-specific mount
615 - */
616 - if (strcmp(fstype, MNTTYPE_CACHEFS) == 0) {
617 - struct mnttab m;
618 - char *p;
619 -
620 - m.mnt_mntopts = entryopts;
621 - if ((p = hasmntopt(&m, BACKFSTYPE)) != NULL) {
622 - int len = strlen(MNTTYPE_NFS);
623 -
624 - p += strlen(BACKFSTYPE_EQ);
625 -
626 - if (strncmp(p, MNTTYPE_NFS, len) == 0 &&
627 - (p[len] == '\0' || p[len] == ',')) {
628 - /*
629 - * Cached nfs mount
630 - */
631 - (void) strcpy(fstype, MNTTYPE_NFS);
632 - (void) strcpy(mounter, MNTTYPE_CACHEFS);
633 - }
634 - }
635 - }
636 -
637 - /*
638 610 * child options are exactly fstype = somefs, we need to do some
639 611 * more option pushing work.
640 612 */
641 613 if (fstype_opt == TRUE &&
642 614 (strcmp(me->map_mntopts, NO_OPTS) == 0)) {
643 615 free(me->map_mntopts);
644 616 if ((rc = fstype_opts(me, opts, defaultopts,
645 617 mapopts)) != PARSE_OK)
646 618 return (rc);
647 619 }
648 620
649 621 done:
650 622 if (((me->map_fstype = strdup(fstype)) == NULL) ||
651 623 ((me->map_mounter = strdup(mounter)) == NULL)) {
652 624 if (me->map_fstype != NULL)
653 625 free(me->map_fstype);
654 626 syslog(LOG_ERR, "set_mapent_opts: No memory");
655 627 return (ENOMEM);
656 628 }
↓ open down ↓ |
9 lines elided |
↑ open up ↑ |
657 629
658 630 return (rc);
659 631 }
660 632
661 633 /*
662 634 * Check the option string for an "fstype"
663 635 * option. If found, return the fstype
664 636 * and the option string with the fstype
665 637 * option removed, e.g.
666 638 *
667 - * input: "fstype=cachefs,ro,nosuid"
639 + * input: "fstype=nfs,ro,nosuid"
668 640 * opts: "ro,nosuid"
669 - * fstype: "cachefs"
641 + * fstype: "nfs"
670 642 *
671 643 * Also indicates if the fstype option was present
672 644 * by setting a flag, if the pointer to the flag
673 645 * is not NULL.
674 646 */
675 647 static void
676 648 get_opts(input, opts, fstype, fstype_opt)
677 649 char *input;
678 650 char *opts; /* output */
679 651 char *fstype; /* output */
680 652 bool_t *fstype_opt;
681 653 {
682 654 char *p, *pb;
683 655 char buf[MAXOPTSLEN];
684 656 char *placeholder;
685 657
686 658 *opts = '\0';
687 659 (void) strcpy(buf, input);
688 660 pb = buf;
689 661 while (p = (char *)strtok_r(pb, ",", &placeholder)) {
690 662 pb = NULL;
691 663 if (strncmp(p, FSTYPE_EQ, 7) == 0) {
692 664 if (fstype_opt != NULL)
693 665 *fstype_opt = TRUE;
694 666 (void) strcpy(fstype, p + 7);
695 667 } else {
696 668 if (*opts)
697 669 (void) strcat(opts, ",");
698 670 (void) strcat(opts, p);
699 671 }
700 672 }
701 673 }
702 674
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
703 675 /*
704 676 * fstype_opts(struct mapent *me, char *opts, char *defaultopts,
705 677 * char *mapopts)
706 678 * We need to push global options to the child entry if it is exactly
707 679 * fstype=somefs.
708 680 */
709 681 static int
710 682 fstype_opts(struct mapent *me, char *opts, char *defaultopts,
711 683 char *mapopts)
712 684 {
713 - char pushopts[AUTOFS_MAXOPTSLEN];
714 685 char pushentryopts[AUTOFS_MAXOPTSLEN];
715 686 char pushfstype[MAX_FSLEN];
716 687
717 688 if (defaultopts && *defaultopts == '-')
718 689 defaultopts++;
719 690
720 691 /*
721 692 * the options to push are the global defaults for the entry,
722 693 * if they exist, or mapopts, if the global defaults for the
723 694 * entry does not exist.
724 695 */
725 696 if (strcmp(defaultopts, opts) == 0) {
726 697 if (*mapopts == '-')
727 698 mapopts++;
728 699 get_opts(mapopts, pushentryopts, pushfstype, NULL);
729 - strcpy(pushopts, mapopts);
730 700 } else {
731 701 get_opts(defaultopts, pushentryopts, pushfstype, NULL);
732 - strcpy(pushopts, defaultopts);
733 702 }
734 703
735 - if (strcmp(pushfstype, MNTTYPE_CACHEFS) == 0)
736 - me->map_mntopts = strdup(pushopts);
737 - else
738 - me->map_mntopts = strdup(pushentryopts);
704 + me->map_mntopts = strdup(pushentryopts);
739 705
740 706 if (!me->map_mntopts) {
741 707 syslog(LOG_ERR, "fstype_opts: No memory");
742 708 return (ENOMEM);
743 709 }
744 710
745 711 return (PARSE_OK);
746 712 }
747 713
748 714 /*
749 715 * modify_mapents(struct mapent **mapents, char *mapname,
750 716 * char *mapopts, char *subdir, hiernode *rootnode,
751 717 * char *key, uint_t isdirect, bool_t mount_access)
752 718 * modifies the intermediate mapentry list into the final one, and passes
753 719 * back a pointer to it. The final list may contain faked mapentries for
754 720 * hiernodes that do not point to a mapentry, or converted mapentries, if
755 721 * hiernodes that point to a mapentry need to be converted from nfs to autofs.
756 722 * mounts. Entries that are not directly 1 level below the subdir are removed.
757 723 * Returns PARSE_OK or PARSE_ERROR
758 724 */
759 725 static int
760 726 modify_mapents(struct mapent **mapents, char *mapname,
761 727 char *mapopts, char *subdir, hiernode *rootnode,
762 728 char *key, uint_t isdirect, bool_t mount_access)
763 729 {
764 730 struct mapent *mp = NULL;
765 731 char w[MAXPATHLEN];
766 732
767 733 struct mapent *me;
768 734 int rc = PARSE_OK;
769 735 struct mapent *faked_mapents = NULL;
770 736
771 737 /*
772 738 * correct the mapentry mntlevel from default -1 to level depending on
773 739 * position in hierarchy, and build any faked mapentries, if required
774 740 * at one level below the rootnode given by subdir.
775 741 */
776 742 if ((rc = set_and_fake_mapent_mntlevel(rootnode, subdir, key, mapname,
777 743 &faked_mapents, isdirect, mapopts, mount_access)) != PARSE_OK)
778 744 return (rc);
779 745
780 746 /*
781 747 * attaches faked mapents to real mapents list. Assumes mapents
782 748 * is not NULL.
783 749 */
784 750 me = *mapents;
785 751 while (me->map_next != NULL)
786 752 me = me->map_next;
787 753 me->map_next = faked_mapents;
788 754
789 755 /*
790 756 * get rid of nodes marked at level -1
791 757 */
792 758 me = *mapents;
793 759 while (me != NULL) {
794 760 if ((me->map_mntlevel == -1) || (me->map_err) ||
795 761 (mount_access == FALSE && me->map_mntlevel == 0)) {
796 762 /*
797 763 * syslog any errors and free entry
798 764 */
799 765 if (me->map_err)
800 766 dump_mapent_err(me, key, mapname);
801 767
802 768 if (me == (*mapents)) {
803 769 /* special case when head has to be freed */
804 770 *mapents = me->map_next;
805 771 if ((*mapents) == NULL) {
806 772 /* something wierd happened */
807 773 if (verbose)
808 774 syslog(LOG_ERR,
809 775 "modify_mapents: level error");
810 776 return (PARSE_ERROR);
811 777 }
812 778
813 779 /* separate out the node */
814 780 me->map_next = NULL;
815 781 free_mapent(me);
816 782 me = *mapents;
817 783 } else {
818 784 mp->map_next = me->map_next;
819 785 me->map_next = NULL;
820 786 free_mapent(me);
821 787 me = mp->map_next;
822 788 }
823 789 continue;
824 790 }
825 791
826 792 /*
827 793 * convert level 1 mapents that are not already autonodes
828 794 * to autonodes
829 795 */
830 796 if (me->map_mntlevel == 1 &&
831 797 (strcmp(me->map_fstype, MNTTYPE_AUTOFS) != 0) &&
832 798 (me->map_faked != TRUE)) {
833 799 if ((rc = convert_mapent_to_automount(me, mapname,
834 800 mapopts)) != PARSE_OK)
835 801 return (rc);
836 802 }
837 803 strcpy(w, (me->map_mntpnt+strlen(subdir)));
838 804 strcpy(me->map_mntpnt, w);
839 805 mp = me;
840 806 me = me->map_next;
841 807 }
842 808
843 809 if (trace > 3)
844 810 trace_mapents("modify_mapents:", *mapents);
845 811
846 812 return (PARSE_OK);
847 813 }
848 814
849 815 /*
850 816 * set_and_fake_mapent_mntlevel(hiernode *rootnode, char *subdir, char *key,
851 817 * char *mapname, struct mapent **faked_mapents,
852 818 * uint_t isdirect, char *mapopts, bool_t mount_access)
853 819 * sets the mapentry mount levels (depths) with respect to the subdir.
854 820 * Assigns a value of 0 to the new root. Finds the level1 directories by
855 821 * calling mark_*_level1_*(). Also cleans off extra /'s in level0 and
856 822 * level1 map_mntpnts. Note that one level below the new root is an existing
857 823 * mapentry if there's a mapentry (nfs mount) corresponding to the root,
858 824 * and the direct subdir set for the root, if there's no mapentry corresponding
859 825 * to the root (we install autodirs). Returns PARSE_OK or error value.
860 826 */
861 827 static int
862 828 set_and_fake_mapent_mntlevel(hiernode *rootnode, char *subdir, char *key,
863 829 char *mapname, struct mapent **faked_mapents,
864 830 uint_t isdirect, char *mapopts, bool_t mount_access)
865 831 {
866 832 char dirname[MAXFILENAMELEN];
867 833 char traversed_path[MAXPATHLEN]; /* used in building fake mapentries */
868 834
869 835 char *subdir_child = subdir;
870 836 hiernode *prevnode = rootnode;
871 837 hiernode *currnode = rootnode->subdir;
872 838 int rc = PARSE_OK;
873 839 traversed_path[0] = '\0';
874 840
875 841 /*
876 842 * find and mark the root by tracing down subdir. Use traversed_path
877 843 * to keep track of how far we go, while guaranteeing that it
878 844 * contains no '/' at the end. Took some mucking to get that right.
879 845 */
880 846 if ((rc = get_dir_from_path(dirname, &subdir_child, sizeof (dirname)))
881 847 != PARSE_OK)
882 848 return (rc);
883 849
884 850 if (dirname[0] != '\0')
885 851 sprintf(traversed_path, "%s/%s", traversed_path, dirname);
886 852
887 853 prevnode = rootnode;
888 854 currnode = rootnode->subdir;
889 855 while (dirname[0] != '\0' && currnode != NULL) {
890 856 if (strcmp(currnode->dirname, dirname) == 0) {
891 857
892 858 /* subdir is a child of currnode */
893 859 prevnode = currnode;
894 860 currnode = currnode->subdir;
895 861
896 862 if ((rc = get_dir_from_path(dirname, &subdir_child,
897 863 sizeof (dirname))) != PARSE_OK)
898 864 return (rc);
899 865 if (dirname[0] != '\0')
900 866 sprintf(traversed_path, "%s/%s",
901 867 traversed_path, dirname);
902 868
903 869 } else {
904 870 /* try next leveldir */
905 871 prevnode = currnode;
906 872 currnode = currnode->leveldir;
907 873 }
908 874 }
909 875
910 876 if (dirname[0] != '\0') {
911 877 if (verbose)
912 878 syslog(LOG_ERR,
913 879 "set_and_fake_mapent_mntlevel: subdir=%s error: map=%s",
914 880 subdir, mapname);
915 881 return (PARSE_ERROR);
916 882 }
917 883
918 884 /*
919 885 * see if level of root really points to a mapent and if
920 886 * have access to that filessystem - call appropriate
921 887 * routine to mark level 1 nodes, and build faked entries
922 888 */
923 889 if (prevnode->mapent != NULL && mount_access == TRUE) {
924 890 if (trace > 3)
925 891 trace_prt(1, " node mountpoint %s\t travpath=%s\n",
926 892 prevnode->mapent->map_mntpnt, traversed_path);
927 893
928 894 /*
929 895 * Copy traversed path map_mntpnt to get rid of any extra
930 896 * '/' the map entry may contain.
931 897 */
932 898 if (strlen(prevnode->mapent->map_mntpnt) <
933 899 strlen(traversed_path)) { /* sanity check */
934 900 if (verbose)
935 901 syslog(LOG_ERR,
936 902 "set_and_fake_mapent_mntlevel: path=%s error",
937 903 traversed_path);
938 904 return (PARSE_ERROR);
939 905 }
940 906 if (strcmp(prevnode->mapent->map_mntpnt, traversed_path) != 0)
941 907 strcpy(prevnode->mapent->map_mntpnt, traversed_path);
942 908
943 909 prevnode->mapent->map_mntlevel = 0; /* root level is 0 */
944 910 if (currnode != NULL) {
945 911 if ((rc = mark_level1_root(currnode,
946 912 traversed_path)) != PARSE_OK)
947 913 return (rc);
948 914 }
949 915 } else if (currnode != NULL) {
950 916 if (trace > 3)
951 917 trace_prt(1, " No rootnode, travpath=%s\n",
952 918 traversed_path);
953 919 if ((rc = mark_and_fake_level1_noroot(currnode,
954 920 traversed_path, key, mapname, faked_mapents, isdirect,
955 921 mapopts)) != PARSE_OK)
956 922 return (rc);
957 923 }
958 924
959 925 if (trace > 3) {
960 926 trace_prt(1, "\n\tset_and_fake_mapent_mntlevel\n");
961 927 trace_hierarchy(rootnode, 0);
962 928 }
963 929
964 930 return (rc);
965 931 }
966 932
967 933
968 934 /*
969 935 * mark_level1_root(hiernode *node, char *traversed_path)
970 936 * marks nodes upto one level below the rootnode given by subdir
971 937 * recursively. Called if rootnode points to a mapent.
972 938 * In this routine, a level 1 node is considered to be the 1st existing
973 939 * mapentry below the root node, so there's no faking involved.
974 940 * Returns PARSE_OK or error value
975 941 */
976 942 static int
977 943 mark_level1_root(hiernode *node, char *traversed_path)
978 944 {
979 945 /* ensure we touch all leveldirs */
980 946 while (node) {
981 947 /*
982 948 * mark node level as 1, if one exists - else walk down
983 949 * subdirs until we find one.
984 950 */
985 951 if (node->mapent == NULL) {
986 952 char w[MAXPATHLEN];
987 953
988 954 if (node->subdir != NULL) {
989 955 sprintf(w, "%s/%s", traversed_path,
990 956 node->dirname);
991 957 if (mark_level1_root(node->subdir, w)
992 958 == PARSE_ERROR)
993 959 return (PARSE_ERROR);
994 960 } else {
995 961 if (verbose) {
996 962 syslog(LOG_ERR,
997 963 "mark_level1_root: hierarchy error");
998 964 }
999 965 return (PARSE_ERROR);
1000 966 }
1001 967 } else {
1002 968 char w[MAXPATHLEN];
1003 969
1004 970 sprintf(w, "%s/%s", traversed_path, node->dirname);
1005 971 if (trace > 3)
1006 972 trace_prt(1, " node mntpnt %s\t travpath %s\n",
1007 973 node->mapent->map_mntpnt, w);
1008 974
1009 975 /* replace mntpnt with travpath to clean extra '/' */
1010 976 if (strlen(node->mapent->map_mntpnt) < strlen(w)) {
1011 977 if (verbose) {
1012 978 syslog(LOG_ERR,
1013 979 "mark_level1_root: path=%s error",
1014 980 traversed_path);
1015 981 }
1016 982 return (PARSE_ERROR);
1017 983 }
1018 984 if (strcmp(node->mapent->map_mntpnt, w) != 0)
1019 985 strcpy(node->mapent->map_mntpnt, w);
1020 986 node->mapent->map_mntlevel = 1;
1021 987 }
1022 988 node = node->leveldir;
1023 989 }
1024 990 return (PARSE_OK);
1025 991 }
1026 992
1027 993 /*
1028 994 * mark_and_fake_level1_noroot(hiernode *node, char *traversed_path,
1029 995 * char *key,char *mapname, struct mapent **faked_mapents,
1030 996 * uint_t isdirect, char *mapopts)
1031 997 * Called if the root of the hierarchy does not point to a mapent. marks nodes
1032 998 * upto one physical level below the rootnode given by subdir. checks if
1033 999 * there's a real mapentry. If not, it builds a faked one (autonode) at that
1034 1000 * point. The faked autonode is direct, with the map being the same as the
1035 1001 * original one from which the call originated. Options are same as that of
1036 1002 * the map and assigned in automount_opts(). Returns PARSE_OK or error value.
1037 1003 */
1038 1004 static int
1039 1005 mark_and_fake_level1_noroot(hiernode *node, char *traversed_path,
1040 1006 char *key, char *mapname, struct mapent **faked_mapents,
1041 1007 uint_t isdirect, char *mapopts)
1042 1008 {
1043 1009 struct mapent *me;
1044 1010 int rc = 0;
1045 1011 char faked_map_mntpnt[MAXPATHLEN];
1046 1012 char w1[MAXPATHLEN];
1047 1013 char w[MAXPATHLEN];
1048 1014
1049 1015 while (node != NULL) {
1050 1016 if (node->mapent != NULL) {
1051 1017 /*
1052 1018 * existing mapentry at level 1 - copy travpath to
1053 1019 * get rid of extra '/' in mntpnt
1054 1020 */
1055 1021 sprintf(w, "%s/%s", traversed_path, node->dirname);
1056 1022 if (trace > 3)
1057 1023 trace_prt(1, " node mntpnt=%s\t travpath=%s\n",
1058 1024 node->mapent->map_mntpnt, w);
1059 1025 if (strlen(node->mapent->map_mntpnt) < strlen(w)) {
1060 1026 /* sanity check */
1061 1027 if (verbose)
1062 1028 syslog(LOG_ERR,
1063 1029 "mark_fake_level1_noroot:path=%s error",
1064 1030 traversed_path);
1065 1031 return (PARSE_ERROR);
1066 1032 }
1067 1033 if (strcmp(node->mapent->map_mntpnt, w) != 0)
1068 1034 strcpy(node->mapent->map_mntpnt, w);
1069 1035 node->mapent->map_mntlevel = 1;
1070 1036 } else {
1071 1037 /*
1072 1038 * build the faked autonode
1073 1039 */
1074 1040 if ((me = (struct mapent *)malloc(sizeof (*me)))
1075 1041 == NULL) {
1076 1042 syslog(LOG_ERR,
1077 1043 "mark_and_fake_level1_noroot: out of memory");
1078 1044 return (ENOMEM);
1079 1045 }
1080 1046 (void) memset((char *)me, 0, sizeof (*me));
1081 1047
1082 1048 if ((me->map_fs = (struct mapfs *)
1083 1049 malloc(sizeof (struct mapfs))) == NULL)
1084 1050 return (ENOMEM);
1085 1051 (void) memset(me->map_fs, 0, sizeof (struct mapfs));
1086 1052
1087 1053 if (isdirect) {
1088 1054 *w1 = '\0';
1089 1055 } else {
1090 1056 strcpy(w1, "/");
1091 1057 strcat(w1, key);
1092 1058 }
1093 1059 me->map_root = strdup(w1);
1094 1060
1095 1061 sprintf(faked_map_mntpnt, "%s/%s", traversed_path,
1096 1062 node->dirname);
1097 1063 me->map_mntpnt = strdup(faked_map_mntpnt);
1098 1064 me->map_fstype = strdup(MNTTYPE_AUTOFS);
1099 1065 me->map_mounter = strdup(MNTTYPE_AUTOFS);
1100 1066
1101 1067 /* set options */
1102 1068 if ((rc = automount_opts(&me->map_mntopts, mapopts))
1103 1069 != PARSE_OK)
1104 1070 return (rc);
1105 1071 me->map_fs->mfs_dir = strdup(mapname);
1106 1072 me->map_mntlevel = 1;
1107 1073 me->map_modified = FALSE;
1108 1074 me->map_faked = TRUE; /* mark as faked */
1109 1075 if (me->map_root == NULL ||
1110 1076 me->map_mntpnt == NULL ||
1111 1077 me->map_fstype == NULL ||
1112 1078 me->map_mounter == NULL ||
1113 1079 me->map_mntopts == NULL ||
1114 1080 me->map_fs->mfs_dir == NULL) {
1115 1081 syslog(LOG_ERR,
1116 1082 "mark_and_fake_level1_noroot: out of memory");
1117 1083 free_mapent(*faked_mapents);
1118 1084 return (ENOMEM);
1119 1085 }
1120 1086
1121 1087 if (*faked_mapents == NULL)
1122 1088 *faked_mapents = me;
1123 1089 else { /* attach to the head */
1124 1090 me->map_next = *faked_mapents;
1125 1091 *faked_mapents = me;
1126 1092 }
1127 1093 node->mapent = me;
1128 1094 }
1129 1095 node = node->leveldir;
1130 1096 }
1131 1097 return (rc);
1132 1098 }
1133 1099
1134 1100 /*
1135 1101 * convert_mapent_to_automount(struct mapent *me, char *mapname,
1136 1102 * char *mapopts)
1137 1103 * change the mapentry me to an automount - free fields first and NULL them
1138 1104 * to avoid freeing again, while freeing the mapentry at a later stage.
1139 1105 * Could have avoided freeing entries here as we don't really look at them.
1140 1106 * Give the converted mapent entry the options that came with the map using
1141 1107 * automount_opts(). Returns PARSE_OK or appropriate error value.
1142 1108 */
1143 1109 static int
1144 1110 convert_mapent_to_automount(struct mapent *me, char *mapname,
1145 1111 char *mapopts)
1146 1112 {
1147 1113 struct mapfs *mfs = me->map_fs; /* assumes it exists */
1148 1114 int rc = PARSE_OK;
1149 1115
1150 1116 /* free relevant entries */
1151 1117 if (mfs->mfs_host) {
1152 1118 free(mfs->mfs_host);
1153 1119 mfs->mfs_host = NULL;
1154 1120 }
1155 1121 while (me->map_fs->mfs_next != NULL) {
1156 1122 mfs = me->map_fs->mfs_next;
1157 1123 if (mfs->mfs_host)
1158 1124 free(mfs->mfs_host);
1159 1125 if (mfs->mfs_dir)
1160 1126 free(mfs->mfs_dir);
1161 1127 me->map_fs->mfs_next = mfs->mfs_next; /* nulls eventually */
1162 1128 free((void*)mfs);
1163 1129 }
1164 1130
1165 1131 /* replace relevant entries */
1166 1132 if (me->map_fstype)
1167 1133 free(me->map_fstype);
1168 1134 if ((me->map_fstype = strdup(MNTTYPE_AUTOFS)) == NULL)
1169 1135 goto alloc_failed;
1170 1136
1171 1137 if (me->map_mounter)
1172 1138 free(me->map_mounter);
1173 1139 if ((me->map_mounter = strdup(me->map_fstype)) == NULL)
1174 1140 goto alloc_failed;
1175 1141
1176 1142 if (me->map_fs->mfs_dir)
1177 1143 free(me->map_fs->mfs_dir);
1178 1144 if ((me->map_fs->mfs_dir = strdup(mapname)) == NULL)
1179 1145 goto alloc_failed;
1180 1146
1181 1147 /* set options */
1182 1148 if (me->map_mntopts)
1183 1149 free(me->map_mntopts);
1184 1150 if ((rc = automount_opts(&me->map_mntopts, mapopts)) != PARSE_OK)
1185 1151 return (rc);
1186 1152
1187 1153 /* mucked with this entry, set the map_modified field to TRUE */
1188 1154 me->map_modified = TRUE;
1189 1155
1190 1156 return (rc);
1191 1157
1192 1158 alloc_failed:
1193 1159 syslog(LOG_ERR,
1194 1160 "convert_mapent_to_automount: Memory allocation failed");
1195 1161 return (ENOMEM);
1196 1162 }
1197 1163
1198 1164 /*
1199 1165 * automount_opts(char **map_mntopts, char *mapopts)
1200 1166 * modifies automount opts - gets rid of all "indirect" and "direct" strings
1201 1167 * if they exist, and then adds a direct string to force a direct automount.
1202 1168 * Rest of the mapopts stay intact. Returns PARSE_OK or appropriate error.
1203 1169 */
1204 1170 static int
1205 1171 automount_opts(char **map_mntopts, char *mapopts)
1206 1172 {
1207 1173 char *opts;
1208 1174 char *opt;
1209 1175 int len;
1210 1176 char *placeholder;
1211 1177 char buf[AUTOFS_MAXOPTSLEN];
1212 1178
1213 1179 char *addopt = "direct";
1214 1180
1215 1181 len = strlen(mapopts)+ strlen(addopt)+2; /* +2 for ",", '\0' */
1216 1182 if (len > AUTOFS_MAXOPTSLEN) {
1217 1183 syslog(LOG_ERR,
1218 1184 "option string %s too long (max=%d)", mapopts,
1219 1185 AUTOFS_MAXOPTSLEN-8);
1220 1186 return (PARSE_ERROR);
1221 1187 }
1222 1188
1223 1189 if (((*map_mntopts) = ((char *)malloc(len))) == NULL) {
1224 1190 syslog(LOG_ERR, "automount_opts: Memory allocation failed");
1225 1191 return (ENOMEM);
1226 1192 }
1227 1193 memset(*map_mntopts, 0, len);
1228 1194
1229 1195 strcpy(buf, mapopts);
1230 1196 opts = buf;
1231 1197 while ((opt = strtok_r(opts, ",", &placeholder)) != NULL) {
1232 1198 opts = NULL;
1233 1199
1234 1200 /* remove trailing and leading spaces */
1235 1201 while (isspace(*opt))
1236 1202 opt++;
1237 1203 len = strlen(opt)-1;
1238 1204 while (isspace(opt[len]))
1239 1205 opt[len--] = '\0';
1240 1206
1241 1207 /*
1242 1208 * if direct or indirect found, get rid of it, else put it
1243 1209 * back
1244 1210 */
1245 1211 if ((strcmp(opt, "indirect") == 0) ||
1246 1212 (strcmp(opt, "direct") == 0))
1247 1213 continue;
1248 1214 if (*map_mntopts[0] != '\0')
1249 1215 strcat(*map_mntopts, ",");
1250 1216 strcat(*map_mntopts, opt);
1251 1217 }
1252 1218
1253 1219 /* add the direct string at the end */
1254 1220 if (*map_mntopts[0] != '\0')
1255 1221 strcat(*map_mntopts, ",");
1256 1222 strcat(*map_mntopts, addopt);
1257 1223
1258 1224 return (PARSE_OK);
1259 1225 }
1260 1226
1261 1227 /*
1262 1228 * parse_fsinfo(char *mapname, struct mapent *mapents)
1263 1229 * parses the filesystem information stored in me->map_fsw and me->map_fswq
1264 1230 * and calls appropriate filesystem parser.
1265 1231 * Returns PARSE_OK or an appropriate error value.
1266 1232 */
1267 1233 static int
1268 1234 parse_fsinfo(char *mapname, struct mapent *mapents)
1269 1235 {
1270 1236 struct mapent *me = mapents;
1271 1237 char *bufp;
1272 1238 char *bufq;
1273 1239 int wordsz = MAXPATHLEN;
1274 1240 int err = 0;
1275 1241
1276 1242 while (me != NULL) {
1277 1243 bufp = "";
1278 1244 bufq = "";
1279 1245 if (strcmp(me->map_fstype, MNTTYPE_NFS) == 0) {
1280 1246 err = parse_nfs(mapname, me, me->map_fsw,
1281 1247 me->map_fswq, &bufp, &bufq, wordsz);
1282 1248 } else {
1283 1249 err = parse_special(me, me->map_fsw, me->map_fswq,
1284 1250 &bufp, &bufq, wordsz);
1285 1251 }
1286 1252
1287 1253 if (err != PARSE_OK || *me->map_fsw != '\0' ||
1288 1254 *me->map_fswq != '\0') {
1289 1255 /* sanity check */
1290 1256 if (verbose)
1291 1257 syslog(LOG_ERR,
1292 1258 "parse_fsinfo: mount location error %s",
1293 1259 me->map_fsw);
1294 1260 return (PARSE_ERROR);
1295 1261 }
1296 1262
1297 1263 me = me->map_next;
1298 1264 }
1299 1265
1300 1266 if (trace > 3) {
1301 1267 trace_mapents("parse_fsinfo:", mapents);
1302 1268 }
1303 1269
1304 1270 return (PARSE_OK);
1305 1271 }
1306 1272
1307 1273 /*
1308 1274 * This function parses the map entry for a nfs type file system
1309 1275 * The input is the string lp (and lq) which can be one of the
1310 1276 * following forms:
1311 1277 * a) host[(penalty)][,host[(penalty)]]... :/directory
1312 1278 * b) host[(penalty)]:/directory[ host[(penalty)]:/directory]...
1313 1279 * This routine constructs a mapfs link-list for each of
1314 1280 * the hosts and the corresponding file system. The list
1315 1281 * is then attatched to the mapent struct passed in.
1316 1282 */
1317 1283 int
1318 1284 parse_nfs(mapname, me, fsw, fswq, lp, lq, wsize)
1319 1285 struct mapent *me;
1320 1286 char *mapname, *fsw, *fswq, **lp, **lq;
1321 1287 int wsize;
1322 1288 {
1323 1289 struct mapfs *mfs, **mfsp;
1324 1290 char *wlp, *wlq;
1325 1291 char *hl, hostlist[1024], *hlq, hostlistq[1024];
1326 1292 char hostname_and_penalty[MXHOSTNAMELEN+5];
1327 1293 char *hn, *hnq, hostname[MXHOSTNAMELEN+1];
1328 1294 char dirname[MAXPATHLEN+1], subdir[MAXPATHLEN+1];
1329 1295 char qbuff[MAXPATHLEN+1], qbuff1[MAXPATHLEN+1];
1330 1296 char pbuff[10], pbuffq[10];
1331 1297 int penalty;
1332 1298 char w[MAXPATHLEN];
1333 1299 char wq[MAXPATHLEN];
1334 1300 int host_cnt;
1335 1301
1336 1302 mfsp = &me->map_fs;
1337 1303 *mfsp = NULL;
1338 1304
1339 1305 /*
1340 1306 * there may be more than one entry in the map list. Get the
1341 1307 * first one. Use temps to handle the word information and
1342 1308 * copy back into fsw and fswq fields when done.
1343 1309 */
1344 1310 *lp = fsw;
1345 1311 *lq = fswq;
1346 1312 if (getword(w, wq, lp, lq, ' ', wsize) == -1)
1347 1313 return (PARSE_ERROR);
1348 1314 while (*w && *w != '/') {
1349 1315 bool_t maybe_url;
1350 1316
1351 1317 maybe_url = TRUE;
1352 1318
1353 1319 wlp = w; wlq = wq;
1354 1320 if (getword(hostlist, hostlistq, &wlp, &wlq, ':',
1355 1321 sizeof (hostlist)) == -1)
1356 1322 return (PARSE_ERROR);
1357 1323 if (!*hostlist)
1358 1324 goto bad_entry;
1359 1325
1360 1326 if (strcmp(hostlist, "nfs") != 0)
1361 1327 maybe_url = FALSE;
1362 1328
1363 1329 if (getword(dirname, qbuff, &wlp, &wlq, ':',
1364 1330 sizeof (dirname)) == -1)
1365 1331 return (PARSE_ERROR);
1366 1332 if (*dirname == '\0')
1367 1333 goto bad_entry;
1368 1334
1369 1335 if (maybe_url == TRUE && strncmp(dirname, "//", 2) != 0)
1370 1336 maybe_url = FALSE;
1371 1337
1372 1338 /*
1373 1339 * See the next block comment ("Once upon a time ...") to
1374 1340 * understand this. It turns the deprecated concept
1375 1341 * of "subdir mounts" produced some useful code for handling
1376 1342 * the possibility of a ":port#" in the URL.
1377 1343 */
1378 1344 if (maybe_url == FALSE)
1379 1345 *subdir = '/';
1380 1346 else
1381 1347 *subdir = ':';
1382 1348
1383 1349 *qbuff = ' ';
1384 1350
1385 1351 /*
1386 1352 * Once upon time, before autofs, there was support for
1387 1353 * "subdir mounts". The idea was to "economize" the
1388 1354 * number of mounts, so if you had a number of entries
1389 1355 * all referring to a common subdirectory, e.g.
1390 1356 *
1391 1357 * carol seasons:/export/home11/carol
1392 1358 * ted seasons:/export/home11/ted
1393 1359 * alice seasons:/export/home11/alice
1394 1360 *
1395 1361 * then you could tell the automounter to mount a
1396 1362 * common mountpoint which was delimited by the second
1397 1363 * colon:
1398 1364 *
1399 1365 * carol seasons:/export/home11:carol
1400 1366 * ted seasons:/export/home11:ted
1401 1367 * alice seasons:/export/home11:alice
1402 1368 *
1403 1369 * The automounter would mount seasons:/export/home11
1404 1370 * then for any other map entry that referenced the same
1405 1371 * directory it would build a symbolic link that
1406 1372 * appended the remainder of the path after the second
1407 1373 * colon, i.e. once the common subdir was mounted, then
1408 1374 * other directories could be accessed just by link
1409 1375 * building - no further mounts required.
1410 1376 *
1411 1377 * In theory the "mount saving" idea sounded good. In
1412 1378 * practice the saving didn't amount to much and the
1413 1379 * symbolic links confused people because the common
1414 1380 * mountpoint had to have a pseudonym.
1415 1381 *
1416 1382 * To remain backward compatible with the existing
1417 1383 * maps, we interpret a second colon as a slash.
1418 1384 */
1419 1385 if (getword(subdir+1, qbuff+1, &wlp, &wlq, ':',
1420 1386 sizeof (subdir)) == -1)
1421 1387 return (PARSE_ERROR);
1422 1388
1423 1389 if (*(subdir+1))
1424 1390 (void) strcat(dirname, subdir);
1425 1391
1426 1392 hl = hostlist; hlq = hostlistq;
1427 1393
1428 1394 host_cnt = 0;
1429 1395 for (;;) {
1430 1396
1431 1397 if (getword(hostname_and_penalty, qbuff, &hl, &hlq, ',',
1432 1398 sizeof (hostname_and_penalty)) == -1)
1433 1399 return (PARSE_ERROR);
1434 1400 if (!*hostname_and_penalty)
1435 1401 break;
1436 1402
1437 1403 host_cnt++;
1438 1404 if (host_cnt > 1)
1439 1405 maybe_url = FALSE;
1440 1406
1441 1407 hn = hostname_and_penalty;
1442 1408 hnq = qbuff;
1443 1409 if (getword(hostname, qbuff1, &hn, &hnq, '(',
1444 1410 sizeof (hostname)) == -1)
1445 1411 return (PARSE_ERROR);
1446 1412 if (hostname[0] == '\0')
1447 1413 goto bad_entry;
1448 1414
1449 1415 if (strcmp(hostname, hostname_and_penalty) == 0) {
1450 1416 penalty = 0;
1451 1417 } else {
1452 1418 maybe_url = FALSE;
1453 1419 hn++; hnq++;
1454 1420 if (getword(pbuff, pbuffq, &hn, &hnq, ')',
1455 1421 sizeof (pbuff)) == -1)
1456 1422 return (PARSE_ERROR);
1457 1423 if (!*pbuff)
1458 1424 penalty = 0;
1459 1425 else
1460 1426 penalty = atoi(pbuff);
1461 1427 }
1462 1428 mfs = (struct mapfs *)malloc(sizeof (*mfs));
1463 1429 if (mfs == NULL) {
1464 1430 syslog(LOG_ERR,
1465 1431 "parse_nfs: Memory allocation failed");
1466 1432 return (PARSE_ERROR);
1467 1433 }
1468 1434 (void) memset(mfs, 0, sizeof (*mfs));
1469 1435 *mfsp = mfs;
1470 1436 mfsp = &mfs->mfs_next;
1471 1437
1472 1438 if (maybe_url == TRUE) {
1473 1439 char *host;
1474 1440 char *path;
1475 1441 char *sport;
1476 1442
1477 1443 host = dirname+2;
1478 1444 path = strchr(host, '/');
1479 1445 if (path == NULL) {
1480 1446 syslog(LOG_ERR,
1481 1447 "parse_nfs: illegal nfs url syntax: %s",
1482 1448 host);
1483 1449
1484 1450 return (PARSE_ERROR);
1485 1451 }
1486 1452 *path = '\0';
1487 1453 sport = strchr(host, ':');
1488 1454
1489 1455 if (sport != NULL && sport < path) {
1490 1456 *sport = '\0';
1491 1457 mfs->mfs_port = atoi(sport+1);
1492 1458
1493 1459 if (mfs->mfs_port > USHRT_MAX) {
1494 1460 syslog(LOG_ERR,
1495 1461 "parse_nfs: invalid "
1496 1462 "port number (%d) in "
1497 1463 "NFS URL",
1498 1464 mfs->mfs_port);
1499 1465
1500 1466 return (PARSE_ERROR);
1501 1467 }
1502 1468
1503 1469 }
1504 1470
1505 1471 path++;
1506 1472 if (*path == '\0')
1507 1473 path = ".";
1508 1474
1509 1475 mfs->mfs_flags |= MFS_URL;
1510 1476
1511 1477 mfs->mfs_host = strdup(host);
1512 1478 mfs->mfs_dir = strdup(path);
1513 1479 } else {
1514 1480 mfs->mfs_host = strdup(hostname);
1515 1481 mfs->mfs_dir = strdup(dirname);
1516 1482 }
1517 1483
1518 1484 mfs->mfs_penalty = penalty;
1519 1485 if (mfs->mfs_host == NULL || mfs->mfs_dir == NULL) {
1520 1486 syslog(LOG_ERR,
1521 1487 "parse_nfs: Memory allocation failed");
1522 1488 return (PARSE_ERROR);
1523 1489 }
1524 1490 }
1525 1491 /*
1526 1492 * We check host_cnt to make sure we haven't parsed an entry
1527 1493 * with no host information.
1528 1494 */
1529 1495 if (host_cnt == 0) {
1530 1496 syslog(LOG_ERR,
1531 1497 "parse_nfs: invalid host specified - bad entry "
1532 1498 "in map %s \"%s\"",
1533 1499 mapname, w);
1534 1500 return (PARSE_ERROR);
1535 1501 }
1536 1502 if (getword(w, wq, lp, lq, ' ', wsize) == -1)
1537 1503 return (PARSE_ERROR);
1538 1504 }
1539 1505
1540 1506 strcpy(fsw, w);
1541 1507 strcpy(fswq, wq);
1542 1508
1543 1509 return (PARSE_OK);
1544 1510
1545 1511 bad_entry:
1546 1512 syslog(LOG_ERR, "parse_nfs: bad entry in map %s \"%s\"", mapname, w);
1547 1513 return (PARSE_ERROR);
1548 1514 }
1549 1515
1550 1516 static int
1551 1517 parse_special(me, w, wq, lp, lq, wsize)
1552 1518 struct mapent *me;
1553 1519 char *w, *wq, **lp, **lq;
1554 1520 int wsize;
1555 1521 {
1556 1522 char devname[MAXPATHLEN + 1], qbuf[MAXPATHLEN + 1];
1557 1523 char *wlp, *wlq;
1558 1524 struct mapfs *mfs;
1559 1525
1560 1526 wlp = w;
1561 1527 wlq = wq;
1562 1528 if (getword(devname, qbuf, &wlp, &wlq, ' ', sizeof (devname)) == -1)
1563 1529 return (PARSE_ERROR);
1564 1530 if (devname[0] == '\0')
1565 1531 return (PARSE_ERROR);
1566 1532
1567 1533 mfs = (struct mapfs *)malloc(sizeof (struct mapfs));
1568 1534 if (mfs == NULL)
1569 1535 return (PARSE_ERROR);
1570 1536 (void) memset(mfs, 0, sizeof (*mfs));
1571 1537
1572 1538 /*
1573 1539 * A device name that begins with a slash could
1574 1540 * be confused with a mountpoint path, hence use
1575 1541 * a colon to escape a device string that begins
1576 1542 * with a slash, e.g.
1577 1543 *
1578 1544 * foo -ro /bar foo:/bar
1579 1545 * and
1580 1546 * foo -ro /dev/sr0
1581 1547 *
1582 1548 * would confuse the parser. The second instance
1583 1549 * must use a colon:
1584 1550 *
1585 1551 * foo -ro :/dev/sr0
1586 1552 */
1587 1553 mfs->mfs_dir = strdup(&devname[devname[0] == ':']);
1588 1554 if (mfs->mfs_dir == NULL)
1589 1555 return (PARSE_ERROR);
1590 1556 me->map_fs = mfs;
1591 1557 if (getword(w, wq, lp, lq, ' ', wsize) == -1)
1592 1558 return (PARSE_ERROR);
1593 1559 return (0);
1594 1560 }
1595 1561
1596 1562 /*
1597 1563 * get_dir_from_path(char *dir, char **path, int dirsz)
1598 1564 * gets the directory name dir from path for max string of length dirsz.
1599 1565 * A modification of the getword routine. Assumes the delimiter is '/'
1600 1566 * and that excess /'s are redundant.
1601 1567 * Returns PARSE_OK or PARSE_ERROR
1602 1568 */
1603 1569 static int
1604 1570 get_dir_from_path(char *dir, char **path, int dirsz)
1605 1571 {
1606 1572 char *tmp = dir;
1607 1573 int count = dirsz;
1608 1574
1609 1575 if (dirsz <= 0) {
1610 1576 if (verbose)
1611 1577 syslog(LOG_ERR,
1612 1578 "get_dir_from_path: invalid directory size %d", dirsz);
1613 1579 return (PARSE_ERROR);
1614 1580 }
1615 1581
1616 1582 /* get rid of leading /'s in path */
1617 1583 while (**path == '/')
1618 1584 (*path)++;
1619 1585
1620 1586 /* now at a word or at the end of path */
1621 1587 while ((**path) && ((**path) != '/')) {
1622 1588 if (--count <= 0) {
1623 1589 *tmp = '\0';
1624 1590 syslog(LOG_ERR,
1625 1591 "get_dir_from_path: max pathlength exceeded %d", dirsz);
1626 1592 return (PARSE_ERROR);
1627 1593 }
1628 1594 *dir++ = *(*path)++;
1629 1595 }
1630 1596
1631 1597 *dir = '\0';
1632 1598
1633 1599 /* get rid of trailing /'s in path */
1634 1600 while (**path == '/')
1635 1601 (*path)++;
1636 1602
1637 1603 return (PARSE_OK);
1638 1604 }
1639 1605
1640 1606 /*
1641 1607 * alloc_hiernode(hiernode **newnode, char *dirname)
1642 1608 * allocates a new hiernode corresponding to a new directory entry
1643 1609 * in the hierarchical structure, and passes a pointer to it back
1644 1610 * to the calling program.
1645 1611 * Returns PARSE_OK or appropriate error value.
1646 1612 */
1647 1613 static int
1648 1614 alloc_hiernode(hiernode **newnode, char *dirname)
1649 1615 {
1650 1616 if ((*newnode = (hiernode *)malloc(sizeof (hiernode))) == NULL) {
1651 1617 syslog(LOG_ERR, "alloc_hiernode: Memory allocation failed");
1652 1618 return (ENOMEM);
1653 1619 }
1654 1620
1655 1621 memset(((char *)*newnode), 0, sizeof (hiernode));
1656 1622 strcpy(((*newnode)->dirname), dirname);
1657 1623 return (PARSE_OK);
1658 1624 }
1659 1625
1660 1626 /*
1661 1627 * free_hiernode(hiernode *node)
1662 1628 * frees the allocated hiernode given the head of the structure
1663 1629 * recursively calls itself until it frees entire structure.
1664 1630 * Returns nothing.
1665 1631 */
1666 1632 static void
1667 1633 free_hiernode(hiernode *node)
1668 1634 {
1669 1635 hiernode *currnode = node;
1670 1636 hiernode *prevnode = NULL;
1671 1637
1672 1638 while (currnode != NULL) {
1673 1639 if (currnode->subdir != NULL)
1674 1640 free_hiernode(currnode->subdir);
1675 1641 prevnode = currnode;
1676 1642 currnode = currnode->leveldir;
1677 1643 free((void*)prevnode);
1678 1644 }
1679 1645 }
1680 1646
1681 1647 /*
1682 1648 * free_mapent(struct mapent *)
1683 1649 * free the mapentry and its fields
1684 1650 */
1685 1651 void
1686 1652 free_mapent(me)
1687 1653 struct mapent *me;
1688 1654 {
1689 1655 struct mapfs *mfs;
1690 1656 struct mapent *m;
1691 1657
1692 1658 while (me) {
1693 1659 while (me->map_fs) {
1694 1660 mfs = me->map_fs;
1695 1661 if (mfs->mfs_host)
1696 1662 free(mfs->mfs_host);
1697 1663 if (mfs->mfs_dir)
1698 1664 free(mfs->mfs_dir);
1699 1665 if (mfs->mfs_args)
1700 1666 free(mfs->mfs_args);
1701 1667 if (mfs->mfs_nconf)
1702 1668 freenetconfigent(mfs->mfs_nconf);
1703 1669 me->map_fs = mfs->mfs_next;
1704 1670 free((char *)mfs);
1705 1671 }
1706 1672
1707 1673 if (me->map_root)
1708 1674 free(me->map_root);
1709 1675 if (me->map_mntpnt)
1710 1676 free(me->map_mntpnt);
1711 1677 if (me->map_mntopts)
1712 1678 free(me->map_mntopts);
1713 1679 if (me->map_fstype)
1714 1680 free(me->map_fstype);
1715 1681 if (me->map_mounter)
1716 1682 free(me->map_mounter);
1717 1683 if (me->map_fsw)
1718 1684 free(me->map_fsw);
1719 1685 if (me->map_fswq)
1720 1686 free(me->map_fswq);
1721 1687
1722 1688 m = me;
1723 1689 me = me->map_next;
1724 1690 free((char *)m);
1725 1691 }
1726 1692 }
1727 1693
1728 1694 /*
1729 1695 * trace_mapents(struct mapent *mapents)
1730 1696 * traces through the mapentry structure and prints it element by element
1731 1697 * returns nothing
1732 1698 */
1733 1699 static void
1734 1700 trace_mapents(char *s, struct mapent *mapents)
1735 1701 {
1736 1702 struct mapfs *mfs;
1737 1703 struct mapent *me;
1738 1704
1739 1705 trace_prt(1, "\n\t%s\n", s);
1740 1706 for (me = mapents; me; me = me->map_next) {
1741 1707 trace_prt(1, " (%s,%s)\t %s%s -%s\n",
1742 1708 me->map_fstype ? me->map_fstype : "",
1743 1709 me->map_mounter ? me->map_mounter : "",
1744 1710 me->map_root ? me->map_root : "",
1745 1711 me->map_mntpnt ? me->map_mntpnt : "",
1746 1712 me->map_mntopts ? me->map_mntopts : "");
1747 1713 for (mfs = me->map_fs; mfs; mfs = mfs->mfs_next)
1748 1714 trace_prt(0, "\t\t%s:%s\n",
1749 1715 mfs->mfs_host ? mfs->mfs_host: "",
1750 1716 mfs->mfs_dir ? mfs->mfs_dir : "");
1751 1717
1752 1718 trace_prt(1, "\tme->map_fsw=%s\n",
1753 1719 me->map_fsw ? me->map_fsw:"",
1754 1720 me->map_fswq ? me->map_fsw:"");
1755 1721 trace_prt(1, "\t mntlevel=%d\t%s\t%s err=%d\n",
1756 1722 me->map_mntlevel,
1757 1723 me->map_modified ? "modify=TRUE":"modify=FALSE",
1758 1724 me->map_faked ? "faked=TRUE":"faked=FALSE",
1759 1725 me->map_err);
1760 1726 }
1761 1727 }
1762 1728
1763 1729 /*
1764 1730 * trace_hierarchy(hiernode *node)
1765 1731 * traces the allocated hiernode given the head of the structure
1766 1732 * recursively calls itself until it traces entire structure.
1767 1733 * the first call made at the root is made with a zero level.
1768 1734 * nodelevel is simply used to print tab and make the tracing clean.
1769 1735 * Returns nothing.
1770 1736 */
1771 1737 static void
1772 1738 trace_hierarchy(hiernode *node, int nodelevel)
1773 1739 {
1774 1740 hiernode *currnode = node;
1775 1741 int i;
1776 1742
1777 1743 while (currnode != NULL) {
1778 1744 if (currnode->subdir != NULL) {
1779 1745 for (i = 0; i < nodelevel; i++)
1780 1746 trace_prt(0, "\t");
1781 1747 trace_prt(0, "\t(%s, ",
1782 1748 currnode->dirname ? currnode->dirname :"");
1783 1749 if (currnode->mapent) {
1784 1750 trace_prt(0, "%d, %s)\n",
1785 1751 currnode->mapent->map_mntlevel,
1786 1752 currnode->mapent->map_mntopts ?
1787 1753 currnode->mapent->map_mntopts:"");
1788 1754 }
1789 1755 else
1790 1756 trace_prt(0, " ,)\n");
1791 1757 nodelevel++;
1792 1758 trace_hierarchy(currnode->subdir, nodelevel);
1793 1759 } else {
1794 1760 for (i = 0; i < nodelevel; i++)
1795 1761 trace_prt(0, "\t");
1796 1762 trace_prt(0, "\t(%s, ",
1797 1763 currnode->dirname ? currnode->dirname :"");
1798 1764 if (currnode->mapent) {
1799 1765 trace_prt(0, "%d, %s)\n",
1800 1766 currnode->mapent->map_mntlevel,
1801 1767 currnode->mapent->map_mntopts ?
1802 1768 currnode->mapent->map_mntopts:"");
1803 1769 }
1804 1770 else
1805 1771 trace_prt(0, ", )\n");
1806 1772 }
1807 1773 currnode = currnode->leveldir;
1808 1774 }
1809 1775 }
1810 1776
1811 1777 struct mapent *
1812 1778 do_mapent_hosts(mapopts, host, isdirect)
1813 1779 char *mapopts, *host;
1814 1780 uint_t isdirect;
1815 1781 {
1816 1782 CLIENT *cl;
1817 1783 struct mapent *me, *ms, *mp;
1818 1784 struct mapfs *mfs;
1819 1785 struct exportnode *ex = NULL;
1820 1786 struct exportnode *exlist, *texlist, **texp, *exnext;
1821 1787 struct timeval timeout;
1822 1788 enum clnt_stat clnt_stat;
1823 1789 char name[MAXPATHLEN];
1824 1790 char entryopts[MAXOPTSLEN];
1825 1791 char fstype[32], mounter[32];
1826 1792 int exlen, duplicate;
1827 1793 struct mnttab mb; /* needed for hasmntopt() to get nfs version */
1828 1794 rpcvers_t nfsvers; /* version in map options, 0 if not there */
1829 1795 rpcvers_t vers, versmin; /* used to negotiate nfs vers in pingnfs() */
1830 1796 int retries, delay;
1831 1797 int foundvers;
1832 1798
1833 1799 if (trace > 1)
1834 1800 trace_prt(1, " do_mapent_hosts: host %s\n", host);
1835 1801
1836 1802 /* check for special case: host is me */
1837 1803
1838 1804 if (self_check(host)) {
1839 1805 ms = (struct mapent *)malloc(sizeof (*ms));
1840 1806 if (ms == NULL)
1841 1807 goto alloc_failed;
1842 1808 (void) memset((char *)ms, 0, sizeof (*ms));
1843 1809 (void) strcpy(fstype, MNTTYPE_NFS);
1844 1810 get_opts(mapopts, entryopts, fstype, NULL);
1845 1811 ms->map_mntopts = strdup(entryopts);
1846 1812 if (ms->map_mntopts == NULL)
1847 1813 goto alloc_failed;
1848 1814 ms->map_mounter = strdup(fstype);
1849 1815 if (ms->map_mounter == NULL)
1850 1816 goto alloc_failed;
1851 1817 ms->map_fstype = strdup(MNTTYPE_NFS);
1852 1818 if (ms->map_fstype == NULL)
1853 1819 goto alloc_failed;
1854 1820
1855 1821 if (isdirect)
1856 1822 name[0] = '\0';
1857 1823 else {
1858 1824 (void) strcpy(name, "/");
1859 1825 (void) strcat(name, host);
1860 1826 }
1861 1827 ms->map_root = strdup(name);
1862 1828 if (ms->map_root == NULL)
1863 1829 goto alloc_failed;
1864 1830 ms->map_mntpnt = strdup("");
1865 1831 if (ms->map_mntpnt == NULL)
1866 1832 goto alloc_failed;
1867 1833 mfs = (struct mapfs *)malloc(sizeof (*mfs));
1868 1834 if (mfs == NULL)
1869 1835 goto alloc_failed;
1870 1836 (void) memset((char *)mfs, 0, sizeof (*mfs));
1871 1837 ms->map_fs = mfs;
1872 1838 mfs->mfs_host = strdup(host);
1873 1839 if (mfs->mfs_host == NULL)
1874 1840 goto alloc_failed;
1875 1841 mfs->mfs_dir = strdup("/");
1876 1842 if (mfs->mfs_dir == NULL)
1877 1843 goto alloc_failed;
1878 1844
1879 1845 /* initialize mntlevel and modify */
1880 1846 ms->map_mntlevel = -1;
1881 1847 ms->map_modified = FALSE;
1882 1848 ms->map_faked = FALSE;
1883 1849
1884 1850 if (trace > 1)
1885 1851 trace_prt(1,
1886 1852 " do_mapent_hosts: self-host %s OK\n", host);
1887 1853
1888 1854 return (ms);
1889 1855 }
1890 1856
1891 1857 /*
1892 1858 * Call pingnfs. Note that we can't have replicated hosts in /net.
1893 1859 * XXX - we would like to avoid duplicating the across the wire calls
1894 1860 * made here in nfsmount(). The pingnfs cache should help avoid it.
1895 1861 */
1896 1862 mb.mnt_mntopts = mapopts;
1897 1863 foundvers = nopt(&mb, MNTOPT_VERS, (int *)&nfsvers);
1898 1864 if (!foundvers)
1899 1865 nfsvers = 0;
1900 1866 if (set_versrange(nfsvers, &vers, &versmin) != 0) {
1901 1867 syslog(LOG_ERR, "Incorrect NFS version specified for %s", host);
1902 1868 return ((struct mapent *)NULL);
1903 1869 }
1904 1870 if (pingnfs(host, get_retry(mapopts) + 1, &vers, versmin, 0, FALSE,
1905 1871 NULL, NULL) != RPC_SUCCESS)
1906 1872 return ((struct mapent *)NULL);
1907 1873
1908 1874 retries = get_retry(mapopts);
1909 1875 delay = INITDELAY;
1910 1876 retry:
1911 1877 /* get export list of host */
1912 1878 cl = clnt_create(host, MOUNTPROG, MOUNTVERS, "circuit_v");
1913 1879 if (cl == NULL) {
1914 1880 cl = clnt_create(host, MOUNTPROG, MOUNTVERS, "datagram_v");
1915 1881 if (cl == NULL) {
1916 1882 syslog(LOG_ERR,
1917 1883 "do_mapent_hosts: %s %s", host, clnt_spcreateerror(""));
1918 1884 return ((struct mapent *)NULL);
1919 1885 }
1920 1886
1921 1887 }
1922 1888 #ifdef MALLOC_DEBUG
1923 1889 add_alloc("CLNT_HANDLE", cl, 0, __FILE__, __LINE__);
1924 1890 add_alloc("AUTH_HANDLE", cl->cl_auth, 0,
1925 1891 __FILE__, __LINE__);
1926 1892 #endif
1927 1893
1928 1894 timeout.tv_usec = 0;
1929 1895 timeout.tv_sec = 25;
1930 1896 if (clnt_stat = clnt_call(cl, MOUNTPROC_EXPORT, xdr_void, 0,
1931 1897 xdr_exports, (caddr_t)&ex, timeout)) {
1932 1898
1933 1899 if (retries-- > 0) {
1934 1900 clnt_destroy(cl);
1935 1901 DELAY(delay);
1936 1902 goto retry;
1937 1903 }
1938 1904
1939 1905 syslog(LOG_ERR,
1940 1906 "do_mapent_hosts: %s: export list: %s",
1941 1907 host, clnt_sperrno(clnt_stat));
1942 1908 #ifdef MALLOC_DEBUG
1943 1909 drop_alloc("CLNT_HANDLE", cl, __FILE__, __LINE__);
1944 1910 drop_alloc("AUTH_HANDLE", cl->cl_auth,
1945 1911 __FILE__, __LINE__);
1946 1912 #endif
1947 1913 clnt_destroy(cl);
1948 1914 return ((struct mapent *)NULL);
1949 1915 }
1950 1916
1951 1917 #ifdef MALLOC_DEBUG
1952 1918 drop_alloc("CLNT_HANDLE", cl, __FILE__, __LINE__);
1953 1919 drop_alloc("AUTH_HANDLE", cl->cl_auth,
1954 1920 __FILE__, __LINE__);
1955 1921 #endif
1956 1922 clnt_destroy(cl);
1957 1923
1958 1924 if (ex == NULL) {
1959 1925 if (trace > 1)
1960 1926 trace_prt(1,
1961 1927 gettext(" getmapent_hosts: null export list\n"));
1962 1928 return ((struct mapent *)NULL);
1963 1929 }
1964 1930
1965 1931 /* now sort by length of names - to get mount order right */
1966 1932 exlist = ex;
1967 1933 texlist = NULL;
1968 1934 #ifdef lint
1969 1935 exnext = NULL;
1970 1936 #endif
1971 1937 for (; ex; ex = exnext) {
1972 1938 exnext = ex->ex_next;
1973 1939 exlen = strlen(ex->ex_dir);
1974 1940 duplicate = 0;
1975 1941 for (texp = &texlist; *texp; texp = &((*texp)->ex_next)) {
1976 1942 if (exlen < (int)strlen((*texp)->ex_dir))
1977 1943 break;
1978 1944 duplicate = (strcmp(ex->ex_dir, (*texp)->ex_dir) == 0);
1979 1945 if (duplicate) {
1980 1946 /* disregard duplicate entry */
1981 1947 freeex_ent(ex);
↓ open down ↓ |
1233 lines elided |
↑ open up ↑ |
1982 1948 break;
1983 1949 }
1984 1950 }
1985 1951 if (!duplicate) {
1986 1952 ex->ex_next = *texp;
1987 1953 *texp = ex;
1988 1954 }
1989 1955 }
1990 1956 exlist = texlist;
1991 1957
1992 - /*
1993 - * The following ugly chunk of code crept in as
1994 - * a result of cachefs. If it's a cachefs mount
1995 - * of an nfs filesystem, then have it handled as
1996 - * an nfs mount but have cachefs do the mount.
1997 - */
1998 1958 (void) strcpy(fstype, MNTTYPE_NFS);
1999 1959 get_opts(mapopts, entryopts, fstype, NULL);
2000 1960 (void) strcpy(mounter, fstype);
2001 - if (strcmp(fstype, MNTTYPE_CACHEFS) == 0) {
2002 - struct mnttab m;
2003 - char *p;
2004 1961
2005 - m.mnt_mntopts = entryopts;
2006 - if ((p = hasmntopt(&m, "backfstype")) != NULL) {
2007 - int len = strlen(MNTTYPE_NFS);
2008 -
2009 - p += 11;
2010 - if (strncmp(p, MNTTYPE_NFS, len) == 0 &&
2011 - (p[len] == '\0' || p[len] == ',')) {
2012 - /*
2013 - * Cached nfs mount
2014 - */
2015 - (void) strcpy(fstype, MNTTYPE_NFS);
2016 - (void) strcpy(mounter, MNTTYPE_CACHEFS);
2017 - }
2018 - }
2019 - }
2020 -
2021 1962 /* Now create a mapent from the export list */
2022 1963 ms = NULL;
2023 1964 me = NULL;
2024 1965
2025 1966 for (ex = exlist; ex; ex = ex->ex_next) {
2026 1967 mp = me;
2027 1968 me = (struct mapent *)malloc(sizeof (*me));
2028 1969 if (me == NULL)
2029 1970 goto alloc_failed;
2030 1971 (void) memset((char *)me, 0, sizeof (*me));
2031 1972
2032 1973 if (ms == NULL)
2033 1974 ms = me;
2034 1975 else
2035 1976 mp->map_next = me;
2036 1977
2037 1978 if (isdirect)
2038 1979 name[0] = '\0';
2039 1980 else {
2040 1981 (void) strcpy(name, "/");
2041 1982 (void) strcat(name, host);
2042 1983 }
2043 1984 me->map_root = strdup(name);
2044 1985 if (me->map_root == NULL)
2045 1986 goto alloc_failed;
2046 1987
2047 1988 *name = '\0';
2048 1989 if (strcmp(ex->ex_dir, "/") != 0) {
2049 1990 if (*(ex->ex_dir) != '/')
2050 1991 (void) strcpy(name, "/");
2051 1992 (void) strcat(name, ex->ex_dir);
2052 1993 }
2053 1994 me->map_mntpnt = strdup(name);
2054 1995 if (me->map_mntpnt == NULL)
2055 1996 goto alloc_failed;
2056 1997
2057 1998 me->map_fstype = strdup(fstype);
2058 1999 if (me->map_fstype == NULL)
2059 2000 goto alloc_failed;
2060 2001 me->map_mounter = strdup(mounter);
2061 2002 if (me->map_mounter == NULL)
2062 2003 goto alloc_failed;
2063 2004 me->map_mntopts = strdup(entryopts);
2064 2005 if (me->map_mntopts == NULL)
2065 2006 goto alloc_failed;
2066 2007
2067 2008 mfs = (struct mapfs *)malloc(sizeof (*mfs));
2068 2009 if (mfs == NULL)
2069 2010 goto alloc_failed;
2070 2011 (void) memset((char *)mfs, 0, sizeof (*mfs));
2071 2012 me->map_fs = mfs;
2072 2013 mfs->mfs_host = strdup(host);
2073 2014 if (mfs->mfs_host == NULL)
2074 2015 goto alloc_failed;
2075 2016 mfs->mfs_dir = strdup(ex->ex_dir);
2076 2017 if (mfs->mfs_dir == NULL)
2077 2018 goto alloc_failed;
2078 2019
2079 2020 /* initialize mntlevel and modify values */
2080 2021 me->map_mntlevel = -1;
2081 2022 me->map_modified = FALSE;
2082 2023 me->map_faked = FALSE;
2083 2024 }
2084 2025 freeex(exlist);
2085 2026
2086 2027 if (trace > 1)
2087 2028 trace_prt(1, " do_mapent_hosts: host %s OK\n", host);
2088 2029
2089 2030 return (ms);
2090 2031
2091 2032 alloc_failed:
2092 2033 syslog(LOG_ERR, "do_mapent_hosts: Memory allocation failed");
2093 2034 free_mapent(ms);
2094 2035 freeex(exlist);
2095 2036 return ((struct mapent *)NULL);
2096 2037 }
2097 2038
2098 2039
2099 2040 static void
2100 2041 freeex_ent(ex)
2101 2042 struct exportnode *ex;
2102 2043 {
2103 2044 struct groupnode *groups, *tmpgroups;
2104 2045
2105 2046 free(ex->ex_dir);
2106 2047 groups = ex->ex_groups;
2107 2048 while (groups) {
2108 2049 free(groups->gr_name);
2109 2050 tmpgroups = groups->gr_next;
2110 2051 free((char *)groups);
2111 2052 groups = tmpgroups;
2112 2053 }
2113 2054 free((char *)ex);
2114 2055 }
2115 2056
2116 2057 static void
2117 2058 freeex(ex)
2118 2059 struct exportnode *ex;
2119 2060 {
2120 2061 struct exportnode *tmpex;
2121 2062
2122 2063 while (ex) {
2123 2064 tmpex = ex->ex_next;
2124 2065 freeex_ent(ex);
2125 2066 ex = tmpex;
2126 2067 }
2127 2068 }
2128 2069
2129 2070 static const char uatfs_err[] = "submount under fstype=autofs not supported";
2130 2071 /*
2131 2072 * dump_mapent_err(struct mapent *me, char *key, char *mapname)
2132 2073 * syslog appropriate error in mapentries.
2133 2074 */
2134 2075 static void dump_mapent_err(struct mapent *me, char *key, char *mapname)
2135 2076 {
2136 2077 switch (me->map_err) {
2137 2078 case MAPENT_NOERR:
2138 2079 if (verbose)
2139 2080 syslog(LOG_ERR,
2140 2081 "map=%s key=%s mntpnt=%s: no error");
2141 2082 break;
2142 2083 case MAPENT_UATFS:
2143 2084 syslog(LOG_ERR,
2144 2085 "mountpoint %s in map %s key %s not mounted: %s",
2145 2086 me->map_mntpnt, mapname, key, uatfs_err);
2146 2087 break;
2147 2088 default:
2148 2089 if (verbose)
2149 2090 syslog(LOG_ERR,
2150 2091 "map=%s key=%s mntpnt=%s: unknown mapentry error");
2151 2092 }
2152 2093 }
↓ open down ↓ |
122 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX