return error from copying in arg list, not from throwing it away
[unix-history] / usr / src / sbin / mount / mount.c
CommitLineData
4ba29bcc 1/*
f58c02bf
KM
2 * Copyright (c) 1980, 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
4ba29bcc
DF
16 */
17
18#ifndef lint
19char copyright[] =
f58c02bf 20"@(#) Copyright (c) 1980, 1989 The Regents of the University of California.\n\
4ba29bcc 21 All rights reserved.\n";
f58c02bf 22#endif /* not lint */
4ba29bcc 23
a3c5c1bf 24#ifndef lint
9965791c 25static char sccsid[] = "@(#)mount.c 5.18 (Berkeley) %G%";
f58c02bf 26#endif /* not lint */
9dc9fb3d 27
c6534479 28#include "pathnames.h"
7a6d69cb 29#include <sys/param.h>
f8836a3c 30#include <sys/file.h>
71799463 31#include <sys/time.h>
c265c4cc 32#include <sys/wait.h>
a3c5c1bf 33#include <fstab.h>
78b57350 34#include <errno.h>
f8836a3c 35#include <stdio.h>
71799463
KM
36#include <strings.h>
37#include <sys/dir.h>
38#include <sys/uio.h>
39#include <sys/namei.h>
40#include <sys/mount.h>
41#ifdef NFS
42#include <sys/socket.h>
43#include <sys/socketvar.h>
44#include <netdb.h>
45#include <rpc/rpc.h>
46#include <rpc/pmap_clnt.h>
47#include <rpc/pmap_prot.h>
48#include <nfs/rpcv2.h>
49#include <nfs/nfsv2.h>
50#include <nfs/nfs.h>
51#endif
9dc9fb3d 52
f8836a3c
KB
53#define BADTYPE(type) \
54 (strcmp(type, FSTAB_RO) && strcmp(type, FSTAB_RW) && \
55 strcmp(type, FSTAB_RQ))
56#define SETTYPE(type) \
57 (!strcmp(type, FSTAB_RW) || !strcmp(type, FSTAB_RQ))
9dc9fb3d 58
169158fc 59int fake, verbose, updateflg, mnttype;
f58c02bf 60char *mntname, **envp;
c6534479 61
71799463
KM
62#ifdef NFS
63int xdr_dir(), xdr_fh();
edac6b76 64char *getnfsargs();
71799463
KM
65struct nfs_args nfsargs = {
66 (struct sockaddr_in *)0,
67 (nfsv2fh_t *)0,
68 0,
69 NFS_WSIZE,
70 NFS_RSIZE,
71 NFS_TIMEO,
72 NFS_RETRANS,
73 (char *)0,
74};
75
76struct nfhret {
77 u_long stat;
78 nfsv2fh_t nfh;
79};
80int retrycnt = 10000;
81#define BGRND 1
82#define ISBGRND 2
83int opflags = 0;
84#endif
62c2bd36 85
c6534479 86main(argc, argv, arge)
62c2bd36
BJ
87 int argc;
88 char **argv;
c6534479 89 char **arge;
9dc9fb3d 90{
f8836a3c
KB
91 extern char *optarg;
92 extern int optind;
f8836a3c
KB
93 register struct fstab *fs;
94 register int cnt;
169158fc 95 int all, ch, rval, flags, i;
edac6b76 96 long mntsize;
9965791c 97 struct statfs *mntbuf, *getmntpt();
c6534479 98 char *type, *options = NULL;
f8836a3c 99
c6534479 100 envp = arge;
f8836a3c
KB
101 all = 0;
102 type = NULL;
71799463 103 mnttype = MOUNT_UFS;
f58c02bf 104 mntname = "ufs";
169158fc 105 while ((ch = getopt(argc, argv, "afrwuvt:o:")) != EOF)
f8836a3c
KB
106 switch((char)ch) {
107 case 'a':
108 all = 1;
109 break;
110 case 'f':
111 fake = 1;
112 break;
113 case 'r':
7a6d69cb 114 type = FSTAB_RO;
f8836a3c 115 break;
169158fc
KM
116 case 'u':
117 updateflg = M_UPDATE;
118 break;
f8836a3c
KB
119 case 'v':
120 verbose = 1;
121 break;
122 case 'w':
123 type = FSTAB_RW;
124 break;
71799463 125 case 'o':
c6534479 126 options = optarg;
71799463 127 break;
c6534479 128 case 't':
f58c02bf
KM
129 mnttype = getmnttype(optarg);
130 break;
f8836a3c
KB
131 case '?':
132 default:
133 usage();
c6534479 134 /* NOTREACHED */
df611cb9 135 }
f8836a3c
KB
136 argc -= optind;
137 argv += optind;
138
139 /* NOSTRICT */
f8836a3c 140
df611cb9 141 if (all) {
a15efba1 142 rval = 0;
169158fc 143 while (fs = getfsent()) {
499c04f5
KB
144 if (BADTYPE(fs->fs_type))
145 continue;
146 /* `/' is special, it's always mounted */
147 if (!strcmp(fs->fs_file, "/"))
169158fc
KM
148 flags = M_UPDATE;
149 else
150 flags = updateflg;
151 mnttype = getmnttype(fs->fs_vfstype);
152 rval |= mountfs(fs->fs_spec, fs->fs_file, flags,
153 type, options, fs->fs_mntops);
499c04f5 154 }
5ad3e76c 155 exit(rval);
9dc9fb3d 156 }
f8836a3c
KB
157
158 if (argc == 0) {
159 if (verbose || fake || type)
160 usage();
c64e24b9
KM
161 if ((mntsize = getmntinfo(&mntbuf)) == 0) {
162 fprintf(stderr,
163 "mount: cannot get mount information\n");
edac6b76
KM
164 exit(1);
165 }
b5ce7fc9 166 for (i = 0; i < mntsize; i++)
edac6b76 167 prmount(mntbuf[i].f_mntfromname, mntbuf[i].f_mntonname,
b5ce7fc9 168 mntbuf[i].f_flags);
7a6d69cb
SL
169 exit(0);
170 }
f8836a3c 171
9965791c
KM
172 if (argc == 1 && updateflg) {
173 if ((mntbuf = getmntpt(*argv)) == NULL) {
174 fprintf(stderr,
175 "mount: unknown special file or file system %s.\n",
176 *argv);
177 exit(1);
178 }
179 mnttype = mntbuf->f_type;
180 exit(mountfs(mntbuf->f_mntfromname, mntbuf->f_mntonname,
181 updateflg, type, options, NULL));
182 }
183
f8836a3c
KB
184 if (argc == 1) {
185 if (!(fs = getfsfile(*argv)) && !(fs = getfsspec(*argv))) {
186 fprintf(stderr,
187 "mount: unknown special file or file system %s.\n",
188 *argv);
189 exit(1);
190 }
191 if (BADTYPE(fs->fs_type)) {
192 fprintf(stderr,
193 "mount: %s has unknown file system type.\n", *argv);
194 exit(1);
195 }
169158fc
KM
196 mnttype = getmnttype(fs->fs_vfstype);
197 exit(mountfs(fs->fs_spec, fs->fs_file, updateflg,
198 type, options, fs->fs_mntops));
df611cb9 199 }
9dc9fb3d 200
f8836a3c
KB
201 if (argc != 2)
202 usage();
7a6d69cb 203
169158fc 204 exit(mountfs(argv[0], argv[1], updateflg, type, options, NULL));
7a6d69cb
SL
205}
206
169158fc 207mountfs(spec, name, flags, type, options, mntopts)
c6534479 208 char *spec, *name, *type, *options, *mntopts;
169158fc 209 int flags;
9dc9fb3d 210{
f8836a3c 211 extern int errno;
f8836a3c 212 register int cnt;
169158fc 213 int argc, status, i;
e2b196df 214 struct ufs_args args;
c6534479 215 char *argp, *argv[50];
f58c02bf 216 char execname[MAXPATHLEN + 1], flagval[12];
9dc9fb3d 217
b5ce7fc9
KM
218 if (mntopts)
219 getstdopts(mntopts, &flags);
169158fc
KM
220 if (options)
221 getstdopts(options, &flags);
222 if (type)
223 getstdopts(type, &flags);
b5ce7fc9
KM
224 switch (mnttype) {
225 case MOUNT_UFS:
b5ce7fc9
KM
226 if (mntopts)
227 getufsopts(mntopts, &flags);
169158fc
KM
228 if (options)
229 getufsopts(options, &flags);
b5ce7fc9
KM
230 args.fspec = spec;
231 argp = (caddr_t)&args;
232 break;
edac6b76
KM
233
234#ifdef NFS
b5ce7fc9 235 case MOUNT_NFS:
b5ce7fc9 236 if (mntopts)
169158fc
KM
237 getnfsopts(mntopts, &nfsargs, &opflags, &retrycnt);
238 if (options)
239 getnfsopts(options, &nfsargs, &opflags, &retrycnt);
b5ce7fc9
KM
240 if (argp = getnfsargs(spec, name, type))
241 break;
242 return (1);
edac6b76
KM
243#endif /* NFS */
244
b5ce7fc9 245 case MOUNT_MFS:
f58c02bf
KM
246 default:
247 argv[0] = mntname;
ee64568e 248 argc = 1;
f58c02bf
KM
249 if (flags) {
250 argv[argc++] = "-F";
251 sprintf(flagval, "%d", flags);
252 argv[argc++] = flagval;
253 }
ee64568e
KM
254 if (mntopts)
255 argc += getexecopts(mntopts, &argv[argc]);
169158fc
KM
256 if (options)
257 argc += getexecopts(options, &argv[argc]);
b5ce7fc9
KM
258 argv[argc++] = spec;
259 argv[argc++] = name;
f58c02bf 260 sprintf(execname, "%s/%s", _PATH_EXECDIR, mntname);
b5ce7fc9 261 if (verbose) {
f58c02bf
KM
262 printf("exec: %s", execname);
263 for (i = 1; i < argc; i++)
b5ce7fc9
KM
264 printf(" %s", argv[i]);
265 printf("\n");
266 }
267 if (fake)
268 break;
269 if (i = vfork()) {
270 if (i == -1) {
f58c02bf 271 perror("mount: vfork starting file system");
b5ce7fc9 272 return (1);
c6534479 273 }
b5ce7fc9
KM
274 if (waitpid(i, &status, 0) != -1 &&
275 WIFEXITED(status) &&
276 WEXITSTATUS(status) != 0)
277 return (WEXITSTATUS(status));
f58c02bf 278 spec = mntname;
b5ce7fc9
KM
279 goto out;
280 }
f58c02bf
KM
281 execve(execname, argv, envp);
282 perror(execname);
b5ce7fc9 283 exit (1);
b5ce7fc9 284 /* NOTREACHED */
edac6b76 285
b5ce7fc9
KM
286 }
287 if (!fake && mount(mnttype, name, flags, argp)) {
288 if (opflags & ISBGRND)
289 exit(1);
290 fprintf(stderr, "%s on %s: ", spec, name);
291 switch (errno) {
292 case EMFILE:
293 fprintf(stderr, "Mount table full\n");
294 break;
295 case EINVAL:
169158fc
KM
296 if (flags & M_UPDATE)
297 fprintf(stderr, "Specified device does %s\n",
298 "not match mounted device");
299 else
300 fprintf(stderr, "Bogus super block\n");
301 break;
302 case EOPNOTSUPP:
303 fprintf(stderr, "Operation not supported\n");
b5ce7fc9
KM
304 break;
305 default:
306 perror((char *)NULL);
307 break;
df611cb9 308 }
b5ce7fc9 309 return(1);
7a6d69cb 310 }
f8836a3c 311
c6534479 312out:
7a6d69cb 313 if (verbose)
b5ce7fc9 314 prmount(spec, name, flags);
f8836a3c 315
71799463
KM
316 if (opflags & ISBGRND)
317 exit();
318 else
319 return(0);
f8836a3c
KB
320}
321
322static
b5ce7fc9
KM
323prmount(spec, name, flags)
324 char *spec, *name;
325 long flags;
f8836a3c 326{
edac6b76
KM
327 register char *root;
328
71799463
KM
329 if (opflags & ISBGRND)
330 return;
edac6b76
KM
331 /*
332 * trim trailing /'s and find last component of name
333 */
334 for (root = index(spec, '\0'); *--root == '/';)
335 /* void */;
336 *++root = '\0';
337 if (root = rindex(spec, '/'))
338 spec = root + 1;
339 printf("%s on %s", spec, name);
b5ce7fc9
KM
340 if (flags & M_RDONLY)
341 printf(" (read-only)");
342 if (flags & M_NOEXEC)
343 printf(" (noexec)");
344 if (flags & M_NOSUID)
345 printf(" (nosuid)");
346 if (flags & M_NODEV)
347 printf(" (nodev)");
348 if (flags & M_SYNCHRONOUS)
349 printf(" (synchronous)");
169158fc
KM
350 if (flags & M_UPDATE)
351 printf(" (update only)");
f8836a3c
KB
352 printf("\n");
353}
354
c265c4cc
KM
355getmnttype(fstype)
356 char *fstype;
357{
358
f58c02bf 359 mntname = fstype;
c265c4cc
KM
360 if (!strcmp(fstype, "ufs"))
361 return (MOUNT_UFS);
362 if (!strcmp(fstype, "nfs"))
363 return (MOUNT_NFS);
364 if (!strcmp(fstype, "mfs"))
365 return (MOUNT_MFS);
366 return (0);
367}
368
f8836a3c
KB
369usage()
370{
169158fc 371 fprintf(stderr, "usage: mount [-afurw]\nor mount [-furw] special | node\nor mount [-furw] special node\n");
f8836a3c 372 exit(1);
9dc9fb3d 373}
71799463 374
b5ce7fc9
KM
375getstdopts(options, flagp)
376 char *options;
377 long *flagp;
378{
379 register char *opt;
380 int negative;
381 char *optbuf[BUFSIZ], *strtok();
382
383 strcpy(optbuf, options);
384 for (opt = strtok(optbuf, ","); opt; opt = strtok(NULL, ",")) {
385 if (opt[0] == 'n' && opt[1] == 'o') {
386 negative++;
387 opt += 2;
388 } else {
389 negative = 0;
390 }
169158fc
KM
391 if (!negative && !strcasecmp(opt, FSTAB_RO)) {
392 *flagp |= M_RDONLY;
393 continue;
394 }
395 if (!negative && !strcasecmp(opt, FSTAB_RW)) {
396 *flagp &= ~M_RDONLY;
397 continue;
398 }
b5ce7fc9
KM
399 if (!strcasecmp(opt, "exec")) {
400 if (negative)
401 *flagp |= M_NOEXEC;
169158fc
KM
402 else
403 *flagp &= ~M_NOEXEC;
b5ce7fc9
KM
404 continue;
405 }
406 if (!strcasecmp(opt, "suid")) {
407 if (negative)
408 *flagp |= M_NOSUID;
169158fc
KM
409 else
410 *flagp &= ~M_NOSUID;
b5ce7fc9
KM
411 continue;
412 }
413 if (!strcasecmp(opt, "dev")) {
414 if (negative)
415 *flagp |= M_NODEV;
169158fc
KM
416 else
417 *flagp &= ~M_NODEV;
b5ce7fc9
KM
418 continue;
419 }
420 if (!strcasecmp(opt, "synchronous")) {
421 if (!negative)
422 *flagp |= M_SYNCHRONOUS;
169158fc
KM
423 else
424 *flagp &= ~M_SYNCHRONOUS;
b5ce7fc9
KM
425 continue;
426 }
427 }
428}
429
c6534479
KM
430getufsopts(options, flagp)
431 char *options;
432 long *flagp;
433{
434
435 return;
436}
437
ee64568e 438getexecopts(options, argv)
c6534479
KM
439 char *options;
440 char **argv;
441{
442 register int argc = 0;
443 register char *opt;
444 char *strtok();
445
446 for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) {
447 if (opt[0] != '-')
448 continue;
449 argv[argc++] = opt;
450 if (opt[2] == '\0' || opt[2] != '=')
451 continue;
452 opt[2] = '\0';
453 argv[argc++] = &opt[3];
454 }
455 return (argc);
456}
c6534479 457
9965791c
KM
458struct statfs *
459getmntpt(name)
460 char *name;
461{
462 long mntsize;
463 register long i;
464 struct statfs *mntbuf;
465
466 mntsize = getmntinfo(&mntbuf);
467 for (i = 0; i < mntsize; i++) {
468 if (!strcmp(mntbuf[i].f_mntfromname, name) ||
469 !strcmp(mntbuf[i].f_mntonname, name))
470 return (&mntbuf[i]);
471 }
472 return ((struct statfs *)0);
473}
474
71799463 475#ifdef NFS
c6534479
KM
476/*
477 * Handle the getoption arg.
478 * Essentially update "opflags", "retrycnt" and "nfsargs"
479 */
480getnfsopts(optarg, nfsargsp, opflagsp, retrycntp)
481 char *optarg;
482 struct nfs_args *nfsargsp;
483 int *opflagsp;
484 int *retrycntp;
485{
486 register char *cp, *nextcp;
487 int num;
488 char *nump;
489
490 cp = optarg;
491 while (cp != NULL && *cp != '\0') {
492 if ((nextcp = index(cp, ',')) != NULL)
493 *nextcp++ = '\0';
494 if ((nump = index(cp, '=')) != NULL) {
495 *nump++ = '\0';
496 num = atoi(nump);
497 } else
498 num = -1;
499 /*
500 * Just test for a string match and do it
501 */
502 if (!strcmp(cp, "bg")) {
503 *opflagsp |= BGRND;
504 } else if (!strcmp(cp, "soft")) {
505 nfsargsp->flags |= NFSMNT_SOFT;
506 } else if (!strcmp(cp, "intr")) {
507 nfsargsp->flags |= NFSMNT_INT;
508 } else if (!strcmp(cp, "retry") && num > 0) {
509 *retrycntp = num;
510 } else if (!strcmp(cp, "rsize") && num > 0) {
511 nfsargsp->rsize = num;
512 nfsargsp->flags |= NFSMNT_RSIZE;
513 } else if (!strcmp(cp, "wsize") && num > 0) {
514 nfsargsp->wsize = num;
515 nfsargsp->flags |= NFSMNT_WSIZE;
516 } else if (!strcmp(cp, "timeo") && num > 0) {
517 nfsargsp->timeo = num;
518 nfsargsp->flags |= NFSMNT_TIMEO;
519 } else if (!strcmp(cp, "retrans") && num > 0) {
520 nfsargsp->retrans = num;
521 nfsargsp->flags |= NFSMNT_RETRANS;
522 }
523 cp = nextcp;
524 }
525}
526
edac6b76
KM
527char *
528getnfsargs(spec)
529 char *spec;
530{
531 register CLIENT *clp;
532 struct hostent *hp;
533 struct sockaddr_in saddr;
534 struct timeval pertry, try;
535 enum clnt_stat clnt_stat;
536 int so = RPC_ANYSOCK;
537 char *hostp, *delimp;
538 u_short tport;
539 struct nfhret nfhret;
540 char nam[MNAMELEN + 1];
541
542 strncpy(nam, spec, MNAMELEN);
543 nam[MNAMELEN] = '\0';
544 if ((delimp = index(spec, '@')) != NULL) {
545 hostp = delimp + 1;
546 } else if ((delimp = index(spec, ':')) != NULL) {
547 hostp = spec;
548 spec = delimp + 1;
549 } else {
550 fprintf(stderr,
551 "No <host>:<dirpath> or <dirpath>@<host> spec\n");
552 return (0);
553 }
554 *delimp = '\0';
555 if ((hp = gethostbyname(hostp)) == NULL) {
556 fprintf(stderr, "Can't get net id for host\n");
557 return (0);
558 }
559 bcopy(hp->h_addr, (caddr_t)&saddr.sin_addr, hp->h_length);
560 nfhret.stat = EACCES; /* Mark not yet successful */
561 while (retrycnt > 0) {
562 saddr.sin_family = AF_INET;
563 saddr.sin_port = htons(PMAPPORT);
564 if ((tport = pmap_getport(&saddr, RPCPROG_NFS,
565 NFS_VER2, IPPROTO_UDP)) == 0) {
566 if ((opflags & ISBGRND) == 0)
567 clnt_pcreateerror("NFS Portmap");
568 } else {
569 saddr.sin_port = 0;
570 pertry.tv_sec = 10;
571 pertry.tv_usec = 0;
572 if ((clp = clntudp_create(&saddr, RPCPROG_MNT,
573 RPCMNT_VER1, pertry, &so)) == NULL) {
574 if ((opflags & ISBGRND) == 0)
575 clnt_pcreateerror("Cannot MNT PRC");
576 } else {
577 clp->cl_auth = authunix_create_default();
578 try.tv_sec = 10;
579 try.tv_usec = 0;
580 clnt_stat = clnt_call(clp, RPCMNT_MOUNT,
581 xdr_dir, spec, xdr_fh, &nfhret, try);
582 if (clnt_stat != RPC_SUCCESS) {
583 if ((opflags & ISBGRND) == 0)
584 clnt_perror(clp, "Bad MNT RPC");
585 } else {
586 auth_destroy(clp->cl_auth);
587 clnt_destroy(clp);
588 retrycnt = 0;
589 }
590 }
591 }
592 if (--retrycnt > 0) {
593 if (opflags & BGRND) {
594 opflags &= ~BGRND;
595 if (fork())
596 return (0);
597 else
598 opflags |= ISBGRND;
599 }
600 sleep(10);
601 }
602 }
603 if (nfhret.stat) {
604 if (opflags & ISBGRND)
605 exit(1);
606 fprintf(stderr, "Can't access %s, errno=%d\n", spec,
607 nfhret.stat);
608 return (0);
609 }
610 saddr.sin_port = htons(tport);
611 nfsargs.addr = &saddr;
612 nfsargs.fh = &nfhret.nfh;
613 nfsargs.hostname = nam;
614 return ((caddr_t)&nfsargs);
615}
616
71799463
KM
617/*
618 * xdr routines for mount rpc's
619 */
620xdr_dir(xdrsp, dirp)
621 XDR *xdrsp;
622 char *dirp;
623{
624 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
625}
626
627xdr_fh(xdrsp, np)
628 XDR *xdrsp;
629 struct nfhret *np;
630{
631 if (!xdr_u_long(xdrsp, &(np->stat)))
632 return (0);
633 if (np->stat)
634 return (1);
635 return (xdr_opaque(xdrsp, (caddr_t)&(np->nfh), NFSX_FH));
636}
edac6b76 637#endif /* NFS */