Home | History | Annotate | Line # | Download | only in mount_lfs
      1 /*	$NetBSD: mount_lfs.c,v 1.44 2026/09/09 22:22:41 perseant 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.44 2026/09/09 22:22:41 perseant Exp $");
     43 #endif
     44 #endif /* not lint */
     45 
     46 #include <sys/param.h>
     47 #include <sys/fcntl.h>
     48 #include <sys/mount.h>
     49 
     50 #include <ufs/lfs/lfs.h>
     51 
     52 #include <err.h>
     53 #include <errno.h>
     54 #include <stddef.h>
     55 #include <stdio.h>
     56 #include <stdlib.h>
     57 #include <string.h>
     58 #include <unistd.h>
     59 #include <paths.h>
     60 
     61 #include <signal.h>
     62 
     63 #include <mntopts.h>
     64 #include "pathnames.h"
     65 #include "mountprog.h"
     66 #include "mount_lfs.h"
     67 
     68 static const struct mntopt mopts[] = {
     69 	MOPT_STDOPTS,
     70 	MOPT_UPDATE,
     71 	MOPT_GETARGS,
     72 	MOPT_NOATIME,
     73 	MOPT_RELATIME,
     74 	MOPT_LOG,
     75 	MOPT_NULL,
     76 };
     77 
     78 __dead static void	usage(void);
     79 
     80 #ifdef WANT_CLEANER
     81 __dead static void	invoke_cleaner(char *);
     82 static void	kill_daemon(char *);
     83 static void	kill_cleaner(char *);
     84 #endif /* WANT_CLEANER */
     85 
     86 #define HOWCLEAN_NONE   0
     87 #define HOWCLEAN_USER   1
     88 #define HOWCLEAN_KERNEL 2
     89 
     90 static int short_rds, cleaner_debug, cleaner_bytes, fs_idle, howclean;
     91 static const char *nsegs;
     92 
     93 #ifndef MOUNT_NOMAIN
     94 int
     95 main(int argc, char **argv)
     96 {
     97 
     98 	setprogname(argv[0]);
     99 	return mount_lfs(argc, argv);
    100 }
    101 #endif
    102 
    103 void
    104 mount_lfs_parseargs(int argc, char *argv[],
    105 	struct ulfs_args *args, int *mntflags,
    106 	char *canon_dev, char *canon_dir)
    107 {
    108 	int ch;
    109 	mntoptparse_t mp;
    110 
    111 	memset(args, 0, sizeof(*args));
    112 	nsegs = "4";
    113 	*mntflags = MNT_LOG;
    114 	howclean = HOWCLEAN_KERNEL;
    115 	cleaner_bytes = 1;
    116 	while ((ch = getopt(argc, argv, "bdikN:no:su")) != -1)
    117 		switch (ch) {
    118 		case 'b':
    119 			cleaner_bytes = !cleaner_bytes;
    120 			break;
    121 		case 'd':
    122 			cleaner_debug = 1;
    123 			break;
    124 		case 'i':
    125 			fs_idle = 1;
    126 			break;
    127 		case 'k':
    128 			howclean = HOWCLEAN_KERNEL;
    129 			break;
    130 		case 'n':
    131 			howclean = HOWCLEAN_NONE;
    132 			break;
    133 		case 'N':
    134 			nsegs = optarg;
    135 			break;
    136 		case 'o':
    137 			mp = getmntopts(optarg, mopts, mntflags, 0);
    138 			if (mp == NULL)
    139 				err(EXIT_FAILURE, "getmntopts");
    140 			freemntopts(mp);
    141 			break;
    142 		case 's':
    143 			short_rds = 1;
    144 			break;
    145 		case 'u':
    146 			howclean = HOWCLEAN_USER;
    147 			break;
    148 		case '?':
    149 		default:
    150 			usage();
    151 		}
    152 	argc -= optind;
    153 	argv += optind;
    154 
    155 	if (argc != 2)
    156 		usage();
    157 
    158 	pathadj(argv[0], canon_dev);
    159 	args->fspec = canon_dev;
    160 
    161 	pathadj(argv[1], canon_dir);
    162 }
    163 
    164 int
    165 mount_lfs(int argc, char *argv[])
    166 {
    167 	struct ulfs_args args;
    168 	int mntflags;
    169 	int mntsize, oldflags, i;
    170 	char fs_name[MAXPATHLEN], canon_dev[MAXPATHLEN];
    171 	struct statvfs *mntbuf;
    172 	const char *errcause;
    173 
    174 	mount_lfs_parseargs(argc, argv, &args, &mntflags, canon_dev, fs_name);
    175 
    176 	/*
    177 	 * Record the previous status of this filesystem (if any) before
    178 	 * performing the mount, so we can know whether to start or
    179 	 * kill the cleaner process below.
    180 	 */
    181 	oldflags = MNT_RDONLY; /* If not mounted, pretend r/o */
    182 	if (mntflags & MNT_UPDATE) {
    183 		if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
    184 			err(EXIT_FAILURE, "getmntinfo");
    185 		for (i = 0; i < mntsize; i++) {
    186 			if (strcmp(mntbuf[i].f_mntfromname, args.fspec) == 0) {
    187 				oldflags = mntbuf[i].f_flag;
    188 				break;
    189 			}
    190 		}
    191 	}
    192 
    193 	if (mount(MOUNT_LFS, fs_name, mntflags, &args, sizeof args) == -1) {
    194 		switch (errno) {
    195 		case EMFILE:
    196 			errcause = "mount table full";
    197 			break;
    198 		case EINVAL:
    199 			if (mntflags & MNT_UPDATE)
    200 				errcause =
    201 			    "specified device does not match mounted device";
    202 			else
    203 				errcause = "incorrect super block";
    204 			break;
    205 		default:
    206 			errcause = strerror(errno);
    207 			break;
    208 		}
    209 		errx(EXIT_FAILURE, "%s on %s: %s", args.fspec, fs_name, errcause);
    210 	}
    211 
    212 #ifdef WANT_CLEANER
    213 	/* Not mounting fresh or upgrading to r/w; don't start the cleaner */
    214 	if (!(oldflags & MNT_RDONLY) || (mntflags & MNT_RDONLY)
    215 	    || (mntflags & MNT_GETARGS))
    216 		howclean = HOWCLEAN_NONE;
    217 	if (howclean != HOWCLEAN_NONE)
    218 		invoke_cleaner(fs_name);
    219 		/* NOTREACHED */
    220 
    221 	/* Downgrade to r/o; kill the cleaner */
    222 	if ((mntflags & MNT_RDONLY) && !(oldflags & MNT_RDONLY))
    223 		kill_cleaner(fs_name);
    224 #else
    225 	__USE(oldflags);
    226 #endif /* WANT_CLEANER */
    227 
    228 	return EXIT_SUCCESS;
    229 }
    230 
    231 #ifdef WANT_CLEANER
    232 static void
    233 kill_daemon(char *pidname)
    234 {
    235 	FILE *fp;
    236 	char s[80];
    237 	pid_t pid;
    238 
    239 	fp = fopen(pidname, "r");
    240 	if (fp) {
    241 		fgets(s, sizeof(s), fp);
    242 		pid = atoi(s);
    243 		if (pid)
    244 			kill(pid, SIGINT);
    245 		fclose(fp);
    246 	}
    247 }
    248 
    249 static void
    250 kill_cleaner(char *name)
    251 {
    252 	char *pidname;
    253 	char *cp;
    254 	int off;
    255 
    256 	/* Parent first */
    257 	asprintf(&pidname, "%slfs_cleanerd:m:%s.pid", _PATH_VARRUN, name);
    258 	if (!pidname)
    259 		err(EXIT_FAILURE, "malloc");
    260 	off = strlen(_PATH_VARRUN);
    261 	while((cp = strchr(pidname + off, '/')) != NULL)
    262 		*cp = '|';
    263 	kill_daemon(pidname);
    264 	free(pidname);
    265 
    266 	/* Then child */
    267 	asprintf(&pidname, "%slfs_cleanerd:s:%s.pid", _PATH_VARRUN, name);
    268 	if (!pidname)
    269 		err(EXIT_FAILURE, "malloc");
    270 	off = strlen(_PATH_VARRUN);
    271 	while((cp = strchr(pidname + off, '/')) != NULL)
    272 		*cp = '|';
    273 	kill_daemon(pidname);
    274 	free(pidname);
    275 }
    276 
    277 static void
    278 invoke_cleaner(char *name)
    279 {
    280 	const char *args[7], **ap = args;
    281 	int fd;
    282 	struct lfs_autoclean_params autoclean;
    283 
    284 	if (howclean == HOWCLEAN_KERNEL) {
    285 		fd = open(name, O_RDONLY);
    286 		if (fd < 0)
    287 			err(EXIT_FAILURE, "opening mounted root");
    288 
    289 		autoclean.size = sizeof(autoclean);
    290 		autoclean.mode = LFS_CLEANMODE_GREEDY;
    291 		autoclean.thresh = -1;
    292 		autoclean.target = -1;
    293 		if (fcntl(fd, LFCNAUTOCLEAN, &autoclean) < 0)
    294 			err(EXIT_FAILURE, "LFCNAUTOCLEAN failed");
    295 
    296 		close(fd);
    297 		exit(0);
    298 	}
    299 
    300 	if (howclean == HOWCLEAN_USER) {
    301 		/* Build the argument list. */
    302 		*ap++ = _PATH_LFS_CLEANERD;
    303 		if (cleaner_bytes)
    304 			*ap++ = "-b";
    305 		if (nsegs) {
    306 			*ap++ = "-n";
    307 			*ap++ = nsegs;
    308 		}
    309 		if (short_rds)
    310 			*ap++ = "-s";
    311 		if (cleaner_debug)
    312 			*ap++ = "-d";
    313 		if (fs_idle)
    314 			*ap++ = "-f";
    315 		*ap++ = name;
    316 		*ap = NULL;
    317 
    318 		execv(args[0], __UNCONST(args));
    319 		err(EXIT_FAILURE, "exec %s", _PATH_LFS_CLEANERD);
    320 	}
    321 
    322 	__unreachable();
    323 }
    324 #endif /* WANT_CLEANER */
    325 
    326 static void
    327 usage(void)
    328 {
    329 	(void)fprintf(stderr,
    330 		"usage: %s [-bdins] [-N nsegs] [-o options] special node\n",
    331 		getprogname());
    332 	exit(EXIT_FAILURE);
    333 }
    334