]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libmount/samples/umount.c
libmount: add new exprimental umount(8)
[thirdparty/util-linux.git] / libmount / samples / umount.c
CommitLineData
db216e68
KZ
1/*
2 * umount(8) -- mount a filesystem
3 *
4 * Copyright (C) 2011 Red Hat, Inc. All rights reserved.
5 * Written by Karel Zak <kzak@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it would be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software Foundation,
19 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <errno.h>
25#include <string.h>
26#include <getopt.h>
27#include <unistd.h>
28#include <sys/types.h>
29
30#include <libmount.h>
31
32#include "nls.h"
33#include "c.h"
34#include "env.h"
35#include "optutils.h"
36
37static int table_parser_errcb(struct libmnt_table *tb __attribute__((__unused__)),
38 const char *filename, int line)
39{
40 if (filename)
41 warnx(_("%s: parse error: ignore entry at line %d."),
42 filename, line);
43 return 0;
44}
45
46static void __attribute__((__noreturn__)) print_version(void)
47{
48 const char *ver = NULL;
49
50 mnt_get_library_version(&ver);
51
52 printf(_("%s from %s (libmount %s)\n"),
53 program_invocation_short_name, PACKAGE_STRING, ver);
54 exit(EXIT_SUCCESS);
55}
56
57static void __attribute__((__noreturn__)) usage(FILE *out)
58{
59 fputs(USAGE_HEADER, out);
60 fprintf(out, _(
61 " %1$s [-hV]\n"
62 " %1$s -a [options]\n"
63 " %1$s [options] <source> | <directory>\n"),
64 program_invocation_short_name);
65
66 fputs(USAGE_OPTIONS, out);
67 fprintf(out, _(
68 " -a, --all mount all filesystems mentioned in fstab\n"
69 " -c, --no-canonicalize don't canonicalize paths\n"
70 " -d, --detach-loop if mounted loop device, also free this loop device\n"
71 " --fake dry run; skip the umount(2) syscall\n"
72 " -f, --force force unmount (in case of an unreachable NFS system)\n"));
73 fprintf(out, _(
74 " -i, --internal-only don't call the umount.<type> helpers\n"
75 " -n, --no-mtab don't write to /etc/mtab\n"
76 " -l, --lazy detach the filesystem now, and cleanup all later\n"));
77 fprintf(out, _(
78 " -O, --test-opts <list> limit the set of filesystems (use with -a)\n"
79 " -r, --read-only In case unmounting fails, try to remount read-only\n"
80 " -t, --types <list> limit the set of filesystem types\n"
81 " -v, --verbose say what is being done\n"));
82
83 fputs(USAGE_SEPARATOR, out);
84 fputs(USAGE_HELP, out);
85 fputs(USAGE_VERSION, out);
86 fprintf(out, USAGE_MAN_TAIL("umount(8)"));
87
88 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
89}
90
91static void __attribute__((__noreturn__)) exit_non_root(const char *option)
92{
93 const uid_t ruid = getuid();
94 const uid_t euid = geteuid();
95
96 if (ruid == 0 && euid != 0) {
97 /* user is root, but setuid to non-root */
98 if (option)
99 errx(EXIT_FAILURE,
100 _("only root can use \"--%s\" option "
101 "(effective UID is %u)"),
102 option, euid);
103 errx(EXIT_FAILURE, _("only root can do that "
104 "(effective UID is %u)"), euid);
105 }
106 if (option)
107 errx(EXIT_FAILURE, _("only root can use \"--%s\" option"), option);
108 errx(EXIT_FAILURE, _("only root can do that"));
109}
110
111static int umount_all(struct libmnt_context *cxt __attribute__((__unused__)))
112{
113 return -1; /* TODO */
114}
115
116static int umount_one(struct libmnt_context *cxt, const char *spec)
117{
118 int rc;
119
120 if (!spec)
121 return -EINVAL;
122
123 if (mnt_context_set_target(cxt, spec))
124 err(EXIT_FAILURE, _("failed to set umount target"));
125
126 rc = mnt_context_umount(cxt);
127 if (rc)
128 /* TODO mnt_context_strerror() */
129 warnx(_("%s: umount failed"), spec);
130
131 mnt_reset_context(cxt);
132 return rc;
133}
134
135int main(int argc, char **argv)
136{
137 int c, rc, all = 0;
138 struct libmnt_context *cxt;
139 char *types = NULL;
140
141 enum {
142 UMOUNT_OPT_FAKE = CHAR_MAX + 1,
143 };
144
145 static const struct option longopts[] = {
146 { "all", 0, 0, 'a' },
147 { "detach-loop", 0, 0, 'd' },
148 { "fake", 0, 0, UMOUNT_OPT_FAKE },
149 { "force", 0, 0, 'f' },
150 { "help", 0, 0, 'h' },
151 { "internal-only", 0, 0, 'i' },
152 { "lazy", 0, 0, 'l' },
153 { "no-canonicalize", 0, 0, 'c' },
154 { "no-mtab", 0, 0, 'n' },
155 { "read-only", 0, 0, 'r' },
156 { "test-opts", 1, 0, 'O' },
157 { "types", 1, 0, 't' },
158 { "verbose", 0, 0, 'v' },
159 { "version", 0, 0, 'V' },
160 { NULL, 0, 0, 0 }
161 };
162
163 sanitize_env();
164 setlocale(LC_ALL, "");
165 bindtextdomain(PACKAGE, LOCALEDIR);
166 textdomain(PACKAGE);
167
168 mnt_init_debug(0);
169 cxt = mnt_new_context();
170 if (!cxt)
171 err(EXIT_FAILURE, _("libmount context allocation failed"));
172
173 mnt_context_set_tables_errcb(cxt, table_parser_errcb);
174
175 while ((c = getopt_long(argc, argv, "acdfhilnrO:t:vV",
176 longopts, NULL)) != -1) {
177
178
179 /* only few options are allowed for non-root users */
180 if (mnt_context_is_restricted(cxt) && !strchr("hdilVv", c))
181 exit_non_root(option_to_longopt(c, longopts));
182
183 switch(c) {
184 case 'a':
185 all = 1;
186 break;
187 case 'c':
188 mnt_context_disable_canonicalize(cxt, TRUE);
189 break;
190 case 'd':
191 mnt_context_enable_loopdel(cxt, TRUE);
192 break;
193 case UMOUNT_OPT_FAKE:
194 mnt_context_enable_fake(cxt, TRUE);
195 break;
196 case 'f':
197 mnt_context_enable_force(cxt, TRUE);
198 break;
199 case 'h':
200 usage(stdout);
201 break;
202 case 'i':
203 mnt_context_disable_helpers(cxt, TRUE);
204 break;
205 case 'l':
206 mnt_context_enable_lazy(cxt, TRUE);
207 break;
208 case 'n':
209 mnt_context_disable_mtab(cxt, TRUE);
210 break;
211 case 'r':
212 mnt_context_enable_rdonly_umount(cxt, TRUE);
213 break;
214 case 'O':
215 if (mnt_context_set_options_pattern(cxt, optarg))
216 err(EXIT_FAILURE, _("failed to set options pattern"));
217 break;
218 case 't':
219 types = optarg;
220 break;
221 case 'v':
222 mnt_context_enable_verbose(cxt, TRUE);
223 break;
224 case 'V':
225 print_version();
226 break;
227 default:
228 usage(stderr);
229 break;
230 }
231 }
232
233 argc -= optind;
234 argv += optind;
235
236 if (all) {
237 if (!types)
238 types = "noproc,nodevfs,nodevpts,nosysfs,norpc_pipefs,nonfsd";
239
240 mnt_context_set_fstype_pattern(cxt, types);
241 rc = umount_all(cxt);
242
243 } else if (argc < 1) {
244 usage(stderr);
245
246 } else while (argc--) {
247 rc += umount_one(cxt, *argv++);
248 }
249
250 mnt_free_context(cxt);
251 return rc ? EXIT_FAILURE : EXIT_SUCCESS;
252}
253