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