Upload Tizen:Base source
[framework/base/util-linux-ng.git] / mount / umount.c
1 /*
2  * umount(8) for Linux 0.99 - jrs, 1993
3  */
4
5 #include <stdio.h>
6 #include <unistd.h>
7 #include <getopt.h>
8 #include <string.h>
9 #include <errno.h>
10 #include <ctype.h>
11 #include <sys/stat.h>
12 #include <sys/wait.h>
13 #include <sys/mount.h>
14 #include "mount_constants.h"
15 #include "sundries.h"
16 #include "getusername.h"
17 #include "pathnames.h"
18 #include "lomount.h"
19 #include "loop.h"
20 #include "fstab.h"
21 #include "env.h"
22 #include "nls.h"
23
24 #if defined(MNT_FORCE)
25 /* Interesting ... it seems libc knows about MNT_FORCE and presumably
26    about umount2 as well -- need not do anything */
27 #else /* MNT_FORCE */
28
29 /* Does the present kernel source know about umount2? */
30 #include <linux/unistd.h>
31 #ifdef __NR_umount2
32
33 static int umount2(const char *path, int flags);
34
35 _syscall2(int, umount2, const char *, path, int, flags);
36
37 #else /* __NR_umount2 */
38
39 static int
40 umount2(const char *path, int flags) {
41         fprintf(stderr, _("umount: compiled without support for -f\n"));
42         errno = ENOSYS;
43         return -1;
44 }
45 #endif /* __NR_umount2 */
46
47 #if !defined(MNT_FORCE)
48 /* dare not try to include <linux/mount.h> -- lots of errors */
49 #define MNT_FORCE 1
50 #endif
51
52 #endif /* MNT_FORCE */
53
54 #if !defined(MNT_DETACH)
55 #define MNT_DETACH 2
56 #endif
57
58
59 /* True if we are allowed to call /sbin/umount.${FSTYPE} */
60 int external_allowed = 1;
61
62 /* Nonzero for force umount (-f).  There is kernel support since 2.1.116.  */
63 int force = 0;
64
65 /* Nonzero for lazy umount (-l).  There is kernel support since 2.4.11.  */
66 int lazy = 0;
67
68 /* When umount fails, attempt a read-only remount (-r). */
69 int remount = 0;
70
71 /* Don't write a entry in /etc/mtab (-n).  */
72 int nomtab = 0;
73
74 /* Call losetup -d for each unmounted loop device. */
75 int delloop = 0;
76
77 /* True if (ruid != euid) or (0 != ruid), i.e. only "user" umounts permitted. */
78 int restricted = 1;
79
80 /* Last error message */
81 int complained_err = 0;
82 char *complained_dev = NULL;
83
84 /*
85  * check_special_umountprog()
86  *      If there is a special umount program for this type, exec it.
87  * returns: 0: no exec was done, 1: exec was done, status has result
88  */
89 static int
90 check_special_umountprog(const char *spec, const char *node,
91                          const char *type, int *status) {
92         char umountprog[120];
93         struct stat statbuf;
94         int res;
95
96         if (!external_allowed)
97                 return 0;
98
99         if (type == NULL || strcmp(type, "none") == 0)
100                 return 0;
101
102         if (strlen(type) < 100) {
103                 sprintf(umountprog, "/sbin/umount.%s", type);
104                 if (stat(umountprog, &statbuf) == 0) {
105                         res = fork();
106                         if (res == 0) {
107                                 char *umountargs[8];
108                                 int i = 0;
109
110                                 if(setgid(getgid()) < 0)
111                                         die(EX_FAIL, _("umount: cannot set group id: %s"), strerror(errno));
112
113                                 if(setuid(getuid()) < 0)
114                                         die(EX_FAIL, _("umount: cannot set user id: %s"), strerror(errno));
115
116                                 umountargs[i++] = umountprog;
117                                 umountargs[i++] = xstrdup(node);
118                                 if (nomtab)
119                                         umountargs[i++] = "-n";
120                                 if (lazy)
121                                         umountargs[i++] = "-l";
122                                 if (force)
123                                         umountargs[i++] = "-f";
124                                 if (verbose)
125                                         umountargs[i++] = "-v";
126                                 if (remount)
127                                         umountargs[i++] = "-r";
128                                 umountargs[i] = NULL;
129                                 execv(umountprog, umountargs);
130                                 exit(1);        /* exec failed */
131                         } else if (res != -1) {
132                                 int st;
133                                 wait(&st);
134                                 *status = (WIFEXITED(st) ? WEXITSTATUS(st)
135                                            : EX_SYSERR);
136                                 return 1;
137                         } else {
138                                 int errsv = errno;
139                                 error(_("umount: cannot fork: %s"),
140                                       strerror(errsv));
141                         }
142                 }
143         }
144         return 0;
145 }
146
147 /* complain about a failed umount */
148 static void complain(int err, const char *dev) {
149
150   if (complained_err == err && complained_dev && dev &&
151                   strcmp(dev, complained_dev) == 0)
152     return;
153
154   complained_err = err;
155   free(complained_dev);
156   complained_dev = xstrdup(dev);
157
158   switch (err) {
159     case ENXIO:
160       error (_("umount: %s: invalid block device"), dev); break;
161     case EINVAL:
162       error (_("umount: %s: not mounted"), dev); break;
163     case EIO:
164       error (_("umount: %s: can't write superblock"), dev); break;
165     case EBUSY:
166      /* Let us hope fstab has a line "proc /proc ..."
167         and not "none /proc ..."*/
168       error (_("umount: %s: device is busy.\n"
169                "        (In some cases useful info about processes that use\n"
170                "         the device is found by lsof(8) or fuser(1))"), dev);
171       break;
172     case ENOENT:
173       error (_("umount: %s: not found"), dev); break;
174     case EPERM:
175       error (_("umount: %s: must be superuser to umount"), dev); break;
176     case EACCES:
177       error (_("umount: %s: block devices not permitted on fs"), dev); break;
178     default:
179       error (_("umount: %s: %s"), dev, strerror (err)); break;
180   }
181 }
182
183 /* Umount a single device.  Return a status code, so don't exit
184    on a non-fatal error.  We lock/unlock around each umount.  */
185 static int
186 umount_one (const char *spec, const char *node, const char *type,
187             const char *opts, struct mntentchn *mc) {
188         int umnt_err = 0;
189         int isroot;
190         int res;
191         int status;
192         const char *loopdev;
193         int myloop = 0;
194
195         /* Special case for root.  As of 0.99pl10 we can (almost) unmount root;
196            the kernel will remount it readonly so that we can carry on running
197            afterwards.  The readonly remount is illegal if any files are opened
198            for writing at the time, so we can't update mtab for an unmount of
199            root.  As it is only really a remount, this doesn't matter too
200            much.  [sct May 29, 1993] */
201         isroot = (streq (node, "/") || streq (node, "root")
202                   || streq (node, "rootfs"));
203         if (isroot)
204                 nomtab++;
205
206         /*
207          * Call umount.TYPE for types that require a separate umount program.
208          * All such special things must occur isolated in the types string.
209          */
210         if (check_special_umountprog(spec, node, type, &status))
211                 return status;
212
213         /*
214          * Ignore the option "-d" for non-loop devices and loop devices with
215          * LO_FLAGS_AUTOCLEAR flag.
216          */
217         if (delloop && is_loop_device(spec) && !is_loop_autoclear(spec))
218                 myloop = 1;
219
220         if (lazy) {
221                 res = umount2 (node, MNT_DETACH);
222                 if (res < 0)
223                         umnt_err = errno;
224                 goto writemtab;
225         }
226
227         if (force) {            /* only supported for NFS */
228                 res = umount2 (node, MNT_FORCE);
229                 if (res == -1) {
230                         int errsv = errno;
231                         perror("umount2");
232                         errno = errsv;
233                         if (errno == ENOSYS) {
234                                 if (verbose)
235                                         printf(_("no umount2, trying umount...\n"));
236                                 res = umount (node);
237                         }
238                 }
239         } else
240                 res = umount (node);
241
242         if (res < 0)
243                 umnt_err = errno;
244
245         if (res < 0 && remount && umnt_err == EBUSY) {
246                 /* Umount failed - let us try a remount */
247                 res = mount(spec, node, NULL,
248                             MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
249                 if (res == 0) {
250                         struct my_mntent remnt;
251                         fprintf(stderr,
252                                 _("umount: %s busy - remounted read-only\n"),
253                                 spec);
254                         remnt.mnt_type = remnt.mnt_fsname = NULL;
255                         remnt.mnt_dir = xstrdup(node);
256                         remnt.mnt_opts = xstrdup("ro");
257                         if (!nomtab)
258                                 update_mtab(node, &remnt);
259                         return 0;
260                 } else if (errno != EBUSY) {    /* hmm ... */
261                         perror("remount");
262                         fprintf(stderr,
263                                 _("umount: could not remount %s read-only\n"),
264                                 spec);
265                 }
266         }
267
268         loopdev = 0;
269         if (res >= 0) {
270                 /* Umount succeeded */
271                 if (verbose)
272                         printf (_("%s umounted\n"), spec);
273
274                 /* Free any loop devices that we allocated ourselves */
275                 if (mc) {
276                         char *optl;
277
278                         /* old style mtab line? */
279                         if (streq(mc->m.mnt_type, "loop")) {
280                                 loopdev = spec;
281                                 goto gotloop;
282                         }
283
284                         /* new style mtab line? */
285                         optl = mc->m.mnt_opts ? xstrdup(mc->m.mnt_opts) : "";
286                         for (optl = strtok (optl, ","); optl;
287                              optl = strtok (NULL, ",")) {
288                                 if (!strncmp(optl, "loop=", 5)) {
289                                         loopdev = optl+5;
290                                         goto gotloop;
291                                 }
292                         }
293                 } else {
294                         /*
295                          * If option "-o loop=spec" occurs in mtab,
296                          * note the mount point, and delete mtab line.
297                          */
298                         if ((mc = getmntoptfile (spec)) != NULL)
299                                 node = mc->m.mnt_dir;
300                 }
301
302                 /* Also free loop devices when -d flag is given */
303                 if (myloop)
304                         loopdev = spec;
305         }
306  gotloop:
307         if (loopdev)
308                 del_loop(loopdev);
309
310  writemtab:
311         if (!nomtab &&
312             (umnt_err == 0 || umnt_err == EINVAL || umnt_err == ENOENT)) {
313                 update_mtab (node, NULL);
314         }
315
316         if (res >= 0)
317                 return 0;
318         if (umnt_err)
319                 complain(umnt_err, node);
320         return 1;
321 }
322
323 /*
324  * umount_one_bw: unmount FILE that has last occurrence MC0
325  *
326  * Why this loop?
327  * 1. People who boot a system with a bad fstab root entry
328  *    will get an incorrect "/dev/foo on /" in mtab.
329  *    If later /dev/foo is actually mounted elsewhere,
330  *    it will occur twice in mtab.
331  * 2. With overmounting one can get the situation that
332  *    the same filename is used as mount point twice.
333  * In both cases, it is best to try the last occurrence first.
334  */
335 static int
336 umount_one_bw (const char *file, struct mntentchn *mc0) {
337         struct mntentchn *mc;
338         int res = 1;
339
340         mc = mc0;
341         while (res && mc) {
342                 res = umount_one(mc->m.mnt_fsname, mc->m.mnt_dir,
343                                  mc->m.mnt_type, mc->m.mnt_opts, mc);
344                 mc = getmntdirbackward(file, mc);
345         }
346         mc = mc0;
347         while (res && mc) {
348                 res = umount_one(mc->m.mnt_fsname, mc->m.mnt_dir,
349                                  mc->m.mnt_type, mc->m.mnt_opts, mc);
350                 mc = getmntdevbackward(file, mc);
351         }
352         return res;
353 }
354
355 /* Unmount all filesystems of type VFSTYPES found in mtab.  Since we are
356    concurrently updating mtab after every successful umount, we have to
357    slurp in the entire file before we start.  This isn't too bad, because
358    in any case it's important to umount mtab entries in reverse order
359    to mount, e.g. /usr/spool before /usr.  */
360 static int
361 umount_all (char *types, char *test_opts) {
362      struct mntentchn *mc, *hd;
363      int errors = 0;
364
365      hd = mtab_head();
366      if (!hd->prev)
367           die (2, _("umount: cannot find list of filesystems to unmount"));
368      for (mc = hd->prev; mc != hd; mc = mc->prev) {
369           if (matching_type (mc->m.mnt_type, types)
370               && matching_opts (mc->m.mnt_opts, test_opts)) {
371                errors |= umount_one (mc->m.mnt_fsname, mc->m.mnt_dir,
372                                      mc->m.mnt_type, mc->m.mnt_opts, mc);
373           }
374      }
375
376      sync ();
377      return errors;
378 }
379
380 static struct option longopts[] =
381 {
382   { "all", 0, 0, 'a' },
383   { "force", 0, 0, 'f' },
384   { "help", 0, 0, 'h' },
385   { "no-mtab", 0, 0, 'n' },
386   { "test-opts", 1, 0, 'O' },
387   { "verbose", 0, 0, 'v' },
388   { "version", 0, 0, 'V' },
389   { "read-only", 0, 0, 'r' },
390   { "types", 1, 0, 't' },
391   { NULL, 0, 0, 0 }
392 };
393
394 static void
395 usage (FILE *fp, int n)
396 {
397   fprintf (fp, _("Usage: umount -h | -V\n"
398                "       umount -a [-d] [-f] [-r] [-n] [-v] [-t vfstypes] [-O opts]\n"
399                "       umount [-d] [-f] [-r] [-n] [-v] special | node...\n"));
400   exit (n);
401 }
402
403 /*
404  * Look for an option in a comma-separated list
405  */
406 static int
407 contains(const char *list, const char *s) {
408         int n = strlen(s);
409
410         while (list && *list) {
411                 if (strncmp(list, s, n) == 0 &&
412                     (list[n] == 0 || list[n] == ','))
413                         return 1;
414                 while (*list && *list++ != ',') ;
415         }
416         return 0;
417 }
418
419 /*
420  * If list contains "user=peter" and we ask for "user=", return "peter"
421  */
422 static char *
423 get_value(const char *list, const char *s) {
424         const char *t;
425         int n = strlen(s);
426
427         while (list && *list) {
428                 if (strncmp(list, s, n) == 0) {
429                         s = t = list+n;
430                         while (*s && *s != ',')
431                                 s++;
432                         return xstrndup(t, s-t);
433                 }
434                 while (*list && *list++ != ',') ;
435         }
436         return NULL;
437 }
438
439 /* check if @mc contains a loop device which is associated
440  * with the @file in fs
441  */
442 static int
443 is_valid_loop(struct mntentchn *mc, struct mntentchn *fs)
444 {
445         unsigned long long offset = 0;
446         char *p;
447
448         /* check if it begins with /dev/loop */
449         if (strncmp(mc->m.mnt_fsname, _PATH_DEV_LOOP,
450                                 sizeof(_PATH_DEV_LOOP) - 1))
451                 return 0;
452
453         /* check for loop option in fstab */
454         if (!contains(fs->m.mnt_opts, "loop"))
455                 return 0;
456
457         /* check for offset option in fstab */
458         p = get_value(fs->m.mnt_opts, "offset=");
459         if (p)
460                 offset = strtoull(p, NULL, 10);
461
462         /* check association */
463         if (loopfile_used_with((char *) mc->m.mnt_fsname,
464                                 fs->m.mnt_fsname, offset) == 1) {
465                 if (verbose > 1)
466                         printf(_("device %s is associated with %s\n"),
467                                mc->m.mnt_fsname, fs->m.mnt_fsname);
468                 return 1;
469         }
470
471         if (verbose > 1)
472                 printf(_("device %s is not associated with %s\n"),
473                        mc->m.mnt_fsname, fs->m.mnt_fsname);
474         return 0;
475 }
476
477 static int
478 umount_file (char *arg) {
479         struct mntentchn *mc, *fs;
480         const char *file, *options;
481         int fstab_has_user, fstab_has_users, fstab_has_owner, fstab_has_group;
482         int ok;
483
484         if (!*arg) {            /* "" would be expanded to `pwd` */
485                 die(2, _("Cannot umount \"\"\n"));
486                 return 0;
487         }
488
489         file = canonicalize(arg); /* mtab paths are canonicalized */
490         if (verbose > 1)
491                 printf(_("Trying to umount %s\n"), file);
492
493         mc = getmntdirbackward(file, NULL);
494         if (!mc) {
495                 mc = getmntdevbackward(file, NULL);
496                 if (mc) {
497                         struct mntentchn *mc1;
498
499                         mc1 = getmntdirbackward(mc->m.mnt_dir, NULL);
500                         if (!mc1)
501                                 /* 'mc1' must exist, though not necessarily
502                                     equals to `mc'. Otherwise we go mad. */
503                                 die(EX_SOFTWARE,
504                                     _("umount: confused when analyzing mtab"));
505
506                         if (strcmp(file, mc1->m.mnt_fsname)) {
507                                 /* Something was stacked over `file' on the
508                                    same mount point. */
509                                 die(EX_FAIL, _("umount: cannot umount %s -- %s is "
510                                     "mounted over it on the same point."),
511                                     file, mc1->m.mnt_fsname);
512                         }
513                 }
514         }
515         if (!mc && verbose)
516                 printf(_("Could not find %s in mtab\n"), file);
517
518         if (restricted) {
519                 char *mtab_user = NULL;
520
521                 if (!mc)
522                         die(2,
523                             _("umount: %s is not mounted (according to mtab)"),
524                             file);
525                 /*
526                  * uhelper - unprivileged umount helper
527                  * -- external umount (for example HAL mounts)
528                  */
529                 if (external_allowed) {
530                         char *uhelper = NULL;
531
532                         if (mc->m.mnt_opts)
533                                 uhelper = get_value(mc->m.mnt_opts, "uhelper=");
534                         if (uhelper) {
535                                 int status = 0;
536                                 if (check_special_umountprog(arg, arg,
537                                                         uhelper, &status))
538                                         return status;
539                         }
540                 }
541
542                 /* The 2.4 kernel will generally refuse to mount the same
543                    filesystem on the same mount point, but will accept NFS.
544                    So, unmounting must be possible. */
545                 if (!is_mounted_once(file) && strcmp(mc->m.mnt_type,"nfs"))
546                         die(2,
547                             _("umount: it seems %s is mounted multiple times"),
548                             file);
549
550                 /* If fstab contains the two lines
551                    /dev/sda1 /mnt/zip auto user,noauto  0 0
552                    /dev/sda4 /mnt/zip auto user,noauto  0 0
553                    then "mount /dev/sda4" followed by "umount /mnt/zip"
554                    used to fail. So, we must not look for file, but for
555                    the pair (dev,file) in fstab. */
556                 fs = getfs_by_devdir(mc->m.mnt_fsname, mc->m.mnt_dir);
557                 if (!fs) {
558                         fs = getfs_by_dir(file);
559                         if (!fs && !getfs_by_spec(file))
560                                 die (2,
561                                      _("umount: %s is not in the fstab "
562                                        "(and you are not root)"),
563                                      file);
564
565                         /* spec could be a file which is loop mounted */
566                         if (fs && !is_valid_loop(mc, fs))
567                                 die (2, _("umount: %s mount disagrees with "
568                                           "the fstab"), file);
569                 }
570
571                 /*
572                  * User mounting and unmounting is allowed only
573                  * if fstab contains one of the options `user',
574                  * `users' or `owner' or `group'.
575                  *
576                  * The option `users' allows arbitrary users to mount
577                  * and unmount - this may be a security risk.
578                  *
579                  * The options `user', `owner' and `group' only allow
580                  * unmounting by the user that mounted (visible in mtab).
581                  */
582
583                 options = fs->m.mnt_opts;
584                 if (!options)
585                         options = "";
586                 fstab_has_user = contains(options, "user");
587                 fstab_has_users = contains(options, "users");
588                 fstab_has_owner = contains(options, "owner");
589                 fstab_has_group = contains(options, "group");
590                 ok = 0;
591
592                 if (fstab_has_users)
593                         ok = 1;
594
595                 if (!ok && (fstab_has_user || fstab_has_owner ||
596                             fstab_has_group)) {
597                         char *user = getusername();
598
599                         options = mc->m.mnt_opts;
600                         if (!options)
601                                 options = "";
602                         mtab_user = get_value(options, "user=");
603
604                         if (user && mtab_user && streq (user, mtab_user))
605                                 ok = 1;
606                 }
607                 if (!ok)
608                         die (2, _("umount: only %s can unmount %s from %s"),
609                              mtab_user ? mtab_user : "root",
610                              fs->m.mnt_fsname, fs->m.mnt_dir);
611         }
612
613         if (mc)
614                 return umount_one_bw (file, mc);
615         else
616                 return umount_one (arg, arg, arg, arg, NULL);
617 }
618
619 int
620 main (int argc, char *argv[]) {
621         int c;
622         int all = 0;
623         char *types = NULL, *test_opts = NULL, *p;
624         int result = 0;
625
626         sanitize_env();
627         setlocale(LC_ALL, "");
628         bindtextdomain(PACKAGE, LOCALEDIR);
629         textdomain(PACKAGE);
630
631         progname = argv[0];
632         if ((p = strrchr(progname, '/')) != NULL)
633                 progname = p+1;
634
635         umask(022);
636
637         while ((c = getopt_long (argc, argv, "adfhlnrit:O:vV",
638                                  longopts, NULL)) != -1)
639                 switch (c) {
640                 case 'a':               /* umount everything */
641                         ++all;
642                         break;
643                         /* fall through? */
644                 case 'd':               /* do losetup -d for unmounted loop devices */
645                         ++delloop;
646                         break;
647                 case 'f':               /* force umount */
648                         ++force;
649                         break;
650                 case 'h':               /* help */
651                         usage (stdout, 0);
652                         break;
653                 case 'l':               /* lazy umount */
654                         ++lazy;
655                         break;
656                 case 'n':               /* do not write in /etc/mtab */
657                         ++nomtab;
658                         break;
659                 case 'O':               /* specify file system options */
660                         test_opts = optarg;
661                         break;
662                 case 'r':               /* remount read-only if umount fails */
663                         ++remount;
664                         break;
665                 case 'v':               /* make noise */
666                         ++verbose;
667                         break;
668                 case 'V':               /* version */
669                         printf ("umount (%s)\n", PACKAGE_STRING);
670                         exit (0);
671                 case 't':               /* specify file system type */
672                         types = optarg;
673                         break;
674                 case 'i':
675                         external_allowed = 0;
676                         break;
677                 case 0:
678                         break;
679                 case '?':
680                 default:
681                         usage (stderr, 1);
682                 }
683
684         {
685                 const uid_t ruid = getuid();
686                 const uid_t euid = geteuid();
687
688                 /* if we're really root and aren't running setuid */
689                 if (((uid_t)0 == ruid) && (ruid == euid)) {
690                         restricted = 0;
691                 }
692         }
693
694         if (restricted && (all || types || nomtab || force || remount)) {
695                 die (2, _("umount: only root can do that"));
696         }
697
698         argc -= optind;
699         argv += optind;
700
701         atexit(unlock_mtab);
702
703         if (all) {
704                 /* nodev stuff: sysfs, usbfs, oprofilefs, ... */
705                 if (types == NULL)
706                         types = "noproc,nodevfs,nodevpts,nosysfs,norpc_pipefs,nonfsd";
707                 result = umount_all (types, test_opts);
708         } else if (argc < 1) {
709                 usage (stderr, 2);
710         } else while (argc--) {
711                 result += umount_file(*argv++);
712         }
713         exit (result);          /* nonzero on at least one failure */
714 }