master xplshn/aruu / cmd / linux / umount.c
  1/* See LICENSE file for copyright and license details. */
  2
  3
  4#include <sys/mount.h>
  5
  6#include <mntent.h>
  7#include <stdio.h>
  8#include <stdlib.h>
  9#include <string.h>
 10
 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(int flags
 79#if FEATURE_UMOUNT_OPTIONS
 80          , const char *oflag
 81#endif
 82)
 83{
 84	FILE *fp;
 85	struct mntent *me;
 86	int ret = 0;
 87	char **mntdirs = NULL;
 88	int len = 0;
 89
 90	fp = setmntent("/proc/mounts", "r");
 91	if (!fp)
 92		eprintf("setmntent %s:", "/proc/mounts");
 93	while ((me = getmntent(fp))) {
 94		if (strcmp(me->mnt_type, "proc") == 0)
 95			continue;
 96#if FEATURE_UMOUNT_OPTIONS
 97		if (oflag && !fsopts_matches(me->mnt_opts, oflag))
 98			continue;
 99#endif
100		mntdirs = erealloc(mntdirs, ++len * sizeof(*mntdirs));
101		mntdirs[len - 1] = estrdup(me->mnt_dir);
102	}
103	endmntent(fp);
104	while (--len >= 0) {
105		if (umount2(mntdirs[len], flags) < 0) {
106			weprintf("umount2 %s:", mntdirs[len]);
107			ret = 1;
108		}
109		free(mntdirs[len]);
110	}
111	free(mntdirs);
112	return ret;
113}
114
115static void
116usage(void)
117{
118#if FEATURE_UMOUNT_OPTIONS
119	weprintf("usage: %s [-lfn] [-O options] target...\n", argv0);
120	weprintf("usage: %s -a [-lfn] [-O options]\n", argv0);
121#else
122	weprintf("usage: %s [-lfn] target...\n", argv0);
123	weprintf("usage: %s -a [-lfn]\n", argv0);
124#endif
125	exit(1);
126}
127
128// ?man umount: unmount filesystems
129// ?man arguments: target...
130// ?man unmount a filesystem from the directory tree
131int
132main(int argc, char *argv[])
133{
134	int i;
135	int aflag = 0;
136	int flags = 0;
137	int ret = 0;
138#if FEATURE_UMOUNT_OPTIONS
139	char *oflag = NULL;
140#endif
141
142	ARGBEGIN {
143	// ?man -a: print or show all entries
144	case 'a':
145		aflag = 1;
146		break;
147	// ?man -f: force the operation
148	case 'f':
149		flags |= MNT_FORCE;
150		break;
151	// ?man -l: list in long format
152	case 'l':
153		flags |= MNT_DETACH;
154		break;
155	// ?man -n: print line numbers or counts
156	case 'n':
157		break;
158#if FEATURE_UMOUNT_OPTIONS
159	// ?man -O:str: specify option flag
160	case 'O':
161		oflag = EARGF(usage());
162		break;
163#endif
164	default:
165		usage();
166	} ARGEND;
167
168	if (argc < 1 && aflag == 0)
169		usage();
170
171#if FEATURE_UMOUNT_OPTIONS
172	if (oflag && aflag == 0)
173		usage();
174#endif
175
176	if (aflag == 1)
177		return umountall(flags
178#if FEATURE_UMOUNT_OPTIONS
179		                 , oflag
180#endif
181		);
182
183	for (i = 0; i < argc; i++) {
184		if (umount2(argv[i], flags) < 0) {
185			weprintf("umount2 %s:", argv[i]);
186			ret = 1;
187		}
188	}
189	return ret;
190}