1 1.108 kre /* $NetBSD: mount.c,v 1.108 2025/07/01 17:55:05 kre Exp $ */ 2 1.16 cgd 3 1.1 cgd /* 4 1.12 mycroft * Copyright (c) 1980, 1989, 1993, 1994 5 1.12 mycroft * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.66 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.29 christos #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.85 lukem __COPYRIGHT("@(#) Copyright (c) 1980, 1989, 1993, 1994\ 35 1.85 lukem The Regents of the University of California. All rights reserved."); 36 1.1 cgd #endif /* not lint */ 37 1.1 cgd 38 1.1 cgd #ifndef lint 39 1.16 cgd #if 0 40 1.32 lukem static char sccsid[] = "@(#)mount.c 8.25 (Berkeley) 5/8/95"; 41 1.16 cgd #else 42 1.108 kre __RCSID("$NetBSD: mount.c,v 1.108 2025/07/01 17:55:05 kre Exp $"); 43 1.16 cgd #endif 44 1.1 cgd #endif /* not lint */ 45 1.1 cgd 46 1.1 cgd #include <sys/param.h> 47 1.12 mycroft #include <sys/mount.h> 48 1.1 cgd #include <sys/wait.h> 49 1.12 mycroft 50 1.90 pooka #include <fs/puffs/puffs_msgif.h> 51 1.90 pooka 52 1.12 mycroft #include <err.h> 53 1.12 mycroft #include <errno.h> 54 1.1 cgd #include <fstab.h> 55 1.32 lukem #include <pwd.h> 56 1.12 mycroft #include <signal.h> 57 1.1 cgd #include <stdio.h> 58 1.1 cgd #include <stdlib.h> 59 1.12 mycroft #include <string.h> 60 1.12 mycroft #include <unistd.h> 61 1.94 christos #include <util.h> 62 1.12 mycroft 63 1.48 abs #define MOUNTNAMES 64 1.48 abs #include <fcntl.h> 65 1.73 thorpej #include <sys/disk.h> 66 1.48 abs #include <sys/disklabel.h> 67 1.48 abs #include <sys/ioctl.h> 68 1.48 abs 69 1.1 cgd #include "pathnames.h" 70 1.86 pooka #include "mountprog.h" 71 1.1 cgd 72 1.108 kre static int debug, verbose, noise; 73 1.1 cgd 74 1.76 xtraeme static void catopt(char **, const char *); 75 1.53 enami static const char * 76 1.76 xtraeme getfslab(const char *str); 77 1.69 christos static struct statvfs * 78 1.76 xtraeme getmntpt(const char *); 79 1.76 xtraeme static int getmntargs(struct statvfs *, char *, size_t); 80 1.76 xtraeme static int hasopt(const char *, const char *); 81 1.82 christos static void mangle(char *, int *, const char ** volatile *, int *); 82 1.76 xtraeme static int mountfs(const char *, const char *, const char *, 83 1.76 xtraeme int, const char *, const char *, int, char *, size_t); 84 1.76 xtraeme static void prmount(struct statvfs *); 85 1.93 joerg __dead static void usage(void); 86 1.53 enami 87 1.12 mycroft 88 1.99 ast /* Map from mount options to printable formats. */ 89 1.52 jdolecek static const struct opt { 90 1.12 mycroft int o_opt; 91 1.24 cgd int o_silent; 92 1.12 mycroft const char *o_name; 93 1.12 mycroft } optnames[] = { 94 1.58 christos __MNT_FLAGS 95 1.1 cgd }; 96 1.1 cgd 97 1.103 mlelstv #define FLG_UPDATE 1 98 1.103 mlelstv #define FLG_RDONLY 2 99 1.103 mlelstv #define FLG_RDWRITE 4 100 1.103 mlelstv #define FLG_FORCE 8 101 1.103 mlelstv 102 1.94 christos static const char ffs_fstype[] = "ffs"; 103 1.30 christos 104 1.12 mycroft int 105 1.76 xtraeme main(int argc, char *argv[]) 106 1.1 cgd { 107 1.32 lukem const char *mntfromname, *mntonname, **vfslist, *vfstype; 108 1.12 mycroft struct fstab *fs; 109 1.69 christos struct statvfs *mntbuf; 110 1.89 yamt #if 0 111 1.12 mycroft FILE *mountdfp; 112 1.89 yamt #endif 113 1.22 cgd int all, ch, forceall, i, init_flags, mntsize, rval; 114 1.12 mycroft char *options; 115 1.43 mycroft const char *mountopts, *fstypename; 116 1.94 christos char canonical_path_buf[MAXPATHLEN], buf[MAXPATHLEN]; 117 1.75 he char *canonical_path; 118 1.52 jdolecek 119 1.52 jdolecek /* started as "mount" */ 120 1.22 cgd all = forceall = init_flags = 0; 121 1.12 mycroft options = NULL; 122 1.32 lukem vfslist = NULL; 123 1.40 cgd vfstype = ffs_fstype; 124 1.31 lukem while ((ch = getopt(argc, argv, "Aadfo:rwt:uv")) != -1) 125 1.12 mycroft switch (ch) { 126 1.22 cgd case 'A': 127 1.22 cgd all = forceall = 1; 128 1.22 cgd break; 129 1.1 cgd case 'a': 130 1.1 cgd all = 1; 131 1.1 cgd break; 132 1.12 mycroft case 'd': 133 1.12 mycroft debug = 1; 134 1.12 mycroft break; 135 1.1 cgd case 'f': 136 1.103 mlelstv init_flags |= FLG_FORCE; 137 1.12 mycroft break; 138 1.12 mycroft case 'o': 139 1.12 mycroft if (*optarg) 140 1.35 mycroft catopt(&options, optarg); 141 1.1 cgd break; 142 1.1 cgd case 'r': 143 1.103 mlelstv init_flags |= FLG_RDONLY; 144 1.12 mycroft break; 145 1.12 mycroft case 't': 146 1.32 lukem if (vfslist != NULL) 147 1.94 christos errx(EXIT_FAILURE, 148 1.94 christos "Only one -t option may be specified."); 149 1.32 lukem vfslist = makevfslist(optarg); 150 1.12 mycroft vfstype = optarg; 151 1.1 cgd break; 152 1.1 cgd case 'u': 153 1.103 mlelstv init_flags |= FLG_UPDATE; 154 1.1 cgd break; 155 1.1 cgd case 'v': 156 1.61 christos verbose++; 157 1.1 cgd break; 158 1.1 cgd case 'w': 159 1.103 mlelstv init_flags |= FLG_RDWRITE; 160 1.1 cgd break; 161 1.1 cgd case '?': 162 1.1 cgd default: 163 1.1 cgd usage(); 164 1.1 cgd /* NOTREACHED */ 165 1.1 cgd } 166 1.1 cgd argc -= optind; 167 1.1 cgd argv += optind; 168 1.1 cgd 169 1.12 mycroft #define BADTYPE(type) \ 170 1.12 mycroft (strcmp(type, FSTAB_RO) && \ 171 1.12 mycroft strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ)) 172 1.12 mycroft 173 1.108 kre noise = 0; 174 1.108 kre if (argc > 0 && verbose) { 175 1.108 kre noise = 1; 176 1.108 kre verbose--; 177 1.108 kre } 178 1.108 kre 179 1.12 mycroft rval = 0; 180 1.12 mycroft switch (argc) { 181 1.12 mycroft case 0: 182 1.105 simonb if (all) { 183 1.12 mycroft while ((fs = getfsent()) != NULL) { 184 1.12 mycroft if (BADTYPE(fs->fs_type)) 185 1.12 mycroft continue; 186 1.32 lukem if (checkvfsname(fs->fs_vfstype, vfslist)) 187 1.12 mycroft continue; 188 1.12 mycroft if (hasopt(fs->fs_mntops, "noauto")) 189 1.12 mycroft continue; 190 1.68 cgd if (strcmp(fs->fs_spec, "from_mount") == 0) { 191 1.94 christos if ((mntbuf = getmntpt(fs->fs_file)) 192 1.94 christos == NULL) 193 1.94 christos errx(EXIT_FAILURE, 194 1.94 christos "Unknown file system %s", 195 1.68 cgd fs->fs_file); 196 1.68 cgd mntfromname = mntbuf->f_mntfromname; 197 1.68 cgd } else 198 1.68 cgd mntfromname = fs->fs_spec; 199 1.95 christos mntfromname = getfsspecname(buf, sizeof(buf), 200 1.95 christos mntfromname); 201 1.95 christos if (mntfromname == NULL) 202 1.97 christos err(EXIT_FAILURE, "%s", buf); 203 1.68 cgd if (mountfs(fs->fs_vfstype, mntfromname, 204 1.12 mycroft fs->fs_file, init_flags, options, 205 1.61 christos fs->fs_mntops, !forceall, NULL, 0)) 206 1.12 mycroft rval = 1; 207 1.12 mycroft } 208 1.105 simonb } else { 209 1.12 mycroft if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) 210 1.94 christos err(EXIT_FAILURE, "getmntinfo"); 211 1.12 mycroft for (i = 0; i < mntsize; i++) { 212 1.32 lukem if (checkvfsname(mntbuf[i].f_fstypename, 213 1.32 lukem vfslist)) 214 1.12 mycroft continue; 215 1.13 mycroft prmount(&mntbuf[i]); 216 1.12 mycroft } 217 1.1 cgd } 218 1.98 christos return rval; 219 1.12 mycroft case 1: 220 1.40 cgd if (vfslist != NULL) { 221 1.1 cgd usage(); 222 1.40 cgd /* NOTREACHED */ 223 1.40 cgd } 224 1.1 cgd 225 1.74 erh /* 226 1.74 erh * Create a canonical version of the device or mount path 227 1.74 erh * passed to us. It's ok for this to fail. It's also ok 228 1.74 erh * for the result to be exactly the same as the original. 229 1.74 erh */ 230 1.74 erh canonical_path = realpath(*argv, canonical_path_buf); 231 1.74 erh 232 1.103 mlelstv if (init_flags & FLG_UPDATE) { 233 1.74 erh /* 234 1.77 lukem * Try looking up the canonical path first, 235 1.74 erh * then try exactly what the user entered. 236 1.74 erh */ 237 1.74 erh if ((canonical_path == NULL || 238 1.94 christos (mntbuf = getmntpt(canonical_path)) == NULL) && 239 1.94 christos (mntbuf = getmntpt(*argv)) == NULL) { 240 1.94 christos out: 241 1.94 christos errx(EXIT_FAILURE, 242 1.94 christos "Unknown special file or file system `%s'", 243 1.12 mycroft *argv); 244 1.74 erh } 245 1.68 cgd mntfromname = mntbuf->f_mntfromname; 246 1.42 ross if ((fs = getfsfile(mntbuf->f_mntonname)) != NULL) { 247 1.68 cgd if (strcmp(fs->fs_spec, "from_mount") != 0) 248 1.68 cgd mntfromname = fs->fs_spec; 249 1.42 ross /* ignore the fstab file options. */ 250 1.42 ross fs->fs_mntops = NULL; 251 1.68 cgd } 252 1.42 ross mntonname = mntbuf->f_mntonname; 253 1.42 ross fstypename = mntbuf->f_fstypename; 254 1.42 ross mountopts = NULL; 255 1.12 mycroft } else { 256 1.74 erh /* 257 1.77 lukem * Try looking up the canonical path first, 258 1.74 erh * then try exactly what the user entered. 259 1.74 erh */ 260 1.77 lukem if (canonical_path == NULL || 261 1.77 lukem ((fs = getfsfile(canonical_path)) == NULL && 262 1.77 lukem (fs = getfsspec(canonical_path)) == NULL)) 263 1.74 erh { 264 1.74 erh if ((fs = getfsfile(*argv)) == NULL && 265 1.94 christos (fs = getfsspec(*argv)) == NULL) { 266 1.94 christos goto out; 267 1.74 erh } 268 1.74 erh } 269 1.12 mycroft if (BADTYPE(fs->fs_type)) 270 1.94 christos errx(EXIT_FAILURE, 271 1.94 christos "Unknown file system type for `%s'", 272 1.12 mycroft *argv); 273 1.68 cgd if (strcmp(fs->fs_spec, "from_mount") == 0) { 274 1.74 erh if ((canonical_path == NULL || 275 1.94 christos (mntbuf = getmntpt(canonical_path)) 276 1.94 christos == NULL) && 277 1.94 christos (mntbuf = getmntpt(*argv)) == NULL) 278 1.94 christos goto out; 279 1.68 cgd mntfromname = mntbuf->f_mntfromname; 280 1.68 cgd } else 281 1.68 cgd mntfromname = fs->fs_spec; 282 1.42 ross mntonname = fs->fs_file; 283 1.42 ross fstypename = fs->fs_vfstype; 284 1.42 ross mountopts = fs->fs_mntops; 285 1.12 mycroft } 286 1.95 christos mntfromname = getfsspecname(buf, sizeof(buf), mntfromname); 287 1.95 christos if (mntfromname == NULL) 288 1.95 christos err(EXIT_FAILURE, "%s", buf); 289 1.42 ross rval = mountfs(fstypename, mntfromname, 290 1.61 christos mntonname, init_flags, options, mountopts, 0, NULL, 0); 291 1.12 mycroft break; 292 1.12 mycroft case 2: 293 1.1 cgd /* 294 1.12 mycroft * If -t flag has not been specified, and spec contains either 295 1.12 mycroft * a ':' or a '@' then assume that an NFS filesystem is being 296 1.12 mycroft * specified ala Sun. 297 1.1 cgd */ 298 1.95 christos mntfromname = getfsspecname(buf, sizeof(buf), argv[0]); 299 1.95 christos if (mntfromname == NULL) 300 1.95 christos err(EXIT_FAILURE, "%s", buf); 301 1.48 abs if (vfslist == NULL) { 302 1.87 pooka if (strpbrk(argv[0], ":@") != NULL) { 303 1.48 abs vfstype = "nfs"; 304 1.87 pooka } else { 305 1.94 christos vfstype = getfslab(mntfromname); 306 1.48 abs if (vfstype == NULL) 307 1.48 abs vfstype = ffs_fstype; 308 1.48 abs } 309 1.48 abs } 310 1.94 christos rval = mountfs(vfstype, mntfromname, argv[1], init_flags, 311 1.94 christos options, NULL, 0, NULL, 0); 312 1.12 mycroft break; 313 1.12 mycroft default: 314 1.12 mycroft usage(); 315 1.1 cgd } 316 1.1 cgd 317 1.89 yamt #if 0 /* disabled because it interferes the service. */ 318 1.12 mycroft /* 319 1.12 mycroft * If the mount was successfully, and done by root, tell mountd the 320 1.12 mycroft * good news. Pid checks are probably unnecessary, but don't hurt. 321 1.12 mycroft */ 322 1.12 mycroft if (rval == 0 && getuid() == 0 && 323 1.12 mycroft (mountdfp = fopen(_PATH_MOUNTDPID, "r")) != NULL) { 324 1.29 christos int pid; 325 1.29 christos 326 1.29 christos if (fscanf(mountdfp, "%d", &pid) == 1 && 327 1.53 enami pid > 0 && kill(pid, SIGHUP) == -1 && errno != ESRCH) 328 1.94 christos err(EXIT_FAILURE, "signal mountd"); 329 1.12 mycroft (void)fclose(mountdfp); 330 1.1 cgd } 331 1.89 yamt #endif 332 1.1 cgd 333 1.98 christos return rval; 334 1.1 cgd } 335 1.1 cgd 336 1.12 mycroft int 337 1.76 xtraeme hasopt(const char *mntopts, const char *option) 338 1.1 cgd { 339 1.12 mycroft int negative, found; 340 1.12 mycroft char *opt, *optbuf; 341 1.1 cgd 342 1.12 mycroft if (option[0] == 'n' && option[1] == 'o') { 343 1.12 mycroft negative = 1; 344 1.12 mycroft option += 2; 345 1.12 mycroft } else 346 1.12 mycroft negative = 0; 347 1.94 christos optbuf = estrdup(mntopts); 348 1.12 mycroft found = 0; 349 1.12 mycroft for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) { 350 1.12 mycroft if (opt[0] == 'n' && opt[1] == 'o') { 351 1.12 mycroft if (!strcasecmp(opt + 2, option)) 352 1.12 mycroft found = negative; 353 1.12 mycroft } else if (!strcasecmp(opt, option)) 354 1.12 mycroft found = !negative; 355 1.12 mycroft } 356 1.12 mycroft free(optbuf); 357 1.106 christos return found; 358 1.1 cgd } 359 1.1 cgd 360 1.52 jdolecek static int 361 1.99 ast mountfs(const char *vfstype, const char *spec, const char *name, 362 1.94 christos int flags, const char *options, const char *mntopts, 363 1.94 christos int skipmounted, char *buf, size_t buflen) 364 1.1 cgd { 365 1.12 mycroft /* List of directories containing mount_xxx subcommands. */ 366 1.12 mycroft static const char *edirs[] = { 367 1.72 christos #ifdef RESCUEDIR 368 1.72 christos RESCUEDIR, 369 1.60 lukem #endif 370 1.12 mycroft _PATH_SBIN, 371 1.12 mycroft _PATH_USRSBIN, 372 1.12 mycroft NULL 373 1.12 mycroft }; 374 1.82 christos const char ** volatile argv, **edir; 375 1.69 christos struct statvfs *sfp, sf; 376 1.12 mycroft pid_t pid; 377 1.61 christos int pfd[2]; 378 1.36 drochner int argc, numfs, i, status, maxargc; 379 1.33 christos char *optbuf, execname[MAXPATHLEN + 1], execbase[MAXPATHLEN], 380 1.33 christos mntpath[MAXPATHLEN]; 381 1.82 christos volatile int getargs; 382 1.1 cgd 383 1.12 mycroft if (realpath(name, mntpath) == NULL) { 384 1.94 christos warn("realpath `%s'", name); 385 1.106 christos return 1; 386 1.12 mycroft } 387 1.1 cgd 388 1.12 mycroft name = mntpath; 389 1.1 cgd 390 1.35 mycroft optbuf = NULL; 391 1.35 mycroft if (mntopts) 392 1.35 mycroft catopt(&optbuf, mntopts); 393 1.81 christos 394 1.81 christos if (options) { 395 1.35 mycroft catopt(&optbuf, options); 396 1.81 christos getargs = strstr(options, "getargs") != NULL; 397 1.81 christos } else 398 1.81 christos getargs = 0; 399 1.81 christos 400 1.35 mycroft if (!mntopts && !options) 401 1.35 mycroft catopt(&optbuf, "rw"); 402 1.12 mycroft 403 1.92 pooka if (getargs == 0 && strcmp(name, "/") == 0 && !hasopt(optbuf, "union")) 404 1.103 mlelstv flags |= FLG_UPDATE; 405 1.22 cgd else if (skipmounted) { 406 1.36 drochner if ((numfs = getmntinfo(&sfp, MNT_WAIT)) == 0) { 407 1.36 drochner warn("getmntinfo"); 408 1.106 christos return 1; 409 1.21 cgd } 410 1.36 drochner for(i = 0; i < numfs; i++) { 411 1.91 pooka const char *mountedtype = sfp[i].f_fstypename; 412 1.91 pooka size_t cmplen = sizeof(sfp[i].f_fstypename); 413 1.91 pooka 414 1.91 pooka /* remove "puffs|" from comparisons, if present */ 415 1.91 pooka #define TYPESIZE (sizeof(PUFFS_TYPEPREFIX)-1) 416 1.91 pooka if (strncmp(mountedtype, 417 1.91 pooka PUFFS_TYPEPREFIX, TYPESIZE) == 0) { 418 1.91 pooka mountedtype += TYPESIZE; 419 1.91 pooka cmplen -= TYPESIZE; 420 1.91 pooka } 421 1.91 pooka 422 1.53 enami /* 423 1.53 enami * XXX can't check f_mntfromname, 424 1.53 enami * thanks to mfs, union, etc. 425 1.53 enami */ 426 1.36 drochner if (strncmp(name, sfp[i].f_mntonname, MNAMELEN) == 0 && 427 1.91 pooka strncmp(vfstype, mountedtype, cmplen) == 0) { 428 1.108 kre if (noise || verbose) 429 1.53 enami (void)printf("%s on %s type %.*s: " 430 1.53 enami "%s\n", 431 1.53 enami sfp[i].f_mntfromname, 432 1.53 enami sfp[i].f_mntonname, 433 1.84 christos (int)sizeof(sfp[i].f_fstypename), 434 1.53 enami sfp[i].f_fstypename, 435 1.53 enami "already mounted"); 436 1.106 christos return 0; 437 1.36 drochner } 438 1.21 cgd } 439 1.21 cgd } 440 1.103 mlelstv if (flags & FLG_FORCE) 441 1.35 mycroft catopt(&optbuf, "force"); 442 1.103 mlelstv if (flags & FLG_RDONLY) 443 1.35 mycroft catopt(&optbuf, "ro"); 444 1.103 mlelstv /* make -w override -r */ 445 1.103 mlelstv if (flags & FLG_RDWRITE) 446 1.103 mlelstv catopt(&optbuf, "rw"); 447 1.33 christos 448 1.103 mlelstv if (flags & FLG_UPDATE) { 449 1.35 mycroft catopt(&optbuf, "update"); 450 1.30 christos /* Figure out the fstype only if we defaulted to ffs */ 451 1.69 christos if (vfstype == ffs_fstype && statvfs(name, &sf) != -1) 452 1.30 christos vfstype = sf.f_fstypename; 453 1.30 christos } 454 1.12 mycroft 455 1.35 mycroft maxargc = 64; 456 1.94 christos argv = ecalloc(maxargc, sizeof(*argv)); 457 1.35 mycroft 458 1.90 pooka if (getargs && 459 1.90 pooka strncmp(vfstype, PUFFS_TYPEPREFIX, sizeof(PUFFS_TYPEPREFIX)-1) == 0) 460 1.90 pooka (void)snprintf(execbase, sizeof(execbase), "mount_puffs"); 461 1.90 pooka else if (hasopt(optbuf, "rump")) 462 1.88 pooka (void)snprintf(execbase, sizeof(execbase), "rump_%s", vfstype); 463 1.88 pooka else 464 1.88 pooka (void)snprintf(execbase, sizeof(execbase), "mount_%s", vfstype); 465 1.12 mycroft argc = 0; 466 1.33 christos argv[argc++] = execbase; 467 1.35 mycroft if (optbuf) 468 1.35 mycroft mangle(optbuf, &argc, &argv, &maxargc); 469 1.12 mycroft argv[argc++] = spec; 470 1.12 mycroft argv[argc++] = name; 471 1.12 mycroft argv[argc] = NULL; 472 1.12 mycroft 473 1.81 christos if ((verbose && buf == NULL) || debug) { 474 1.35 mycroft (void)printf("exec:"); 475 1.35 mycroft for (i = 0; i < argc; i++) 476 1.12 mycroft (void)printf(" %s", argv[i]); 477 1.12 mycroft (void)printf("\n"); 478 1.108 kre if (debug) { 479 1.108 kre /* 480 1.108 kre * Don't proceed to attempt to 481 1.108 kre * print fs data, nothing has been 482 1.108 kre * mounted, anything printed would 483 1.108 kre * be for some other filesystem. 484 1.108 kre */ 485 1.108 kre return 0; 486 1.108 kre } 487 1.12 mycroft } 488 1.5 mycroft 489 1.61 christos if (buf) { 490 1.61 christos if (pipe(pfd) == -1) 491 1.61 christos warn("Cannot create pipe"); 492 1.61 christos } 493 1.61 christos 494 1.100 pooka switch (pid = fork()) { 495 1.12 mycroft case -1: /* Error. */ 496 1.100 pooka warn("fork"); 497 1.35 mycroft if (optbuf) 498 1.35 mycroft free(optbuf); 499 1.80 christos free(argv); 500 1.106 christos return 1; 501 1.35 mycroft 502 1.12 mycroft case 0: /* Child. */ 503 1.34 christos if (debug) 504 1.34 christos _exit(0); 505 1.34 christos 506 1.61 christos if (buf) { 507 1.61 christos (void)close(pfd[0]); 508 1.61 christos (void)close(STDOUT_FILENO); 509 1.61 christos if (dup2(pfd[1], STDOUT_FILENO) == -1) 510 1.61 christos warn("Cannot open fd to mount program"); 511 1.61 christos } 512 1.61 christos 513 1.12 mycroft /* Go find an executable. */ 514 1.12 mycroft edir = edirs; 515 1.12 mycroft do { 516 1.12 mycroft (void)snprintf(execname, 517 1.33 christos sizeof(execname), "%s/%s", *edir, execbase); 518 1.78 christos (void)execv(execname, __UNCONST(argv)); 519 1.12 mycroft if (errno != ENOENT) 520 1.12 mycroft warn("exec %s for %s", execname, name); 521 1.12 mycroft } while (*++edir != NULL); 522 1.1 cgd 523 1.12 mycroft if (errno == ENOENT) 524 1.102 christos warn("exec %s for %s: %s", execbase, name, execbase); 525 1.34 christos _exit(1); 526 1.12 mycroft /* NOTREACHED */ 527 1.35 mycroft 528 1.12 mycroft default: /* Parent. */ 529 1.35 mycroft if (optbuf) 530 1.35 mycroft free(optbuf); 531 1.80 christos free(argv); 532 1.1 cgd 533 1.81 christos if (buf || getargs) { 534 1.61 christos char tbuf[1024], *ptr; 535 1.61 christos int nread; 536 1.64 enami 537 1.61 christos if (buf == NULL) { 538 1.61 christos ptr = tbuf; 539 1.61 christos buflen = sizeof(tbuf) - 1; 540 1.61 christos } else { 541 1.61 christos ptr = buf; 542 1.61 christos buflen--; 543 1.61 christos } 544 1.61 christos (void)close(pfd[1]); 545 1.61 christos (void)signal(SIGPIPE, SIG_IGN); 546 1.61 christos while ((nread = read(pfd[0], ptr, buflen)) > 0) { 547 1.61 christos buflen -= nread; 548 1.61 christos ptr += nread; 549 1.61 christos } 550 1.61 christos *ptr = '\0'; 551 1.61 christos if (buflen == 0) { 552 1.61 christos while (read(pfd[0], &nread, sizeof(nread)) > 0) 553 1.61 christos continue; 554 1.61 christos } 555 1.61 christos if (buf == NULL) 556 1.64 enami (void)fprintf(stdout, "%s", tbuf); 557 1.61 christos } 558 1.61 christos 559 1.94 christos if (waitpid(pid, &status, 0) == -1) { 560 1.12 mycroft warn("waitpid"); 561 1.106 christos return 1; 562 1.1 cgd } 563 1.12 mycroft 564 1.12 mycroft if (WIFEXITED(status)) { 565 1.12 mycroft if (WEXITSTATUS(status) != 0) 566 1.106 christos return WEXITSTATUS(status); 567 1.12 mycroft } else if (WIFSIGNALED(status)) { 568 1.17 jtc warnx("%s: %s", name, strsignal(WTERMSIG(status))); 569 1.106 christos return 1; 570 1.1 cgd } 571 1.12 mycroft 572 1.61 christos if (buf == NULL) { 573 1.108 kre if (verbose || noise) { 574 1.94 christos if (statvfs(name, &sf) == -1) { 575 1.69 christos warn("statvfs %s", name); 576 1.106 christos return 1; 577 1.61 christos } 578 1.61 christos prmount(&sf); 579 1.12 mycroft } 580 1.1 cgd } 581 1.12 mycroft break; 582 1.1 cgd } 583 1.12 mycroft 584 1.106 christos return 0; 585 1.1 cgd } 586 1.1 cgd 587 1.52 jdolecek static void 588 1.76 xtraeme prmount(struct statvfs *sfp) 589 1.13 mycroft { 590 1.12 mycroft int flags; 591 1.52 jdolecek const struct opt *o; 592 1.32 lukem struct passwd *pw; 593 1.12 mycroft int f; 594 1.1 cgd 595 1.53 enami (void)printf("%s on %s type %.*s", sfp->f_mntfromname, 596 1.84 christos sfp->f_mntonname, (int)sizeof(sfp->f_fstypename), 597 1.84 christos sfp->f_fstypename); 598 1.1 cgd 599 1.69 christos flags = sfp->f_flag & MNT_VISFLAGMASK; 600 1.99 ast for (f = 0, o = optnames; flags && o < 601 1.58 christos &optnames[sizeof(optnames)/sizeof(optnames[0])]; o++) 602 1.12 mycroft if (flags & o->o_opt) { 603 1.58 christos if (!o->o_silent || verbose) 604 1.24 cgd (void)printf("%s%s", !f++ ? " (" : ", ", 605 1.24 cgd o->o_name); 606 1.12 mycroft flags &= ~o->o_opt; 607 1.12 mycroft } 608 1.24 cgd if (flags) 609 1.27 pk (void)printf("%sunknown flag%s %#x", !f++ ? " (" : ", ", 610 1.24 cgd flags & (flags - 1) ? "s" : "", flags); 611 1.32 lukem if (sfp->f_owner) { 612 1.32 lukem (void)printf("%smounted by ", !f++ ? " (" : ", "); 613 1.32 lukem if ((pw = getpwuid(sfp->f_owner)) != NULL) 614 1.32 lukem (void)printf("%s", pw->pw_name); 615 1.32 lukem else 616 1.32 lukem (void)printf("%d", sfp->f_owner); 617 1.32 lukem } 618 1.71 enami if (verbose) 619 1.71 enami (void)printf("%sfsid: 0x%x/0x%x", 620 1.71 enami !f++ ? " (" /* ) */: ", ", 621 1.71 enami sfp->f_fsidx.__fsid_val[0], sfp->f_fsidx.__fsid_val[1]); 622 1.71 enami 623 1.61 christos if (verbose) { 624 1.69 christos (void)printf("%s", !f++ ? " (" : ", "); 625 1.70 hannken (void)printf("reads: sync %" PRIu64 " async %" PRIu64 "", 626 1.69 christos sfp->f_syncreads, sfp->f_asyncreads); 627 1.70 hannken (void)printf(", writes: sync %" PRIu64 " async %" PRIu64 "", 628 1.69 christos sfp->f_syncwrites, sfp->f_asyncwrites); 629 1.61 christos if (verbose > 1) { 630 1.61 christos char buf[2048]; 631 1.63 enami 632 1.61 christos if (getmntargs(sfp, buf, sizeof(buf))) 633 1.63 enami printf(", [%s: %s]", sfp->f_fstypename, buf); 634 1.61 christos } 635 1.63 enami printf(")\n"); 636 1.61 christos } else 637 1.50 is (void)printf("%s", f ? ")\n" : "\n"); 638 1.61 christos } 639 1.61 christos 640 1.61 christos static int 641 1.76 xtraeme getmntargs(struct statvfs *sfs, char *buf, size_t buflen) 642 1.61 christos { 643 1.64 enami 644 1.61 christos if (mountfs(sfs->f_fstypename, sfs->f_mntfromname, sfs->f_mntonname, 0, 645 1.61 christos "getargs", NULL, 0, buf, buflen)) 646 1.106 christos return 0; 647 1.61 christos else { 648 1.61 christos if (*buf == '\0') 649 1.106 christos return 0; 650 1.61 christos if ((buf = strchr(buf, '\n')) != NULL) 651 1.61 christos *buf = '\0'; 652 1.106 christos return 1; 653 1.61 christos } 654 1.1 cgd } 655 1.1 cgd 656 1.69 christos static struct statvfs * 657 1.76 xtraeme getmntpt(const char *name) 658 1.1 cgd { 659 1.69 christos struct statvfs *mntbuf; 660 1.12 mycroft int i, mntsize; 661 1.1 cgd 662 1.1 cgd mntsize = getmntinfo(&mntbuf, MNT_NOWAIT); 663 1.12 mycroft for (i = 0; i < mntsize; i++) 664 1.12 mycroft if (strcmp(mntbuf[i].f_mntfromname, name) == 0 || 665 1.12 mycroft strcmp(mntbuf[i].f_mntonname, name) == 0) 666 1.106 christos return &mntbuf[i]; 667 1.106 christos return NULL; 668 1.1 cgd } 669 1.1 cgd 670 1.52 jdolecek static void 671 1.76 xtraeme catopt(char **sp, const char *o) 672 1.12 mycroft { 673 1.67 itojun char *s, *n; 674 1.12 mycroft 675 1.35 mycroft s = *sp; 676 1.35 mycroft if (s) { 677 1.94 christos easprintf(&n, "%s,%s", s, o); 678 1.67 itojun free(s); 679 1.67 itojun s = n; 680 1.12 mycroft } else 681 1.94 christos s = estrdup(o); 682 1.35 mycroft *sp = s; 683 1.1 cgd } 684 1.1 cgd 685 1.35 mycroft static void 686 1.82 christos mangle(char *options, int *argcp, const char ** volatile *argvp, int *maxargcp) 687 1.1 cgd { 688 1.12 mycroft char *p, *s; 689 1.35 mycroft int argc, maxargc; 690 1.67 itojun const char **argv, **nargv; 691 1.1 cgd 692 1.12 mycroft argc = *argcp; 693 1.35 mycroft argv = *argvp; 694 1.35 mycroft maxargc = *maxargcp; 695 1.35 mycroft 696 1.35 mycroft for (s = options; (p = strsep(&s, ",")) != NULL;) { 697 1.35 mycroft /* Always leave space for one more argument and the NULL. */ 698 1.35 mycroft if (argc >= maxargc - 4) { 699 1.94 christos nargv = erealloc(argv, (maxargc << 1) * sizeof(nargv)); 700 1.67 itojun argv = nargv; 701 1.35 mycroft maxargc <<= 1; 702 1.35 mycroft } 703 1.44 ross if (*p != '\0') { 704 1.12 mycroft if (*p == '-') { 705 1.12 mycroft argv[argc++] = p; 706 1.12 mycroft p = strchr(p, '='); 707 1.12 mycroft if (p) { 708 1.12 mycroft *p = '\0'; 709 1.12 mycroft argv[argc++] = p+1; 710 1.1 cgd } 711 1.103 mlelstv } else { 712 1.12 mycroft argv[argc++] = "-o"; 713 1.12 mycroft argv[argc++] = p; 714 1.1 cgd } 715 1.44 ross } 716 1.35 mycroft } 717 1.12 mycroft 718 1.12 mycroft *argcp = argc; 719 1.35 mycroft *argvp = argv; 720 1.35 mycroft *maxargcp = maxargc; 721 1.48 abs } 722 1.48 abs 723 1.53 enami /* Deduce the filesystem type from the disk label. */ 724 1.53 enami static const char * 725 1.76 xtraeme getfslab(const char *str) 726 1.48 abs { 727 1.73 thorpej static struct dkwedge_info dkw; 728 1.48 abs struct disklabel dl; 729 1.48 abs int fd; 730 1.48 abs int part; 731 1.48 abs const char *vfstype; 732 1.48 abs u_char fstype; 733 1.53 enami char buf[MAXPATHLEN + 1]; 734 1.51 abs char *sp, *ep; 735 1.48 abs 736 1.51 abs if ((fd = open(str, O_RDONLY)) == -1) { 737 1.51 abs /* 738 1.51 abs * Iff we get EBUSY try the raw device. Since mount always uses 739 1.51 abs * the block device we know we are never passed a raw device. 740 1.51 abs */ 741 1.51 abs if (errno != EBUSY) 742 1.94 christos err(EXIT_FAILURE, "cannot open `%s'", str); 743 1.51 abs strlcpy(buf, str, MAXPATHLEN); 744 1.51 abs if ((sp = strrchr(buf, '/')) != NULL) 745 1.51 abs ++sp; 746 1.51 abs else 747 1.51 abs sp = buf; 748 1.53 enami for (ep = sp + strlen(sp) + 1; ep > sp; ep--) 749 1.53 enami *ep = *(ep - 1); 750 1.51 abs *sp = 'r'; 751 1.51 abs 752 1.51 abs /* Silently fail here - mount call can display error */ 753 1.51 abs if ((fd = open(buf, O_RDONLY)) == -1) 754 1.106 christos return NULL; 755 1.51 abs } 756 1.49 abs 757 1.73 thorpej /* Check to see if this is a wedge. */ 758 1.73 thorpej if (ioctl(fd, DIOCGWEDGEINFO, &dkw) == 0) { 759 1.73 thorpej /* Yup, this is easy. */ 760 1.106 christos close(fd); 761 1.107 christos if (*dkw.dkw_ptype) 762 1.106 christos return dkw.dkw_ptype; 763 1.106 christos return NULL; 764 1.73 thorpej } 765 1.73 thorpej 766 1.51 abs if (ioctl(fd, DIOCGDINFO, &dl) == -1) { 767 1.54 enami (void) close(fd); 768 1.106 christos return NULL; 769 1.49 abs } 770 1.48 abs 771 1.48 abs (void) close(fd); 772 1.48 abs 773 1.48 abs part = str[strlen(str) - 1] - 'a'; 774 1.48 abs 775 1.48 abs if (part < 0 || part >= dl.d_npartitions) 776 1.106 christos return NULL; 777 1.48 abs 778 1.48 abs /* Return NULL for unknown types - caller can fall back to ffs */ 779 1.48 abs if ((fstype = dl.d_partitions[part].p_fstype) >= FSMAXMOUNTNAMES) 780 1.48 abs vfstype = NULL; 781 1.48 abs else 782 1.48 abs vfstype = mountnames[fstype]; 783 1.48 abs 784 1.106 christos return vfstype; 785 1.1 cgd } 786 1.1 cgd 787 1.52 jdolecek static void 788 1.76 xtraeme usage(void) 789 1.1 cgd { 790 1.1 cgd 791 1.94 christos (void)fprintf(stderr, "Usage: %s [-Aadfruvw] [-t type]\n" 792 1.94 christos "\t%s [-dfruvw] special | node\n" 793 1.94 christos "\t%s [-dfruvw] [-o options] [-t type] special node\n", 794 1.94 christos getprogname(), getprogname(), getprogname()); 795 1.12 mycroft exit(1); 796 1.1 cgd } 797