master xplshn/aruu / cmd / linux / umount.c
  1/* See LICENSE file for copyright and license details. */
  2
  3#include <sys/mount.h>
  4
  5#include <mntent.h>
  6#include <stdio.h>
  7#include <stdlib.h>
  8#include <string.h>
  9
 10#include "paths.h"
 11#include "util.h"
 12
 13#if FEATURE_UMOUNT_OPTIONS
 14static int
 15fsopt_matches(const char *opts_list, const char *opt, size_t optlen)
 16{
 17  int match = 1;
 18
 19  if (optlen >= 2 && opt[0] == 'n' && opt[1] == 'o') {
 20    match--;
 21    opt += 2;
 22    optlen -= 2;
 23  }
 24
 25  if (optlen == 0)
 26    return 0;
 27
 28  if (match && optlen > 1 && *opt == '+') {
 29    opt++;
 30    optlen--;
 31  }
 32
 33  while (1) {
 34    if (strncmp(opts_list, opt, optlen) == 0) {
 35      const char *after_opt = opts_list + optlen;
 36      if (*after_opt == '\0' || *after_opt == ',')
 37        return match;
 38    }
 39
 40    opts_list = strchr(opts_list, ',');
 41    if (!opts_list)
 42      break;
 43    opts_list++;
 44  }
 45
 46  return !match;
 47}
 48
 49static int
 50fsopts_matches(const char *opts_list, const char *reqopts_list)
 51{
 52  const char *comma;
 53  size_t      len;
 54
 55  if (!reqopts_list)
 56    return 1;
 57
 58  while (1) {
 59    comma = strchr(reqopts_list, ',');
 60    if (!comma)
 61      len = strlen(reqopts_list);
 62    else
 63      len = comma - reqopts_list;
 64
 65    if (len && !fsopt_matches(opts_list, reqopts_list, len))
 66      return 0;
 67
 68    if (!comma)
 69      break;
 70    reqopts_list = ++comma;
 71  }
 72
 73  return 1;
 74}
 75#endif
 76
 77static int
 78umountall(
 79    int flags
 80#if FEATURE_UMOUNT_OPTIONS
 81    ,
 82    const char *oflag
 83#endif
 84)
 85{
 86  FILE          *fp;
 87  struct mntent *me;
 88  int            ret     = 0;
 89  char         **mntdirs = NULL;
 90  int            len     = 0;
 91
 92  fp = setmntent(ARUU_LINUX_PATH_PROC_MOUNTS, "r");
 93  if (!fp)
 94    eprintf("setmntent %s:", ARUU_LINUX_PATH_PROC_MOUNTS);
 95  while ((me = getmntent(fp))) {
 96    if (strcmp(me->mnt_type, "proc") == 0)
 97      continue;
 98#if FEATURE_UMOUNT_OPTIONS
 99    if (oflag && !fsopts_matches(me->mnt_opts, oflag))
100      continue;
101#endif
102    mntdirs          = erealloc(mntdirs, ++len * sizeof(*mntdirs));
103    mntdirs[len - 1] = estrdup(me->mnt_dir);
104  }
105  endmntent(fp);
106  while (--len >= 0) {
107    if (umount2(mntdirs[len], flags) < 0) {
108      weprintf("umount2 %s:", mntdirs[len]);
109      ret = 1;
110    }
111    free(mntdirs[len]);
112  }
113  free(mntdirs);
114  return ret;
115}
116
117static void
118usage(void)
119{
120#if FEATURE_UMOUNT_OPTIONS
121  weprintf("usage: %s [-lfn] [-O options] target...\n", argv0);
122  weprintf("usage: %s -a [-lfn] [-O options]\n", argv0);
123#else
124  weprintf("usage: %s [-lfn] target...\n", argv0);
125  weprintf("usage: %s -a [-lfn]\n", argv0);
126#endif
127  exit(1);
128}
129
130// ?man umount: unmount filesystems
131// ?man arguments: target...
132// ?man unmount a filesystem from the directory tree
133int
134main(int argc, char *argv[])
135{
136  int i;
137  int aflag = 0;
138  int flags = 0;
139  int ret   = 0;
140#if FEATURE_UMOUNT_OPTIONS
141  char *oflag = NULL;
142#endif
143
144  ARGBEGIN
145  {
146    // ?man -a: print or show all entries
147    case 'a':
148      aflag = 1;
149      break;
150    // ?man -f: force the operation
151    case 'f':
152      flags |= MNT_FORCE;
153      break;
154    // ?man -l: list in long format
155    case 'l':
156      flags |= MNT_DETACH;
157      break;
158    // ?man -n: print line numbers or counts
159    case 'n':
160      break;
161#if FEATURE_UMOUNT_OPTIONS
162    // ?man -O:str: specify option flag
163    case 'O':
164      oflag = EARGF(usage());
165      break;
166#endif
167    default:
168      usage();
169  }
170  ARGEND;
171
172  if (argc < 1 && aflag == 0)
173    usage();
174
175#if FEATURE_UMOUNT_OPTIONS
176  if (oflag && aflag == 0)
177    usage();
178#endif
179
180  if (aflag == 1)
181    return umountall(
182        flags
183#if FEATURE_UMOUNT_OPTIONS
184        ,
185        oflag
186#endif
187    );
188
189  for (i = 0; i < argc; i++) {
190    if (umount2(argv[i], flags) < 0) {
191      weprintf("umount2 %s:", argv[i]);
192      ret = 1;
193    }
194  }
195  return ret;
196}