Print this page
PSARC 2008/290 lofi mount
6384817 Need persistent lofi based mounts and direct mount(1m) support for lofi
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/fs.d/fslib.c
+++ new/usr/src/cmd/fs.d/fslib.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 - * Common Development and Distribution License, Version 1.0 only
6 - * (the "License"). You may not use this file except in compliance
7 - * with the License.
5 + * Common Development and Distribution License (the "License").
6 + * You may not use this file except in compliance with the License.
8 7 *
9 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 9 * or http://www.opensolaris.org/os/licensing.
11 10 * See the License for the specific language governing permissions
12 11 * and limitations under the License.
13 12 *
14 13 * When distributing Covered Code, include this CDDL HEADER in each
15 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 15 * If applicable, add the following below this CDDL HEADER, with the
17 16 * fields enclosed by brackets "[]" replaced with your own identifying
18 17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 18 *
20 19 * CDDL HEADER END
21 20 */
22 21 /*
23 - * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
22 + * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 23 * Use is subject to license terms.
25 24 */
26 25
27 -#pragma ident "@(#)fslib.c 1.25 05/06/08 SMI"
26 +#pragma ident "@(#)fslib.c 1.26 08/05/07 SMI"
28 27
29 28 #include <stdio.h>
30 29 #include <stdarg.h>
31 30 #include <stdlib.h>
32 31 #include <unistd.h>
33 32 #include <libintl.h>
34 33 #include <string.h>
35 34 #include <fcntl.h>
36 35 #include <errno.h>
37 36 #include <syslog.h>
38 37 #include <alloca.h>
39 38 #include <sys/vfstab.h>
40 39 #include <sys/mnttab.h>
41 40 #include <sys/mntent.h>
42 41 #include <sys/mount.h>
43 42 #include <sys/filio.h>
44 43 #include <sys/fs/ufs_filio.h>
45 44 #include <sys/stat.h>
46 45 #include <sys/param.h>
47 46 #include <zone.h>
48 47 #include <signal.h>
49 48 #include <strings.h>
50 49 #include "fslib.h"
51 50
52 51 /* LINTLIBRARY */
53 52
54 53 #define BUFLEN 256
55 54
56 55 #define TIME_MAX 16
57 56
58 57 /*
59 58 * Reads all of the entries from the in-kernel mnttab, and returns the
60 59 * linked list of the entries.
61 60 */
62 61 mntlist_t *
63 62 fsgetmntlist(void)
64 63 {
65 64 FILE *mfp;
66 65 mntlist_t *mntl;
67 66 char buf[BUFLEN];
68 67
69 68 if ((mfp = fopen(MNTTAB, "r")) == NULL) {
70 69 (void) snprintf(buf, BUFLEN, "fsgetmntlist: fopen %s", MNTTAB);
71 70 perror(buf);
72 71 return (NULL);
73 72 }
74 73
75 74 mntl = fsmkmntlist(mfp);
76 75
77 76 (void) fclose(mfp);
78 77 return (mntl);
79 78 }
80 79
81 80
82 81 static struct extmnttab zmnttab = { 0 };
83 82
84 83 struct extmnttab *
85 84 fsdupmnttab(struct extmnttab *mnt)
86 85 {
87 86 struct extmnttab *new;
88 87
89 88 new = (struct extmnttab *)malloc(sizeof (*new));
90 89 if (new == NULL)
91 90 goto alloc_failed;
92 91
93 92 *new = zmnttab;
94 93 /*
95 94 * Allocate an extra byte for the mountpoint
96 95 * name in case a space needs to be added.
97 96 */
98 97 new->mnt_mountp = (char *)malloc(strlen(mnt->mnt_mountp) + 2);
99 98 if (new->mnt_mountp == NULL)
100 99 goto alloc_failed;
101 100 (void) strcpy(new->mnt_mountp, mnt->mnt_mountp);
102 101
103 102 if ((new->mnt_special = strdup(mnt->mnt_special)) == NULL)
104 103 goto alloc_failed;
105 104
106 105 if ((new->mnt_fstype = strdup(mnt->mnt_fstype)) == NULL)
107 106 goto alloc_failed;
108 107
109 108 if (mnt->mnt_mntopts != NULL)
110 109 if ((new->mnt_mntopts = strdup(mnt->mnt_mntopts)) == NULL)
111 110 goto alloc_failed;
112 111
113 112 if (mnt->mnt_time != NULL)
114 113 if ((new->mnt_time = strdup(mnt->mnt_time)) == NULL)
115 114 goto alloc_failed;
116 115
117 116 new->mnt_major = mnt->mnt_major;
118 117 new->mnt_minor = mnt->mnt_minor;
119 118 return (new);
120 119
121 120 alloc_failed:
122 121 (void) fprintf(stderr, gettext("fsdupmnttab: Out of memory\n"));
123 122 fsfreemnttab(new);
124 123 return (NULL);
125 124 }
126 125
127 126 /*
128 127 * Free a single mnttab structure
129 128 */
130 129 void
131 130 fsfreemnttab(struct extmnttab *mnt)
132 131 {
133 132
134 133 if (mnt) {
135 134 if (mnt->mnt_special)
136 135 free(mnt->mnt_special);
137 136 if (mnt->mnt_mountp)
138 137 free(mnt->mnt_mountp);
139 138 if (mnt->mnt_fstype)
140 139 free(mnt->mnt_fstype);
141 140 if (mnt->mnt_mntopts)
142 141 free(mnt->mnt_mntopts);
143 142 if (mnt->mnt_time)
144 143 free(mnt->mnt_time);
145 144 free(mnt);
146 145 }
147 146 }
148 147
149 148 void
150 149 fsfreemntlist(mntlist_t *mntl)
151 150 {
152 151 mntlist_t *mntl_tmp;
153 152
154 153 while (mntl) {
155 154 fsfreemnttab(mntl->mntl_mnt);
156 155 mntl_tmp = mntl;
157 156 mntl = mntl->mntl_next;
158 157 free(mntl_tmp);
159 158 }
160 159 }
161 160
162 161 /*
163 162 * Read the mnttab file and return it as a list of mnttab structs.
164 163 * Returns NULL if there was a memory failure.
165 164 */
166 165 mntlist_t *
|
↓ open down ↓ |
129 lines elided |
↑ open up ↑ |
167 166 fsmkmntlist(FILE *mfp)
168 167 {
169 168 struct extmnttab mnt;
170 169 mntlist_t *mhead, *mtail;
171 170 int ret;
172 171
173 172 mhead = mtail = NULL;
174 173
175 174 resetmnttab(mfp);
176 175 while ((ret = getextmntent(mfp, &mnt, sizeof (struct extmnttab)))
177 - != -1) {
176 + != -1) {
178 177 mntlist_t *mp;
179 178
180 179 if (ret != 0) /* bad entry */
181 180 continue;
182 181
183 182 mp = (mntlist_t *)malloc(sizeof (*mp));
184 183 if (mp == NULL)
185 184 goto alloc_failed;
186 185 if (mhead == NULL)
187 186 mhead = mp;
188 187 else
189 188 mtail->mntl_next = mp;
190 189 mtail = mp;
191 190 mp->mntl_next = NULL;
192 191 mp->mntl_flags = 0;
193 192 if ((mp->mntl_mnt = fsdupmnttab(&mnt)) == NULL)
194 193 goto alloc_failed;
195 194 }
196 195 return (mhead);
197 196
198 197 alloc_failed:
199 198 fsfreemntlist(mhead);
200 199 return (NULL);
201 200 }
202 201
203 202 /*
204 203 * Return the last entry that matches mntin's special
205 204 * device and/or mountpt.
206 205 * Helps to be robust here, so we check for NULL pointers.
207 206 */
208 207 mntlist_t *
|
↓ open down ↓ |
21 lines elided |
↑ open up ↑ |
209 208 fsgetmlast(mntlist_t *ml, struct mnttab *mntin)
210 209 {
211 210 mntlist_t *delete = NULL;
212 211
213 212 for (; ml; ml = ml->mntl_next) {
214 213 if (mntin->mnt_mountp && mntin->mnt_special) {
215 214 /*
216 215 * match if and only if both are equal.
217 216 */
218 217 if ((strcmp(ml->mntl_mnt->mnt_mountp,
219 - mntin->mnt_mountp) == 0) &&
218 + mntin->mnt_mountp) == 0) &&
220 219 (strcmp(ml->mntl_mnt->mnt_special,
221 - mntin->mnt_special) == 0))
220 + mntin->mnt_special) == 0))
222 221 delete = ml;
223 222 } else if (mntin->mnt_mountp) {
224 223 if (strcmp(ml->mntl_mnt->mnt_mountp,
225 - mntin->mnt_mountp) == 0)
224 + mntin->mnt_mountp) == 0)
226 225 delete = ml;
227 226 } else if (mntin->mnt_special) {
228 227 if (strcmp(ml->mntl_mnt->mnt_special,
229 - mntin->mnt_special) == 0)
228 + mntin->mnt_special) == 0)
230 229 delete = ml;
231 - }
230 + }
232 231 }
233 232 return (delete);
234 233 }
235 234
236 235
237 236 /*
238 237 * Returns the mountlevel of the pathname in cp. As examples,
239 238 * / => 1, /bin => 2, /bin/ => 2, ////bin////ls => 3, sdf => 0, etc...
240 239 */
241 240 int
242 241 fsgetmlevel(char *cp)
243 242 {
244 243 int mlevel;
245 244 char *cp1;
246 245
247 246 if (cp == NULL || *cp == NULL || *cp != '/')
248 247 return (0); /* this should never happen */
249 248
250 249 mlevel = 1; /* root (/) is the minimal case */
251 250
252 251 for (cp1 = cp + 1; *cp1; cp++, cp1++)
253 252 if (*cp == '/' && *cp1 != '/') /* "///" counts as 1 */
254 253 mlevel++;
255 254
256 255 return (mlevel);
257 256 }
258 257
259 258 /*
260 259 * Returns non-zero if string s is a member of the strings in ps.
261 260 */
262 261 int
263 262 fsstrinlist(const char *s, const char **ps)
264 263 {
265 264 const char *cp;
266 265 cp = *ps;
267 266 while (cp) {
268 267 if (strcmp(s, cp) == 0)
269 268 return (1);
270 269 ps++;
271 270 cp = *ps;
272 271 }
273 272 return (0);
274 273 }
275 274
276 275 static char *empty_opt_vector[] = {
277 276 NULL
278 277 };
279 278 /*
280 279 * Compare the mount options that were requested by the caller to
281 280 * the options actually supported by the file system. If any requested
282 281 * options are not supported, print a warning message.
283 282 *
284 283 * WARNING: this function modifies the string pointed to by
285 284 * the requested_opts argument.
286 285 *
287 286 * Arguments:
288 287 * requested_opts - the string containing the requested options.
289 288 * actual_opts - the string returned by mount(2), which lists the
290 289 * options actually supported. It is normal for this
291 290 * string to contain more options than the requested options.
292 291 * (The actual options may contain the default options, which
293 292 * may not have been included in the requested options.)
294 293 * special - device being mounted (only used in error messages).
295 294 * mountp - mount point (only used in error messages).
296 295 */
297 296 void
298 297 cmp_requested_to_actual_options(char *requested_opts, char *actual_opts,
299 298 char *special, char *mountp)
300 299 {
301 300 char *option_ptr, *actopt, *equalptr;
|
↓ open down ↓ |
60 lines elided |
↑ open up ↑ |
302 301 int found;
303 302 char *actual_opt_hold, *bufp;
304 303
305 304 if (requested_opts == NULL)
306 305 return;
307 306
308 307 bufp = alloca(strlen(actual_opts) + 1);
309 308
310 309 while (*requested_opts != '\0') {
311 310 (void) getsubopt(&requested_opts, empty_opt_vector,
312 - &option_ptr);
311 + &option_ptr);
313 312
314 313 /*
315 314 * Truncate any "=<value>" string from the end of
316 315 * the option.
317 316 */
318 317 if ((equalptr = strchr(option_ptr, '=')) != NULL)
319 318 *equalptr = '\0';
320 319
321 320 if (*option_ptr == '\0')
322 321 continue;
323 322
324 323 /*
324 + * Whilst we don't need this option to perform a lofi
325 + * mount, let's not be mendacious enough to complain
326 + * about it.
327 + */
328 + if (strcmp(option_ptr, "loop") == 0)
329 + continue;
330 +
331 + /*
325 332 * Search for the requested option in the list of options
326 333 * actually supported.
327 334 */
328 335 found = 0;
329 336
330 337 /*
331 338 * Need to use a copy of actual_opts because getsubopt
332 339 * is destructive and we need to scan the actual_opts
333 340 * string more than once.
334 341 *
335 342 * We also need to reset actual_opt_hold to the
336 343 * beginning of the buffer because getsubopt changes
|
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
337 344 * actual_opt_hold (the pointer).
338 345 */
339 346 actual_opt_hold = bufp;
340 347 if (actual_opts != NULL)
341 348 (void) strcpy(actual_opt_hold, actual_opts);
342 349 else
343 350 *actual_opt_hold = '\0';
344 351
345 352 while (*actual_opt_hold != '\0') {
346 353 (void) getsubopt(&actual_opt_hold, empty_opt_vector,
347 - &actopt);
354 + &actopt);
348 355
349 356 /* Truncate the "=<value>", if any. */
350 357 if ((equalptr = strchr(actopt, '=')) != NULL)
351 358 *equalptr = '\0';
352 359
353 360 if ((strcmp(option_ptr, actopt)) == 0) {
354 361 found = 1;
355 362 break;
356 363 }
357 364 }
358 365
359 366 if (found == 0) {
360 367 /*
361 368 * That we're ignoring the option is always
362 369 * truthful; the old message that the option
363 370 * was unknown is often not correct.
364 371 */
365 372 (void) fprintf(stderr, gettext(
366 373 "mount: %s on %s - WARNING ignoring option "
367 374 "\"%s\"\n"), special, mountp, option_ptr);
368 375 }
369 376 }
370 377 }
371 378 /*
372 379 * FUNCTION: fsgetmaxphys(int *, int *)
373 380 *
374 381 * INPUT: int *maxphys - a pointer to an integer that will hold
375 382 * the value for the system maxphys value.
376 383 * int *error - 0 means completed successfully
377 384 * otherwise this indicates the errno value.
378 385 *
379 386 * RETURNS: int - 0 if maxphys not found
380 387 * - 1 if maxphys is found
381 388 */
382 389 int
383 390 fsgetmaxphys(int *maxphys, int *error) {
384 391
385 392 int gotit = 0;
386 393 int fp = open("/", O_RDONLY);
387 394
388 395 *error = 0;
389 396
390 397 /*
391 398 * For some reason cannot open root as read only. Need a valid file
392 399 * descriptor to call the ufs private ioctl. If this open failes,
393 400 * just assume we cannot get maxphys in this case.
394 401 */
395 402 if (fp == -1) {
396 403 return (gotit);
397 404 }
398 405
399 406 if (ioctl(fp, _FIOGETMAXPHYS, maxphys) == -1) {
400 407 *error = errno;
401 408 (void) close(fp);
402 409 return (gotit);
403 410 }
404 411
405 412 (void) close(fp);
406 413 gotit = 1;
407 414 return (gotit);
408 415
409 416 }
410 417
411 418 /*
412 419 * The below is limited support for zone-aware commands.
413 420 */
414 421 struct zone_summary {
415 422 zoneid_t zoneid;
416 423 char rootpath[MAXPATHLEN];
417 424 size_t rootpathlen;
418 425 };
419 426
420 427 struct zone_summary *
|
↓ open down ↓ |
63 lines elided |
↑ open up ↑ |
421 428 fs_get_zone_summaries(void)
422 429 {
423 430 uint_t numzones = 0, oldnumzones = 0;
424 431 uint_t i, j;
425 432 zoneid_t *ids = NULL;
426 433 struct zone_summary *summaries;
427 434 zoneid_t myzoneid = getzoneid();
428 435
429 436 for (;;) {
430 437 if (zone_list(ids, &numzones) < 0) {
431 - perror("unable to retrieve list of zones");
432 - if (ids != NULL)
433 - free(ids);
434 - return (NULL);
438 + perror("unable to retrieve list of zones");
439 + if (ids != NULL)
440 + free(ids);
441 + return (NULL);
435 442 }
436 443 if (numzones <= oldnumzones)
437 444 break;
438 445 if (ids != NULL)
439 446 free(ids);
440 447 ids = malloc(numzones * sizeof (*ids));
441 448 if (ids == NULL) {
442 449 perror("malloc failed");
443 450 return (NULL);
444 451 }
445 452 oldnumzones = numzones;
446 453 }
447 454
448 455 summaries = malloc((numzones + 1) * sizeof (*summaries));
449 456 if (summaries == NULL) {
450 457 free(ids);
451 458 perror("malloc failed");
452 459 return (NULL);
453 460 }
454 461
455 462
456 463 for (i = 0, j = 0; i < numzones; i++) {
457 464 ssize_t len;
458 465
459 466 if (ids[i] == myzoneid)
460 467 continue;
461 468 len = zone_getattr(ids[i], ZONE_ATTR_ROOT,
462 469 summaries[j].rootpath, sizeof (summaries[j].rootpath));
463 470 if (len < 0) {
464 471 /*
465 472 * Zone must have gone away. Skip.
466 473 */
467 474 continue;
468 475 }
469 476 /*
470 477 * Adding a trailing '/' to the zone's rootpath allows us to
471 478 * use strncmp() to see if a given path resides within that
472 479 * zone.
473 480 *
474 481 * As an example, if the zone's rootpath is "/foo/root",
475 482 * "/foo/root/usr" resides within the zone, while
476 483 * "/foo/rootpath" doesn't.
477 484 */
478 485 (void) strlcat(summaries[j].rootpath, "/",
479 486 sizeof (summaries[j].rootpath));
480 487 summaries[j].rootpathlen = len;
481 488 summaries[j].zoneid = ids[i];
482 489 j++;
483 490 }
484 491 summaries[j].zoneid = -1;
485 492 free(ids);
486 493 return (summaries);
487 494 }
488 495
489 496 static zoneid_t
490 497 fs_find_zone(const struct zone_summary *summaries, const char *mntpt)
491 498 {
492 499 uint_t i;
493 500
494 501 for (i = 0; summaries[i].zoneid != -1; i++) {
495 502 if (strncmp(mntpt, summaries[i].rootpath,
496 503 summaries[i].rootpathlen) == 0)
497 504 return (summaries[i].zoneid);
498 505 }
499 506 /*
500 507 * (-1) is the special token we return to the caller if the mount
501 508 * wasn't found in any other mounts on the system. This means it's
502 509 * only visible to our zone.
503 510 *
504 511 * Odd choice of constant, I know, but it beats calling getzoneid() a
505 512 * million times.
506 513 */
507 514 return (-1);
508 515 }
509 516
510 517 boolean_t
511 518 fs_mount_in_other_zone(const struct zone_summary *summaries, const char *mntpt)
512 519 {
513 520 return (fs_find_zone(summaries, mntpt) != -1);
514 521 }
515 522
516 523 /*
517 524 * List of standard options.
518 525 */
519 526 static const char *stdopts[] = {
520 527 MNTOPT_RO, MNTOPT_RW,
521 528 MNTOPT_SUID, MNTOPT_NOSUID,
522 529 MNTOPT_DEVICES, MNTOPT_NODEVICES,
523 530 MNTOPT_SETUID, MNTOPT_NOSETUID,
524 531 MNTOPT_NBMAND, MNTOPT_NONBMAND,
525 532 MNTOPT_EXEC, MNTOPT_NOEXEC,
526 533 };
527 534
528 535 #define NSTDOPT (sizeof (stdopts) / sizeof (stdopts[0]))
529 536
530 537 static int
531 538 optindx(const char *opt)
532 539 {
533 540 int i;
534 541
535 542 for (i = 0; i < NSTDOPT; i++) {
536 543 if (strcmp(opt, stdopts[i]) == 0)
537 544 return (i);
538 545 }
539 546 return (-1);
540 547 }
541 548
542 549 /*
543 550 * INPUT: filesystem option not recognized by the fs specific option
544 551 * parsing code.
545 552 * OUTPUT: True if and only if the option is one of the standard VFS
546 553 * layer options.
547 554 */
548 555 boolean_t
549 556 fsisstdopt(const char *opt)
550 557 {
551 558 return (optindx(opt) != -1);
552 559 }
|
↓ open down ↓ |
108 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX