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.
36 #include <sys/vfstab.h>
37 #include <sys/mnttab.h>
38 #include <sys/mntent.h>
39 #include <sys/mount.h>
40 #include <sys/filio.h>
41 #include <sys/fs/ufs_filio.h>
43 #include <sys/param.h>
56 * Reads all of the entries from the in-kernel mnttab, and returns the
57 * linked list of the entries.
66 if ((mfp
= fopen(MNTTAB
, "r")) == NULL
) {
67 (void) snprintf(buf
, BUFLEN
, "fsgetmntlist: fopen %s", MNTTAB
);
72 mntl
= fsmkmntlist(mfp
);
79 static struct extmnttab zmnttab
= { 0 };
82 fsdupmnttab(struct extmnttab
*mnt
)
84 struct extmnttab
*new;
86 new = (struct extmnttab
*)malloc(sizeof (*new));
92 * Allocate an extra byte for the mountpoint
93 * name in case a space needs to be added.
95 new->mnt_mountp
= (char *)malloc(strlen(mnt
->mnt_mountp
) + 2);
96 if (new->mnt_mountp
== NULL
)
98 (void) strcpy(new->mnt_mountp
, mnt
->mnt_mountp
);
100 if ((new->mnt_special
= strdup(mnt
->mnt_special
)) == NULL
)
103 if ((new->mnt_fstype
= strdup(mnt
->mnt_fstype
)) == NULL
)
106 if (mnt
->mnt_mntopts
!= NULL
)
107 if ((new->mnt_mntopts
= strdup(mnt
->mnt_mntopts
)) == NULL
)
110 if (mnt
->mnt_time
!= NULL
)
111 if ((new->mnt_time
= strdup(mnt
->mnt_time
)) == NULL
)
114 new->mnt_major
= mnt
->mnt_major
;
115 new->mnt_minor
= mnt
->mnt_minor
;
119 (void) fprintf(stderr
, gettext("fsdupmnttab: Out of memory\n"));
125 * Free a single mnttab structure
128 fsfreemnttab(struct extmnttab
*mnt
)
132 free(mnt
->mnt_special
);
133 free(mnt
->mnt_mountp
);
134 free(mnt
->mnt_fstype
);
135 free(mnt
->mnt_mntopts
);
142 fsfreemntlist(mntlist_t
*mntl
)
147 fsfreemnttab(mntl
->mntl_mnt
);
149 mntl
= mntl
->mntl_next
;
155 * Read the mnttab file and return it as a list of mnttab structs.
156 * Returns NULL if there was a memory failure.
159 fsmkmntlist(FILE *mfp
)
161 struct extmnttab mnt
;
162 mntlist_t
*mhead
, *mtail
;
165 mhead
= mtail
= NULL
;
168 while ((ret
= getextmntent(mfp
, &mnt
, sizeof (struct extmnttab
)))
172 if (ret
!= 0) /* bad entry */
175 mp
= (mntlist_t
*)malloc(sizeof (*mp
));
181 mtail
->mntl_next
= mp
;
183 mp
->mntl_next
= NULL
;
185 if ((mp
->mntl_mnt
= fsdupmnttab(&mnt
)) == NULL
)
191 fsfreemntlist(mhead
);
196 * Return the last entry that matches mntin's special
197 * device and/or mountpt.
198 * Helps to be robust here, so we check for NULL pointers.
201 fsgetmlast(mntlist_t
*ml
, struct mnttab
*mntin
)
203 mntlist_t
*delete = NULL
;
205 for (; ml
; ml
= ml
->mntl_next
) {
206 if (mntin
->mnt_mountp
&& mntin
->mnt_special
) {
208 * match if and only if both are equal.
210 if ((strcmp(ml
->mntl_mnt
->mnt_mountp
,
211 mntin
->mnt_mountp
) == 0) &&
212 (strcmp(ml
->mntl_mnt
->mnt_special
,
213 mntin
->mnt_special
) == 0))
215 } else if (mntin
->mnt_mountp
) {
216 if (strcmp(ml
->mntl_mnt
->mnt_mountp
,
217 mntin
->mnt_mountp
) == 0)
219 } else if (mntin
->mnt_special
) {
220 if (strcmp(ml
->mntl_mnt
->mnt_special
,
221 mntin
->mnt_special
) == 0)
230 * Returns the mountlevel of the pathname in cp. As examples,
231 * / => 1, /bin => 2, /bin/ => 2, ////bin////ls => 3, sdf => 0, etc...
234 fsgetmlevel(char *cp
)
239 if (cp
== NULL
|| *cp
== '\0' || *cp
!= '/')
240 return (0); /* this should never happen */
242 mlevel
= 1; /* root (/) is the minimal case */
244 for (cp1
= cp
+ 1; *cp1
; cp
++, cp1
++)
245 if (*cp
== '/' && *cp1
!= '/') /* "///" counts as 1 */
252 * Returns non-zero if string s is a member of the strings in ps.
255 fsstrinlist(const char *s
, const char **ps
)
260 if (strcmp(s
, cp
) == 0)
268 static char *empty_opt_vector
[] = {
272 * Compare the mount options that were requested by the caller to
273 * the options actually supported by the file system. If any requested
274 * options are not supported, print a warning message.
276 * WARNING: this function modifies the string pointed to by
277 * the requested_opts argument.
280 * requested_opts - the string containing the requested options.
281 * actual_opts - the string returned by mount(2), which lists the
282 * options actually supported. It is normal for this
283 * string to contain more options than the requested options.
284 * (The actual options may contain the default options, which
285 * may not have been included in the requested options.)
286 * special - device being mounted (only used in error messages).
287 * mountp - mount point (only used in error messages).
290 cmp_requested_to_actual_options(char *requested_opts
, char *actual_opts
,
291 char *special
, char *mountp
)
293 char *option_ptr
, *actopt
, *equalptr
;
295 char *actual_opt_hold
, *bufp
;
297 if (requested_opts
== NULL
)
300 bufp
= alloca(strlen(actual_opts
) + 1);
302 while (*requested_opts
!= '\0') {
303 (void) getsubopt(&requested_opts
, empty_opt_vector
,
307 * Truncate any "=<value>" string from the end of
310 if ((equalptr
= strchr(option_ptr
, '=')) != NULL
)
313 if (*option_ptr
== '\0')
317 * Whilst we don't need this option to perform a lofi
318 * mount, let's not be mendacious enough to complain
321 if (strcmp(option_ptr
, "loop") == 0)
325 * Search for the requested option in the list of options
326 * actually supported.
331 * Need to use a copy of actual_opts because getsubopt
332 * is destructive and we need to scan the actual_opts
333 * string more than once.
335 * We also need to reset actual_opt_hold to the
336 * beginning of the buffer because getsubopt changes
337 * actual_opt_hold (the pointer).
339 actual_opt_hold
= bufp
;
340 if (actual_opts
!= NULL
)
341 (void) strcpy(actual_opt_hold
, actual_opts
);
343 *actual_opt_hold
= '\0';
345 while (*actual_opt_hold
!= '\0') {
346 (void) getsubopt(&actual_opt_hold
, empty_opt_vector
,
349 /* Truncate the "=<value>", if any. */
350 if ((equalptr
= strchr(actopt
, '=')) != NULL
)
353 if ((strcmp(option_ptr
, actopt
)) == 0) {
361 * That we're ignoring the option is always
362 * truthful; the old message that the option
363 * was unknown is often not correct.
365 (void) fprintf(stderr
, gettext(
366 "mount: %s on %s - WARNING ignoring option "
367 "\"%s\"\n"), special
, mountp
, option_ptr
);
372 * FUNCTION: fsgetmaxphys(int *, int *)
374 * INPUT: int *maxphys - a pointer to an integer that will hold
375 * the value for the system maxphys value.
376 * int *error - 0 means completed successfully
377 * otherwise this indicates the errno value.
379 * RETURNS: int - 0 if maxphys not found
380 * - 1 if maxphys is found
383 fsgetmaxphys(int *maxphys
, int *error
) {
386 int fp
= open("/", O_RDONLY
);
391 * For some reason cannot open root as read only. Need a valid file
392 * descriptor to call the ufs private ioctl. If this open failes,
393 * just assume we cannot get maxphys in this case.
399 if (ioctl(fp
, _FIOGETMAXPHYS
, maxphys
) == -1) {
412 * The below is limited support for zone-aware commands.
414 struct zone_summary
{
416 char rootpath
[MAXPATHLEN
];
420 struct zone_summary
*
421 fs_get_zone_summaries(void)
423 uint_t numzones
= 0, oldnumzones
= 0;
425 zoneid_t
*ids
= NULL
;
426 struct zone_summary
*summaries
;
427 zoneid_t myzoneid
= getzoneid();
430 if (zone_list(ids
, &numzones
) < 0) {
431 perror("unable to retrieve list of zones");
435 if (numzones
<= oldnumzones
)
438 ids
= malloc(numzones
* sizeof (*ids
));
440 perror("malloc failed");
443 oldnumzones
= numzones
;
446 summaries
= malloc((numzones
+ 1) * sizeof (*summaries
));
447 if (summaries
== NULL
) {
449 perror("malloc failed");
454 for (i
= 0, j
= 0; i
< numzones
; i
++) {
457 if (ids
[i
] == myzoneid
)
459 len
= zone_getattr(ids
[i
], ZONE_ATTR_ROOT
,
460 summaries
[j
].rootpath
, sizeof (summaries
[j
].rootpath
));
463 * Zone must have gone away. Skip.
468 * Adding a trailing '/' to the zone's rootpath allows us to
469 * use strncmp() to see if a given path resides within that
472 * As an example, if the zone's rootpath is "/foo/root",
473 * "/foo/root/usr" resides within the zone, while
474 * "/foo/rootpath" doesn't.
476 (void) strlcat(summaries
[j
].rootpath
, "/",
477 sizeof (summaries
[j
].rootpath
));
478 summaries
[j
].rootpathlen
= len
;
479 summaries
[j
].zoneid
= ids
[i
];
482 summaries
[j
].zoneid
= -1;
488 fs_find_zone(const struct zone_summary
*summaries
, const char *mntpt
)
492 for (i
= 0; summaries
[i
].zoneid
!= -1; i
++) {
493 if (strncmp(mntpt
, summaries
[i
].rootpath
,
494 summaries
[i
].rootpathlen
) == 0)
495 return (summaries
[i
].zoneid
);
498 * (-1) is the special token we return to the caller if the mount
499 * wasn't found in any other mounts on the system. This means it's
500 * only visible to our zone.
502 * Odd choice of constant, I know, but it beats calling getzoneid() a
509 fs_mount_in_other_zone(const struct zone_summary
*summaries
, const char *mntpt
)
511 return (fs_find_zone(summaries
, mntpt
) != -1);
515 * List of standard options.
517 static const char *stdopts
[] = {
518 MNTOPT_RO
, MNTOPT_RW
,
519 MNTOPT_SUID
, MNTOPT_NOSUID
,
520 MNTOPT_DEVICES
, MNTOPT_NODEVICES
,
521 MNTOPT_SETUID
, MNTOPT_NOSETUID
,
522 MNTOPT_NBMAND
, MNTOPT_NONBMAND
,
523 MNTOPT_EXEC
, MNTOPT_NOEXEC
,
526 #define NSTDOPT (sizeof (stdopts) / sizeof (stdopts[0]))
529 optindx(const char *opt
)
533 for (i
= 0; i
< NSTDOPT
; i
++) {
534 if (strcmp(opt
, stdopts
[i
]) == 0)
541 * INPUT: filesystem option not recognized by the fs specific option
543 * OUTPUT: True if and only if the option is one of the standard VFS
547 fsisstdopt(const char *opt
)
549 return (optindx(opt
) != -1);