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
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * Traverses /etc/mnttab in order to find mounted file systems.
36 #include <sys/mnttab.h>
37 #include <sys/types.h>
38 #include <sys/statvfs.h>
47 * Private method declarations
50 static fs_mntlist_t
*create_mntlist_entry(struct mnttab mnttab_entry
);
51 static fs_mntlist_t
*create_extmntlist_entry(struct extmnttab mnttab_entry
);
52 static struct mnttab
*create_mnttab_filter(char *resource
, char *mountp
,
53 char *fstype
, char *mntopts
, char *time
);
54 static void find_overlayed_filesystems(fs_mntlist_t
*mnt_list
,
55 boolean_t filtered_list
, int *errp
);
56 static void free_mnttab_entry(struct mnttab
*mnttab_entry
);
57 static char *is_option(char *opt_string
, char *opt
, int *errp
);
58 boolean_t
is_overlayed(fs_mntlist_t
*complete_mnt_list
,
67 fs_free_mount_list(fs_mntlist_t
*headp
) {
70 while (headp
!= NULL
) {
72 free(headp
->resource
);
82 } /* fs_free_mount_list */
85 fs_get_availablesize(char *mntpnt
, int *errp
) {
86 struct statvfs64 stvfs
;
87 unsigned long long availablesize
;
92 * Set errp to invalid parameter - EINVAL
98 if (statvfs64(mntpnt
, &stvfs
) != -1) {
99 availablesize
= stvfs
.f_bfree
;
100 availablesize
= availablesize
* stvfs
.f_frsize
;
104 } /* if (statvfs64(mntpnt, &stvfs) != -1) */
106 return (availablesize
);
107 } /* fs_get_availablesize */
110 fs_get_avail_for_nonsuperuser_size(char *mntpnt
, int *errp
) {
111 struct statvfs64 stvfs
;
112 unsigned long long avail_for_nonsu_size
;
115 if (mntpnt
== NULL
) {
117 * Set errp to invalid parameter - EINVAL
123 if (statvfs64(mntpnt
, &stvfs
) != -1) {
124 avail_for_nonsu_size
= stvfs
.f_bavail
;
125 avail_for_nonsu_size
= avail_for_nonsu_size
* stvfs
.f_frsize
;
129 } /* if (statvfs64(mntpnt, &stvfs) != -1) */
131 return (avail_for_nonsu_size
);
132 } /* fs_get_avail_for_nonsuperuser_size(char *mntpnt, int *errp) */
135 fs_get_blocksize(char *mntpnt
, int *errp
) {
136 struct statvfs64 stvfs
;
137 unsigned long long blocksize
;
140 if (mntpnt
== NULL
) {
142 * Set errp to invalid parameter - EINVAL
148 if (statvfs64(mntpnt
, &stvfs
) != -1) {
149 blocksize
= stvfs
.f_bsize
;
153 } /* if (statvfs64(mntpnt, &stvfs) != -1) */
156 } /* fs_get_blocksize */
159 fs_get_filtered_mount_list(char *resource
, char *mountp
, char *fstype
,
160 char *mntopts
, char *time
, boolean_t find_overlays
, int *errp
) {
171 if ((fp
= fopen(MNTTAB
, "r")) != NULL
) {
172 struct mnttab mnttab_entry
;
173 struct mnttab
*search_entry
;
175 search_entry
= create_mnttab_filter(resource
, mountp
, fstype
,
177 if (search_entry
== NULL
) {
181 fs_free_mount_list(headp
);
187 while (getmntany(fp
, &mnttab_entry
, search_entry
) == 0) {
188 /* Add to list to be returned */
189 newp
= create_mntlist_entry(mnttab_entry
);
195 fs_free_mount_list(headp
);
210 free_mnttab_entry(search_entry
);
212 if (find_overlays
== B_TRUE
)
213 find_overlayed_filesystems(headp
, B_TRUE
, errp
);
216 } /* if ((fp = fopen(MNTTAB, "r")) != NULL) */
219 } /* fs_get_filtered_mount_list */
222 fs_get_fragsize(char *mntpnt
, int *errp
) {
223 struct statvfs64 stvfs
;
224 unsigned long fragsize
;
227 if (mntpnt
== NULL
) {
229 * Set errp to invalid parameter - EINVAL
235 if (statvfs64(mntpnt
, &stvfs
) != -1) {
236 fragsize
= stvfs
.f_frsize
;
240 } /* (statvfs64(mntpnt, &stvfs) != -1) */
243 } /* fs_get_fragsize(char *mntpnt, int *errp) */
246 fs_get_maxfilenamelen(char *mntpnt
, int *errp
) {
247 long int returned_val
;
248 unsigned long maxfilenamelen
;
251 if (mntpnt
== NULL
) {
253 * Set errp to invalid parameter - EINVAL
259 returned_val
= pathconf(mntpnt
, _PC_PATH_MAX
);
260 if (returned_val
!= -1) {
261 maxfilenamelen
= (unsigned long)returned_val
;
267 return (maxfilenamelen
);
268 } /* fs_get_maxfilenamelen */
271 fs_get_mounts_by_mntopt(char *mntopt
, boolean_t find_overlays
, int *errp
) {
285 if ((fp
= fopen(MNTTAB
, "r")) != NULL
) {
286 struct mnttab mnttab_entry
;
289 while (getmntent(fp
, &mnttab_entry
) == 0) {
290 opt_found
= hasmntopt(&mnttab_entry
, mntopt
);
291 if (opt_found
!= NULL
) {
293 * Add to list to be returned
295 newp
= create_mntlist_entry(mnttab_entry
);
301 fs_free_mount_list(headp
);
314 } /* if (char != NULL) */
317 if (find_overlays
== B_TRUE
)
318 find_overlayed_filesystems(headp
, B_TRUE
, errp
);
322 } /* if ((fp = fopen(MNTTAB, "r")) != NULL) */
325 } /* fs_get_mounts_by_mntpnt */
328 fs_get_mount_list(boolean_t find_overlays
, int *errp
) {
338 if ((fp
= fopen(MNTTAB
, "r")) != NULL
) {
339 struct extmnttab mnttab_entry
;
344 * getextmntent() Is used here so that we can use mnt_major
345 * and mnt_minor to get the fsid. The fsid is used when
346 * getting mount information from kstat.
348 while (getextmntent(fp
, &mnttab_entry
,
349 sizeof (struct extmnttab
)) == 0) {
351 newp
= create_extmntlist_entry(mnttab_entry
);
357 fs_free_mount_list(headp
);
371 } /* while (getmntent(fp, &mnttab_entry) == 0) */
374 find_overlayed_filesystems(headp
, B_FALSE
, errp
);
377 } /* if ((fp = fopen(MNTTAB, "r")) != NULL) */
380 * Caller must free the mount list
383 } /* fs_get_mount_list */
386 fs_is_readonly(char *mntpnt
, int *errp
) {
387 struct statvfs64 stvfs
;
391 if (mntpnt
== NULL
) {
393 * Set errp to invalid parameter - EINVAL
399 if (statvfs64(mntpnt
, &stvfs
) != -1) {
400 readonly
= stvfs
.f_flag
& ST_RDONLY
;
407 } /* fs_is_readonly */
410 * This method will parse the given comma delimited option list (optlist) for
411 * the option passed into the function. If the option (opt) to search for
412 * is one that sets a value such as onerror=, the value to the right of the "="
413 * character will be returned from the function. This function expects the
414 * opt parameter to have the "=" character appended when searching for options
417 * If the option is found in the given optlist, the function will return the
418 * option as found in the option list.
419 * If the option is not found in the given optlist, the function will return
421 * If an error occurs, the function will return NULL and the errp will
422 * reflect the error that has occurred.
424 * NOTE: The caller must free the space allocated for the return value by using
428 fs_parse_optlist_for_option(char *optlist
, char *opt
, int *errp
) {
429 const char *delimiter
= ",";
435 optlist_copy
= strdup(optlist
);
436 if (optlist_copy
== NULL
) {
441 token
= strtok(optlist_copy
, delimiter
);
443 * Check to see if we have found the option.
448 } else if ((return_value
= is_option(token
, opt
, errp
)) != NULL
) {
450 return (return_value
);
453 while (token
!= NULL
) {
455 token
= strtok(NULL
, delimiter
);
457 * If token is NULL then then we are at the end of the list
458 * and we can return NULL because the option was never found in
464 } else if ((return_value
=
465 is_option(token
, opt
, errp
)) != NULL
) {
468 return (return_value
);
477 fs_get_totalsize(char *mntpnt
, int *errp
) {
478 struct statvfs64 stvfs
;
479 unsigned long long totalsize
;
482 if (mntpnt
== NULL
) {
484 * Set errp to invalid parameter - EINVAL
490 if (statvfs64(mntpnt
, &stvfs
) != -1) {
491 totalsize
= stvfs
.f_blocks
;
492 totalsize
= totalsize
* stvfs
.f_frsize
;
497 } /* if (statvfs64(mntpnt, &stvfs) != -1) */
500 } /* fs_get_totalsize */
503 fs_get_usedsize(char *mntpnt
, int *errp
) {
504 struct statvfs64 stvfs
;
505 unsigned long long usedsize
;
508 if (mntpnt
== NULL
) {
510 * Set errp to invalid parameter - EINVAL
516 if (statvfs64(mntpnt
, &stvfs
) != -1) {
517 usedsize
= stvfs
.f_blocks
- stvfs
.f_bfree
;
518 usedsize
= usedsize
* stvfs
.f_frsize
;
522 } /* if (statvfs64(mntpnt, &stvfs) != -1) */
525 } /* fs_get_usedsize */
531 static fs_mntlist_t
*
532 create_mntlist_entry(struct mnttab mnttab_entry
) {
536 newp
= (fs_mntlist_t
*)calloc((size_t)1,
537 (size_t)sizeof (fs_mntlist_t
));
546 newp
->resource
= strdup(mnttab_entry
.mnt_special
);
547 if (newp
->resource
== NULL
) {
551 fs_free_mount_list(newp
);
554 newp
->mountp
= strdup(mnttab_entry
.mnt_mountp
);
555 if (newp
->mountp
== NULL
) {
559 fs_free_mount_list(newp
);
562 newp
->fstype
= strdup(mnttab_entry
.mnt_fstype
);
563 if (newp
->fstype
== NULL
) {
567 fs_free_mount_list(newp
);
570 newp
->mntopts
= strdup(mnttab_entry
.mnt_mntopts
);
571 if (newp
->mntopts
== NULL
) {
575 fs_free_mount_list(newp
);
578 newp
->time
= strdup(mnttab_entry
.mnt_time
);
579 if (newp
->time
== NULL
) {
583 fs_free_mount_list(newp
);
589 } /* create_mntlist_entry */
591 static fs_mntlist_t
*
592 create_extmntlist_entry(struct extmnttab mnttab_entry
) {
596 newp
= (fs_mntlist_t
*)calloc((size_t)1,
597 (size_t)sizeof (fs_mntlist_t
));
606 newp
->resource
= strdup(mnttab_entry
.mnt_special
);
607 if (newp
->resource
== NULL
) {
611 fs_free_mount_list(newp
);
614 newp
->mountp
= strdup(mnttab_entry
.mnt_mountp
);
615 if (newp
->mountp
== NULL
) {
619 fs_free_mount_list(newp
);
622 newp
->fstype
= strdup(mnttab_entry
.mnt_fstype
);
623 if (newp
->fstype
== NULL
) {
627 fs_free_mount_list(newp
);
630 newp
->mntopts
= strdup(mnttab_entry
.mnt_mntopts
);
631 if (newp
->mntopts
== NULL
) {
635 fs_free_mount_list(newp
);
638 newp
->time
= strdup(mnttab_entry
.mnt_time
);
639 if (newp
->time
== NULL
) {
643 fs_free_mount_list(newp
);
646 newp
->major
= mnttab_entry
.mnt_major
;
648 newp
->minor
= mnttab_entry
.mnt_minor
;
653 } /* create_extmntlist_entry */
655 static struct mnttab
*
656 create_mnttab_filter(char *resource
, char *mountp
, char *fstype
, char *mntopts
,
659 struct mnttab
*search_entry
;
661 search_entry
= (struct mnttab
*)calloc((size_t)1,
662 (size_t)sizeof (struct mnttab
));
664 if (search_entry
== NULL
) {
671 if (resource
!= NULL
) {
672 search_entry
->mnt_special
= strdup(resource
);
673 if (search_entry
->mnt_special
== NULL
) {
677 free_mnttab_entry(search_entry
);
682 if (mountp
!= NULL
) {
683 search_entry
->mnt_mountp
= strdup(mountp
);
684 if (search_entry
->mnt_mountp
== NULL
) {
688 free_mnttab_entry(search_entry
);
693 if (fstype
!= NULL
) {
694 search_entry
->mnt_fstype
= strdup(fstype
);
695 if (search_entry
->mnt_fstype
== NULL
) {
699 free_mnttab_entry(search_entry
);
704 if (mntopts
!= NULL
) {
705 search_entry
->mnt_mntopts
= strdup(mntopts
);
706 if (search_entry
->mnt_mntopts
== NULL
) {
710 free_mnttab_entry(search_entry
);
716 search_entry
->mnt_time
= strdup(time
);
717 if (search_entry
->mnt_time
== NULL
) {
721 free_mnttab_entry(search_entry
);
726 return (search_entry
);
727 } /* create_mnttab_filter */
730 * We will go through the /etc/mnttab entries to determine the
731 * instances of overlayed file systems. We do this with the following
734 * 1.) Entries in mnttab are ordered in the way that the most recent
735 * mounts are placed at the bottom of /etc/mnttab. Contract to be
737 * 2.) Mnttab entries that are returned from all mnttab library
738 * functions such as getmntent, getextmntent, and getmntany in the order
739 * as they are found in /etc/mnttab. Goes along with assumption #1.
740 * 3.) All automounted NFS file systems will have an autofs entry and
741 * a NFS entry in /etc/mnttab with the same mount point. Autofs
742 * entries can be ignored.
743 * 4.) The device id (dev=) uniquely identifies a mounted file system
746 * Algorithm explanation:
747 * ----------------------
748 * For each mnt_list entry
749 * 1.) Compare it to each /etc/mnttab entry starting at the point in mnttab
750 * where the mnt_list entry mount is and look for matching mount points,
751 * but ignore all "autofs" entries
752 * If a two entries are found with the same mount point mark the mnt_list
753 * entry as being overlayed.
756 find_overlayed_filesystems(fs_mntlist_t
*mnt_list
,
757 boolean_t filtered_list
, int *errp
) {
759 boolean_t exit
= B_FALSE
;
760 fs_mntlist_t
*mnt_list_to_compare
;
764 if (filtered_list
== B_TRUE
) {
766 * Get the complete mount list
768 mnt_list_to_compare
= fs_get_mount_list(B_FALSE
, errp
);
769 if (mnt_list_to_compare
== NULL
) {
771 * If complete_mnt_list is NULL there are two
773 * 1.) There are simply no entries in /etc/mnttab.
774 * 2.) An error was encountered. errp will reflect
781 mnt_list_to_compare
= mnt_list
;
784 tmp
= mnt_list_to_compare
;
786 while (mnt_list
!= NULL
) {
787 if (!(strcmp(mnt_list
->fstype
, "autofs") == 0)) {
790 dev_id
= fs_parse_optlist_for_option(mnt_list
->mntopts
,
792 if (dev_id
== NULL
) {
797 while (tmp
!= NULL
&& exit
== B_FALSE
) {
798 if (!(strcmp(tmp
->fstype
, "autofs")) == 0) {
802 fs_parse_optlist_for_option(
803 tmp
->mntopts
, "dev=", errp
);
804 if (tmp_dev_id
== NULL
) {
808 if (strcmp(tmp_dev_id
, dev_id
) == 0) {
810 * Start searching for an
813 mnt_list
->overlayed
=
821 } /* while (tmp != NULL && exit == B_FALSE) */
823 } /* if (!(strcmp(mnt_list->fstype, "autofs") == 0)) */
824 mnt_list
= mnt_list
->next
;
825 } /* while (mnt_list != NULL) */
827 if (filtered_list
== B_TRUE
)
828 fs_free_mount_list(mnt_list_to_compare
);
829 } /* find_overlayed_filesystems */
832 free_mnttab_entry(struct mnttab
*mnttab_entry
) {
834 free(mnttab_entry
->mnt_special
);
835 free(mnttab_entry
->mnt_mountp
);
836 free(mnttab_entry
->mnt_fstype
);
837 free(mnttab_entry
->mnt_mntopts
);
838 free(mnttab_entry
->mnt_time
);
842 } /* free_mnttab_entry */
845 is_option(char *opt_string
, char *opt
, int *errp
) {
846 char *equalsign
= "=";
847 char *found_equalsign
;
851 found_equalsign
= strstr(opt
, equalsign
);
854 * If found_equalsign is NULL then we did not find an equal sign
855 * in the option we are to be looking for.
857 if (found_equalsign
== NULL
) {
858 if (strcmp(opt_string
, opt
) == 0) {
860 * We have found the option so return with success.
862 return_val
= strdup(opt
);
863 if (return_val
== NULL
) {
875 opt_found
= strstr(opt_string
, opt
);
877 if (opt_found
== NULL
) {
880 size_t opt_string_len
;
884 opt_string_len
= strlen(opt_string
);
885 opt_len
= strlen(opt
);
887 value_len
= opt_string_len
- opt_len
;
889 value
= (char *)calloc((size_t)(value_len
+1),
890 (size_t)sizeof (char));
901 while (counter
<= (value_len
-1)) {
902 value
[counter
] = opt_string
[opt_len
+counter
];
903 counter
= counter
+ 1;
906 * Add the null terminating character.
908 value
[counter
] = '\0';
918 is_overlayed(fs_mntlist_t
*mnt_list
, char *mountp
) {
919 boolean_t ret_val
= B_FALSE
;
922 * The first entry in the complete_mnt_list is the same mounted
923 * file system as the one we are trying to determine whether it is
924 * overlayed or not. There is no need to compare these mounts.
926 mnt_list
= mnt_list
->next
;
928 while (mnt_list
!= NULL
&& ret_val
== B_FALSE
) {
929 if (!(strcmp(mnt_list
->fstype
, "autofs") == 0)) {
930 if (strcmp(mnt_list
->mountp
, mountp
) == 0) {
936 mnt_list
= mnt_list
->next
;