1 /* $NetBSD: mtab_svr4.c,v 1.1.1.3 2015/01/17 16:34:16 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1997-2014 Erez Zadok 5 * Copyright (c) 1990 Jan-Simon Pendry 6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 7 * Copyright (c) 1990 The Regents of the University of California. 8 * All rights reserved. 9 * 10 * This code is derived from software contributed to Berkeley by 11 * Jan-Simon Pendry at Imperial College, London. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * 38 * File: am-utils/conf/mtab/mtab_svr4.c 39 * 40 * How to manage the mount table file. Based on other SVR3 ports. 41 * -Erez Zadok <ezk@cs.columbia.edu> 42 */ 43 44 #ifdef HAVE_CONFIG_H 45 # include <config.h> 46 #endif /* HAVE_CONFIG_H */ 47 #include <am_defs.h> 48 #include <amu.h> 49 50 /* 51 * file descriptor for lock file 52 * values: -1 no file-descriptor was set yet (or mnttab unlocked, or error 53 * in locking). 54 * >=0 legal file-descriptor value (file lock succeeded) 55 */ 56 static int mntent_lock_fd = -1; 57 58 59 #ifdef MOUNT_TABLE_ON_FILE 60 static char mtlckname[] = "/etc/.mnttab.lock"; 61 #endif /* MOUNT_TABLE_ON_FILE */ 62 63 64 /****************************************************************************/ 65 /*** Private functions */ 66 /****************************************************************************/ 67 68 static void 69 unlockmnttab(void) 70 { 71 #ifdef MOUNT_TABLE_ON_FILE 72 if (mntent_lock_fd >= 0) { 73 close(mntent_lock_fd); 74 mntent_lock_fd = -1; 75 } 76 #endif /* MOUNT_TABLE_ON_FILE */ 77 } 78 79 80 #ifdef MOUNT_TABLE_ON_FILE 81 static int 82 lockfile(int fd, int type) 83 { 84 struct flock lk; 85 int ret; 86 87 lk.l_type = type; 88 lk.l_whence = 0; 89 lk.l_start = 0; 90 lk.l_len = 0; 91 92 /* 93 * F_SETLKW means to block until the read or write block is free to be 94 * locked. 95 */ 96 ret = fcntl(fd, F_SETLKW, &lk); 97 return ret; 98 } 99 #endif /* MOUNT_TABLE_ON_FILE */ 100 101 102 /* return 0 if locking succeeded, -1 if failed */ 103 static int 104 lockmnttab(void) 105 { 106 #ifdef MOUNT_TABLE_ON_FILE 107 /* if mnttab file is locked, all is well */ 108 if (mntent_lock_fd >= 0) 109 return 0; 110 111 /* need to lock mnttab file. first, open the file */ 112 mntent_lock_fd = open(mtlckname, O_RDWR | O_CREAT, 0600); 113 if (mntent_lock_fd < 0) { 114 plog(XLOG_ERROR, "Unable to open/creat %s: %m", mtlckname); 115 return -1; 116 } 117 118 /* if succeeded in opening the file, try to lock it */ 119 if (lockfile(mntent_lock_fd, F_WRLCK) < 0) { 120 close(mntent_lock_fd); 121 mntent_lock_fd = -1; 122 #ifdef DEBUG 123 dlog("lock %s failed: %m", mtlckname); 124 #endif /* DEBUG */ 125 return -1; 126 } 127 #else /* not MOUNT_TABLE_ON_FILE */ 128 /* fake lock for in-kernel mount table */ 129 #endif /* not MOUNT_TABLE_ON_FILE */ 130 131 /* finally, succeeded in also locking the file */ 132 return 0; 133 } 134 135 136 /* 137 * Convert from solaris mnttab to Amd mntent. Since am-utils uses 138 * native "struct mnttab" if available, this really copies fields of 139 * the same structure. 140 */ 141 static mntent_t * 142 mnt_dup(const mntent_t *mtp) 143 { 144 mntent_t *mep = ALLOC(mntent_t); 145 146 mep->mnt_fsname = xstrdup(mtp->mnt_fsname); 147 mep->mnt_dir = xstrdup(mtp->mnt_dir); 148 mep->mnt_type = xstrdup(mtp->mnt_type); 149 mep->mnt_opts = xstrdup(mtp->mnt_opts); 150 mep->mnt_time = xstrdup(mtp->mnt_time); 151 152 return mep; 153 } 154 155 156 /* 157 * Adjust arguments in mntent_t. 158 */ 159 #ifdef MOUNT_TABLE_ON_FILE 160 static mntent_t * 161 update_mnttab_fields(const mntent_t *mnt) 162 { 163 static mntent_t mt; 164 static char timestr[16]; 165 struct timeval tv; 166 167 /* most fields don't change, only update mnt_time below */ 168 mt.mnt_fsname = mnt->mnt_fsname; 169 mt.mnt_dir = mnt->mnt_dir; 170 mt.mnt_type = mnt->mnt_type; 171 mt.mnt_opts = mnt->mnt_opts; 172 173 /* 174 * Solaris 2.5 and newer take a second argument to gettimeofday(). If you 175 * find a useful svr4-like OS that uses the old style, and this code here 176 * fails, then create a new autoconf test that will determine the number 177 * of arguments gettimeofday() takes. -Erez. 178 */ 179 if (gettimeofday(&tv, NULL) < 0) 180 timestr[0] = '\0'; 181 else 182 xsnprintf(timestr, sizeof(timestr), "%ld", tv.tv_sec); 183 184 mt.mnt_time = timestr; 185 186 return &mt; 187 } 188 #endif /* MOUNT_TABLE_ON_FILE */ 189 190 191 static void 192 write_mntent_to_mtab(FILE *fp, const mntent_t *mnt) 193 { 194 #ifdef MOUNT_TABLE_ON_FILE 195 putmntent(fp, update_mnttab_fields(mnt)); 196 #endif /* MOUNT_TABLE_ON_FILE */ 197 } 198 199 200 /****************************************************************************/ 201 /*** Public functions */ 202 /****************************************************************************/ 203 204 205 void 206 unlock_mntlist(void) 207 { 208 unlockmnttab(); 209 } 210 211 212 /* 213 * Read a mount table into memory 214 */ 215 mntlist * 216 read_mtab(char *fs, const char *mnttabname) 217 { 218 mntlist **mpp, *mhp; 219 FILE *fp; 220 mntent_t mountbuf; 221 int ret; 222 223 if (lockmnttab() < 0) /* failed locking */ 224 return NULL; 225 226 fp = fopen(mnttabname, "r"); 227 if (fp == NULL) { 228 plog(XLOG_ERROR, "Can't open %s: %m", mnttabname); 229 return NULL; 230 } 231 mpp = &mhp; 232 233 while ((ret = getmntent(fp, &mountbuf)) == 0) { 234 /* 235 * Allocate a new slot 236 */ 237 *mpp = ALLOC(struct mntlist); 238 239 /* 240 * Copy the data returned by getmntent 241 */ 242 (*mpp)->mnt = mnt_dup(&mountbuf); 243 244 /* 245 * Move to next pointer 246 */ 247 mpp = &(*mpp)->mnext; 248 } 249 250 if (ret > 0) { 251 plog(XLOG_ERROR, "read error on %s: %m", mnttabname); 252 unlockmnttab(); 253 mhp = NULL; 254 } 255 *mpp = NULL; 256 257 fclose(fp); 258 return mhp; 259 } 260 261 262 void 263 rewrite_mtab(mntlist *mp, const char *mnttabname) 264 { 265 FILE *fp; 266 267 assert(mntent_lock_fd >= 0); /* ensure lock fd is valid */ 268 269 fp = fopen(mnttabname, "r+"); 270 if (fp == NULL) { 271 plog(XLOG_ERROR, "Can't open %s: %m", mnttabname); 272 unlockmnttab(); 273 return; 274 } 275 while (mp) { 276 if (mp->mnt) 277 write_mntent_to_mtab(fp, mp->mnt); 278 mp = mp->mnext; 279 } 280 281 ftruncate(fileno(fp), ftell(fp)); 282 fclose(fp); 283 unlockmnttab(); 284 } 285 286 287 void 288 write_mntent(mntent_t *mtp, const char *mnttabname) 289 { 290 FILE *fp; 291 292 if (lockmnttab() < 0) 293 return; 294 295 fp = fopen(mnttabname, "a"); 296 if (fp == NULL) { 297 plog(XLOG_ERROR, "Unable to append %s: %m", mnttabname); 298 return; 299 } 300 write_mntent_to_mtab(fp, mtp); 301 302 fclose(fp); 303 unlockmnttab(); 304 } 305