1 /* $NetBSD: mount_lfs.c,v 1.13 2002/02/26 15:57:13 wiz Exp $ */ 2 3 /*- 4 * Copyright (c) 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 __COPYRIGHT("@(#) Copyright (c) 1993, 1994\n\ 39 The Regents of the University of California. All rights reserved.\n"); 40 #endif /* not lint */ 41 42 #ifndef lint 43 #if 0 44 static char sccsid[] = "@(#)mount_lfs.c 8.4 (Berkeley) 4/26/95"; 45 #else 46 __RCSID("$NetBSD: mount_lfs.c,v 1.13 2002/02/26 15:57:13 wiz Exp $"); 47 #endif 48 #endif /* not lint */ 49 50 #include <sys/param.h> 51 #include <sys/mount.h> 52 53 #include <ufs/ufs/ufsmount.h> 54 55 #include <err.h> 56 #include <errno.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <unistd.h> 61 #include <paths.h> 62 63 #include <signal.h> 64 65 #include "mntopts.h" 66 #include "pathnames.h" 67 68 static const struct mntopt mopts[] = { 69 MOPT_STDOPTS, 70 MOPT_UPDATE, 71 { NULL } 72 }; 73 74 int main __P((int, char *[])); 75 int mount_lfs __P((int, char *[])); 76 static void invoke_cleaner __P((char *)); 77 static void usage __P((void)); 78 static void kill_daemon __P((char *)); 79 static void kill_cleaner __P((char *)); 80 81 static int short_rds, cleaner_debug, cleaner_bytes; 82 static char *nsegs; 83 84 #ifndef MOUNT_NOMAIN 85 int 86 main(argc, argv) 87 int argc; 88 char **argv; 89 { 90 return mount_lfs(argc, argv); 91 } 92 #endif 93 94 int 95 mount_lfs(argc, argv) 96 int argc; 97 char *argv[]; 98 { 99 struct ufs_args args; 100 int ch, mntflags, noclean, mntsize, oldflags, i; 101 char *fs_name, *options; 102 103 const char *errcause; 104 struct statfs *mntbuf; 105 106 options = NULL; 107 nsegs = "4"; 108 mntflags = noclean = 0; 109 cleaner_bytes = 1; 110 while ((ch = getopt(argc, argv, "bdN:no:s")) != -1) 111 switch (ch) { 112 case 'b': 113 cleaner_bytes = !cleaner_bytes; 114 break; 115 case 'd': 116 cleaner_debug = 1; 117 break; 118 case 'n': 119 noclean = 1; 120 break; 121 case 'N': 122 nsegs = optarg; 123 break; 124 case 'o': 125 getmntopts(optarg, mopts, &mntflags, 0); 126 break; 127 case 's': 128 short_rds = 1; 129 break; 130 case '?': 131 default: 132 usage(); 133 } 134 argc -= optind; 135 argv += optind; 136 137 if (argc != 2) 138 usage(); 139 140 args.fspec = argv[0]; /* the name of the device file */ 141 fs_name = argv[1]; /* the mount point */ 142 143 #define DEFAULT_ROOTUID -2 144 args.export.ex_root = DEFAULT_ROOTUID; 145 if (mntflags & MNT_RDONLY) { 146 args.export.ex_flags = MNT_EXRDONLY; 147 noclean = 1; 148 } else 149 args.export.ex_flags = 0; 150 151 /* 152 * Record the previous status of this filesystem (if any) before 153 * performing the mount, so we can know whether to start or 154 * kill the cleaner process below. 155 */ 156 oldflags = MNT_RDONLY; /* If not mounted, pretend r/o */ 157 if (mntflags & MNT_UPDATE) { 158 if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) 159 err(1, "getmntinfo"); 160 for (i = 0; i < mntsize; i++) { 161 if (strcmp(mntbuf[i].f_mntfromname, args.fspec) == 0) { 162 oldflags = mntbuf[i].f_flags; 163 break; 164 } 165 } 166 } 167 168 if (mount(MOUNT_LFS, fs_name, mntflags, &args)) { 169 switch (errno) { 170 case EMFILE: 171 errcause = "mount table full"; 172 break; 173 case EINVAL: 174 if (mntflags & MNT_UPDATE) 175 errcause = 176 "specified device does not match mounted device"; 177 else 178 errcause = "incorrect super block"; 179 break; 180 default: 181 errcause = strerror(errno); 182 break; 183 } 184 errx(1, "%s on %s: %s", args.fspec, fs_name, errcause); 185 } 186 187 /* Not mounting fresh or upgrading to r/w; don't start the cleaner */ 188 if (!(oldflags & MNT_RDONLY) || (mntflags & MNT_RDONLY)) 189 noclean = 1; 190 if (!noclean) 191 invoke_cleaner(fs_name); 192 /* NOTREACHED */ 193 194 /* Downgrade to r/o; kill the cleaner */ 195 if ((mntflags & MNT_RDONLY) && !(oldflags & MNT_RDONLY)) 196 kill_cleaner(fs_name); 197 198 exit(0); 199 } 200 201 static void 202 kill_daemon(pidname) 203 char *pidname; 204 { 205 FILE *fp; 206 char s[80]; 207 pid_t pid; 208 209 fp = fopen(pidname, "r"); 210 if (fp) { 211 fgets(s, 80, fp); 212 pid = atoi(s); 213 if (pid) 214 kill(pid, SIGINT); 215 fclose(fp); 216 } 217 } 218 219 static void 220 kill_cleaner(name) 221 char *name; 222 { 223 char *pidname; 224 char *cp; 225 int off; 226 227 /* Parent first */ 228 pidname = malloc(strlen(name) + 20 + strlen(_PATH_VARRUN)); 229 sprintf(pidname, "%slfs_cleanerd:m:%s.pid", _PATH_VARRUN, name); 230 off = strlen(_PATH_VARRUN); 231 while((cp = strchr(pidname + off, '/')) != NULL) 232 *cp = '|'; 233 kill_daemon(pidname); 234 235 /* Then child */ 236 sprintf(pidname, "%slfs_cleanerd:s:%s.pid", _PATH_VARRUN, name); 237 off = strlen(_PATH_VARRUN); 238 while((cp = strchr(pidname + off, '/')) != NULL) 239 *cp = '|'; 240 kill_daemon(pidname); 241 } 242 243 static void 244 invoke_cleaner(name) 245 char *name; 246 { 247 char *args[6], **ap = args; 248 249 /* Build the argument list. */ 250 *ap++ = _PATH_LFS_CLEANERD; 251 if (cleaner_bytes) 252 *ap++ = "-b"; 253 if (nsegs) { 254 *ap++ = "-n"; 255 *ap++ = nsegs; 256 } 257 if (short_rds) 258 *ap++ = "-s"; 259 if (cleaner_debug) 260 *ap++ = "-d"; 261 *ap++ = name; 262 *ap = NULL; 263 264 execv(args[0], args); 265 err(1, "exec %s", _PATH_LFS_CLEANERD); 266 } 267 268 static void 269 usage() 270 { 271 (void)fprintf(stderr, 272 "usage: mount_lfs [-dns] [-o options] special node\n"); 273 exit(1); 274 } 275