1 /* 2 * CDDL HEADER START 3 * 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. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or https://opensource.org/licenses/CDDL-1.0. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 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] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Copyright 2006 Ricardo Correia. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 /* Copyright (c) 1988 AT&T */ 29 /* All Rights Reserved */ 30 31 #include <stdio.h> 32 #include <string.h> 33 #include <mntent.h> 34 #include <sys/errno.h> 35 #include <sys/mnttab.h> 36 37 #include <sys/types.h> 38 #include <sys/sysmacros.h> 39 #include <sys/stat.h> 40 #include <unistd.h> 41 #include <libzutil.h> 42 43 #define BUFSIZE (MNT_LINE_MAX + 2) 44 45 static __thread char buf[BUFSIZE]; 46 47 #define DIFF(xx) ( \ 48 (mrefp->xx != NULL) && \ 49 (mgetp->xx == NULL || strcmp(mrefp->xx, mgetp->xx) != 0)) 50 51 int 52 getmntany(FILE *fp, struct mnttab *mgetp, struct mnttab *mrefp) 53 { 54 int ret; 55 56 while ( 57 ((ret = _sol_getmntent(fp, mgetp)) == 0) && ( 58 DIFF(mnt_special) || DIFF(mnt_mountp) || 59 DIFF(mnt_fstype) || DIFF(mnt_mntopts))) { } 60 61 return (ret); 62 } 63 64 int 65 _sol_getmntent(FILE *fp, struct mnttab *mgetp) 66 { 67 struct mntent mntbuf; 68 struct mntent *ret; 69 70 ret = getmntent_r(fp, &mntbuf, buf, BUFSIZE); 71 72 if (ret != NULL) { 73 mgetp->mnt_special = mntbuf.mnt_fsname; 74 mgetp->mnt_mountp = mntbuf.mnt_dir; 75 mgetp->mnt_fstype = mntbuf.mnt_type; 76 mgetp->mnt_mntopts = mntbuf.mnt_opts; 77 return (0); 78 } 79 80 if (feof(fp)) 81 return (-1); 82 83 return (MNT_TOOLONG); 84 } 85 86 static int 87 getextmntent_impl(FILE *fp, struct extmnttab *mp) 88 { 89 int ret; 90 struct stat64 st; 91 92 ret = _sol_getmntent(fp, (struct mnttab *)mp); 93 if (ret == 0) { 94 if (stat64(mp->mnt_mountp, &st) != 0) { 95 mp->mnt_major = 0; 96 mp->mnt_minor = 0; 97 return (ret); 98 } 99 mp->mnt_major = major(st.st_dev); 100 mp->mnt_minor = minor(st.st_dev); 101 } 102 103 return (ret); 104 } 105 106 int 107 getextmntent(const char *path, struct extmnttab *entry, struct stat64 *statbuf) 108 { 109 struct stat64 st; 110 FILE *fp; 111 int match; 112 113 if (strlen(path) >= MAXPATHLEN) { 114 (void) fprintf(stderr, "invalid object; pathname too long\n"); 115 return (-1); 116 } 117 118 /* 119 * Search for the path in /proc/self/mounts. Rather than looking for the 120 * specific path, which can be fooled by non-standard paths (i.e. ".." 121 * or "//"), we stat() the path and search for the corresponding 122 * (major,minor) device pair. 123 */ 124 if (stat64(path, statbuf) != 0) { 125 (void) fprintf(stderr, "cannot open '%s': %s\n", 126 path, zfs_strerror(errno)); 127 return (-1); 128 } 129 130 131 if ((fp = fopen(MNTTAB, "re")) == NULL) { 132 (void) fprintf(stderr, "cannot open %s\n", MNTTAB); 133 return (-1); 134 } 135 136 /* 137 * Search for the given (major,minor) pair in the mount table. 138 */ 139 140 match = 0; 141 while (getextmntent_impl(fp, entry) == 0) { 142 if (makedev(entry->mnt_major, entry->mnt_minor) == 143 statbuf->st_dev) { 144 match = 1; 145 break; 146 } 147 } 148 (void) fclose(fp); 149 150 if (!match) { 151 (void) fprintf(stderr, "cannot find mountpoint for '%s'\n", 152 path); 153 return (-1); 154 } 155 156 if (stat64(entry->mnt_mountp, &st) != 0) { 157 entry->mnt_major = 0; 158 entry->mnt_minor = 0; 159 return (-1); 160 } 161 162 return (0); 163 } 164