mount_lfs.c revision 1.13 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