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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
38 #include <sys/vfstab.h>
39 #include <sys/mnttab.h>
40 #include <sys/mntent.h>
41 #include <sys/mount.h>
42 #include <sys/filio.h>
43 #include <sys/fs/ufs_filio.h>
45 #include <sys/param.h>
58 * Reads all of the entries from the in-kernel mnttab, and returns the
59 * linked list of the entries.
68 if ((mfp
= fopen(MNTTAB
, "r")) == NULL
) {
69 (void) snprintf(buf
, BUFLEN
, "fsgetmntlist: fopen %s", MNTTAB
);
74 mntl
= fsmkmntlist(mfp
);
81 static struct extmnttab zmnttab
= { 0 };
84 fsdupmnttab(struct extmnttab
*mnt
)
86 struct extmnttab
*new;
88 new = (struct extmnttab
*)malloc(sizeof (*new));
94 * Allocate an extra byte for the mountpoint
95 * name in case a space needs to be added.
97 new->mnt_mountp
= (char *)malloc(strlen(mnt
->mnt_mountp
) + 2);
98 if (new->mnt_mountp
== NULL
)
100 (void) strcpy(new->mnt_mountp
, mnt
->mnt_mountp
);
102 if ((new->mnt_special
= strdup(mnt
->mnt_special
)) == NULL
)
105 if ((new->mnt_fstype
= strdup(mnt
->mnt_fstype
)) == NULL
)
108 if (mnt
->mnt_mntopts
!= NULL
)
109 if ((new->mnt_mntopts
= strdup(mnt
->mnt_mntopts
)) == NULL
)
112 if (mnt
->mnt_time
!= NULL
)
113 if ((new->mnt_time
= strdup(mnt
->mnt_time
)) == NULL
)
116 new->mnt_major
= mnt
->mnt_major
;
117 new->mnt_minor
= mnt
->mnt_minor
;
121 (void) fprintf(stderr
, gettext("fsdupmnttab: Out of memory\n"));
127 * Free a single mnttab structure
130 fsfreemnttab(struct extmnttab
*mnt
)
134 if (mnt
->mnt_special
)
135 free(mnt
->mnt_special
);
137 free(mnt
->mnt_mountp
);
139 free(mnt
->mnt_fstype
);
140 if (mnt
->mnt_mntopts
)
141 free(mnt
->mnt_mntopts
);
149 fsfreemntlist(mntlist_t
*mntl
)
154 fsfreemnttab(mntl
->mntl_mnt
);
156 mntl
= mntl
->mntl_next
;
162 * Read the mnttab file and return it as a list of mnttab structs.
163 * Returns NULL if there was a memory failure.
166 fsmkmntlist(FILE *mfp
)
168 struct extmnttab mnt
;
169 mntlist_t
*mhead
, *mtail
;
172 mhead
= mtail
= NULL
;
175 while ((ret
= getextmntent(mfp
, &mnt
, sizeof (struct extmnttab
)))
179 if (ret
!= 0) /* bad entry */
182 mp
= (mntlist_t
*)malloc(sizeof (*mp
));
188 mtail
->mntl_next
= mp
;
190 mp
->mntl_next
= NULL
;
192 if ((mp
->mntl_mnt
= fsdupmnttab(&mnt
)) == NULL
)
198 fsfreemntlist(mhead
);
203 * Return the last entry that matches mntin's special
204 * device and/or mountpt.
205 * Helps to be robust here, so we check for NULL pointers.
208 fsgetmlast(mntlist_t
*ml
, struct mnttab
*mntin
)
210 mntlist_t
*delete = NULL
;
212 for (; ml
; ml
= ml
->mntl_next
) {
213 if (mntin
->mnt_mountp
&& mntin
->mnt_special
) {
215 * match if and only if both are equal.
217 if ((strcmp(ml
->mntl_mnt
->mnt_mountp
,
218 mntin
->mnt_mountp
) == 0) &&
219 (strcmp(ml
->mntl_mnt
->mnt_special
,
220 mntin
->mnt_special
) == 0))
222 } else if (mntin
->mnt_mountp
) {
223 if (strcmp(ml
->mntl_mnt
->mnt_mountp
,
224 mntin
->mnt_mountp
) == 0)
226 } else if (mntin
->mnt_special
) {
227 if (strcmp(ml
->mntl_mnt
->mnt_special
,
228 mntin
->mnt_special
) == 0)
237 * Returns the mountlevel of the pathname in cp. As examples,
238 * / => 1, /bin => 2, /bin/ => 2, ////bin////ls => 3, sdf => 0, etc...
241 fsgetmlevel(char *cp
)
246 if (cp
== NULL
|| *cp
== NULL
|| *cp
!= '/')
247 return (0); /* this should never happen */
249 mlevel
= 1; /* root (/) is the minimal case */
251 for (cp1
= cp
+ 1; *cp1
; cp
++, cp1
++)
252 if (*cp
== '/' && *cp1
!= '/') /* "///" counts as 1 */
259 * Returns non-zero if string s is a member of the strings in ps.
262 fsstrinlist(const char *s
, const char **ps
)
267 if (strcmp(s
, cp
) == 0)
275 static char *empty_opt_vector
[] = {
279 * Compare the mount options that were requested by the caller to
280 * the options actually supported by the file system. If any requested
281 * options are not supported, print a warning message.
283 * WARNING: this function modifies the string pointed to by
284 * the requested_opts argument.
287 * requested_opts - the string containing the requested options.
288 * actual_opts - the string returned by mount(2), which lists the
289 * options actually supported. It is normal for this
290 * string to contain more options than the requested options.
291 * (The actual options may contain the default options, which
292 * may not have been included in the requested options.)
293 * special - device being mounted (only used in error messages).
294 * mountp - mount point (only used in error messages).
297 cmp_requested_to_actual_options(char *requested_opts
, char *actual_opts
,
298 char *special
, char *mountp
)
300 char *option_ptr
, *actopt
, *equalptr
;
302 char *actual_opt_hold
, *bufp
;
304 if (requested_opts
== NULL
)
307 bufp
= alloca(strlen(actual_opts
) + 1);
309 while (*requested_opts
!= '\0') {
310 (void) getsubopt(&requested_opts
, empty_opt_vector
,
314 * Truncate any "=<value>" string from the end of
317 if ((equalptr
= strchr(option_ptr
, '=')) != NULL
)
320 if (*option_ptr
== '\0')
324 * Whilst we don't need this option to perform a lofi
325 * mount, let's not be mendacious enough to complain
328 if (strcmp(option_ptr
, "loop") == 0)
332 * Search for the requested option in the list of options
333 * actually supported.
338 * Need to use a copy of actual_opts because getsubopt
339 * is destructive and we need to scan the actual_opts
340 * string more than once.
342 * We also need to reset actual_opt_hold to the
343 * beginning of the buffer because getsubopt changes
344 * actual_opt_hold (the pointer).
346 actual_opt_hold
= bufp
;
347 if (actual_opts
!= NULL
)
348 (void) strcpy(actual_opt_hold
, actual_opts
);
350 *actual_opt_hold
= '\0';
352 while (*actual_opt_hold
!= '\0') {
353 (void) getsubopt(&actual_opt_hold
, empty_opt_vector
,
356 /* Truncate the "=<value>", if any. */
357 if ((equalptr
= strchr(actopt
, '=')) != NULL
)
360 if ((strcmp(option_ptr
, actopt
)) == 0) {
368 * That we're ignoring the option is always
369 * truthful; the old message that the option
370 * was unknown is often not correct.
372 (void) fprintf(stderr
, gettext(
373 "mount: %s on %s - WARNING ignoring option "
374 "\"%s\"\n"), special
, mountp
, option_ptr
);
379 * FUNCTION: fsgetmaxphys(int *, int *)
381 * INPUT: int *maxphys - a pointer to an integer that will hold
382 * the value for the system maxphys value.
383 * int *error - 0 means completed successfully
384 * otherwise this indicates the errno value.
386 * RETURNS: int - 0 if maxphys not found
387 * - 1 if maxphys is found
390 fsgetmaxphys(int *maxphys
, int *error
) {
393 int fp
= open("/", O_RDONLY
);
398 * For some reason cannot open root as read only. Need a valid file
399 * descriptor to call the ufs private ioctl. If this open failes,
400 * just assume we cannot get maxphys in this case.
406 if (ioctl(fp
, _FIOGETMAXPHYS
, maxphys
) == -1) {
419 * The below is limited support for zone-aware commands.
421 struct zone_summary
{
423 char rootpath
[MAXPATHLEN
];
427 struct zone_summary
*
428 fs_get_zone_summaries(void)
430 uint_t numzones
= 0, oldnumzones
= 0;
432 zoneid_t
*ids
= NULL
;
433 struct zone_summary
*summaries
;
434 zoneid_t myzoneid
= getzoneid();
437 if (zone_list(ids
, &numzones
) < 0) {
438 perror("unable to retrieve list of zones");
443 if (numzones
<= oldnumzones
)
447 ids
= malloc(numzones
* sizeof (*ids
));
449 perror("malloc failed");
452 oldnumzones
= numzones
;
455 summaries
= malloc((numzones
+ 1) * sizeof (*summaries
));
456 if (summaries
== NULL
) {
458 perror("malloc failed");
463 for (i
= 0, j
= 0; i
< numzones
; i
++) {
466 if (ids
[i
] == myzoneid
)
468 len
= zone_getattr(ids
[i
], ZONE_ATTR_ROOT
,
469 summaries
[j
].rootpath
, sizeof (summaries
[j
].rootpath
));
472 * Zone must have gone away. Skip.
477 * Adding a trailing '/' to the zone's rootpath allows us to
478 * use strncmp() to see if a given path resides within that
481 * As an example, if the zone's rootpath is "/foo/root",
482 * "/foo/root/usr" resides within the zone, while
483 * "/foo/rootpath" doesn't.
485 (void) strlcat(summaries
[j
].rootpath
, "/",
486 sizeof (summaries
[j
].rootpath
));
487 summaries
[j
].rootpathlen
= len
;
488 summaries
[j
].zoneid
= ids
[i
];
491 summaries
[j
].zoneid
= -1;
497 fs_find_zone(const struct zone_summary
*summaries
, const char *mntpt
)
501 for (i
= 0; summaries
[i
].zoneid
!= -1; i
++) {
502 if (strncmp(mntpt
, summaries
[i
].rootpath
,
503 summaries
[i
].rootpathlen
) == 0)
504 return (summaries
[i
].zoneid
);
507 * (-1) is the special token we return to the caller if the mount
508 * wasn't found in any other mounts on the system. This means it's
509 * only visible to our zone.
511 * Odd choice of constant, I know, but it beats calling getzoneid() a
518 fs_mount_in_other_zone(const struct zone_summary
*summaries
, const char *mntpt
)
520 return (fs_find_zone(summaries
, mntpt
) != -1);
524 * List of standard options.
526 static const char *stdopts
[] = {
527 MNTOPT_RO
, MNTOPT_RW
,
528 MNTOPT_SUID
, MNTOPT_NOSUID
,
529 MNTOPT_DEVICES
, MNTOPT_NODEVICES
,
530 MNTOPT_SETUID
, MNTOPT_NOSETUID
,
531 MNTOPT_NBMAND
, MNTOPT_NONBMAND
,
532 MNTOPT_EXEC
, MNTOPT_NOEXEC
,
535 #define NSTDOPT (sizeof (stdopts) / sizeof (stdopts[0]))
538 optindx(const char *opt
)
542 for (i
= 0; i
< NSTDOPT
; i
++) {
543 if (strcmp(opt
, stdopts
[i
]) == 0)
550 * INPUT: filesystem option not recognized by the fs specific option
552 * OUTPUT: True if and only if the option is one of the standard VFS
556 fsisstdopt(const char *opt
)
558 return (optindx(opt
) != -1);