]>
Commit | Line | Data |
---|---|---|
04fd7a9f KZ |
1 | /* |
2 | * findmnt(8) | |
3 | * | |
68164f6c | 4 | * Copyright (C) 2010,2011 Red Hat, Inc. All rights reserved. |
04fd7a9f KZ |
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 | * | |
7cebf0bb SK |
17 | * You should have received a copy of the GNU General Public License along |
18 | * with this program; if not, write to the Free Software Foundation, Inc., | |
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
04fd7a9f | 20 | */ |
04fd7a9f KZ |
21 | #include <stdio.h> |
22 | #include <stdlib.h> | |
23 | #include <errno.h> | |
04fd7a9f KZ |
24 | #include <unistd.h> |
25 | #include <getopt.h> | |
26 | #include <string.h> | |
9d67679b | 27 | #include <termios.h> |
9d67679b KZ |
28 | #ifdef HAVE_SYS_IOCTL_H |
29 | #include <sys/ioctl.h> | |
30 | #endif | |
9d67679b | 31 | #include <assert.h> |
32e5466a | 32 | #include <poll.h> |
a85ef33b DR |
33 | #include <sys/statvfs.h> |
34 | #include <sys/types.h> | |
9d67679b | 35 | |
2a1f429a | 36 | #include <libmount.h> |
fdedb45e | 37 | |
04fd7a9f KZ |
38 | #include "pathnames.h" |
39 | #include "nls.h" | |
9d67679b | 40 | #include "c.h" |
fdedb45e | 41 | #include "tt.h" |
ad38fb9f | 42 | #include "strutils.h" |
6f312c89 | 43 | #include "xalloc.h" |
04fd7a9f | 44 | |
9d67679b KZ |
45 | /* flags */ |
46 | enum { | |
47 | FL_EVALUATE = (1 << 1), | |
48 | FL_CANONICALIZE = (1 << 2), | |
49 | FL_FIRSTONLY = (1 << 3), | |
50 | FL_INVERT = (1 << 4), | |
9d67679b | 51 | FL_NOSWAPMATCH = (1 << 6), |
b2214e1f | 52 | FL_NOFSROOT = (1 << 7), |
049caefd | 53 | FL_SUBMOUNTS = (1 << 8), |
32e5466a | 54 | FL_POLL = (1 << 9) |
9d67679b KZ |
55 | }; |
56 | ||
57 | /* column IDs */ | |
04fd7a9f KZ |
58 | enum { |
59 | COL_SOURCE, | |
60 | COL_TARGET, | |
61 | COL_FSTYPE, | |
62 | COL_OPTIONS, | |
631280e0 KZ |
63 | COL_VFS_OPTIONS, |
64 | COL_FS_OPTIONS, | |
04fd7a9f KZ |
65 | COL_LABEL, |
66 | COL_UUID, | |
46236388 | 67 | COL_MAJMIN, |
32e5466a KZ |
68 | COL_ACTION, |
69 | COL_OLD_TARGET, | |
70 | COL_OLD_OPTIONS, | |
a85ef33b DR |
71 | COL_SIZE, |
72 | COL_AVAIL, | |
73 | COL_USED, | |
74 | COL_USEPERC, | |
04fd7a9f | 75 | |
af0dc7d3 | 76 | FINDMNT_NCOLUMNS |
04fd7a9f KZ |
77 | }; |
78 | ||
8c5eba3e KZ |
79 | enum { |
80 | TABTYPE_FSTAB = 1, | |
81 | TABTYPE_MTAB, | |
82 | TABTYPE_KERNEL | |
83 | }; | |
84 | ||
9d67679b KZ |
85 | /* column names */ |
86 | struct colinfo { | |
87 | const char *name; /* header */ | |
88 | double whint; /* width hint (N < 1 is in percent of termwidth) */ | |
32e5466a | 89 | int flags; /* tt flags */ |
b152e359 | 90 | const char *help; /* column description */ |
9d67679b | 91 | const char *match; /* pattern for match_func() */ |
04fd7a9f KZ |
92 | }; |
93 | ||
af0dc7d3 KZ |
94 | /* columns descriptions (don't use const, this is writable) */ |
95 | static struct colinfo infos[FINDMNT_NCOLUMNS] = { | |
7aa69cf2 KZ |
96 | [COL_SOURCE] = { "SOURCE", 0.25, TT_FL_NOEXTREMES, N_("source device") }, |
97 | [COL_TARGET] = { "TARGET", 0.30, TT_FL_TREE | TT_FL_NOEXTREMES, N_("mountpoint") }, | |
b152e359 KZ |
98 | [COL_FSTYPE] = { "FSTYPE", 0.10, TT_FL_TRUNC, N_("filesystem type") }, |
99 | [COL_OPTIONS] = { "OPTIONS", 0.10, TT_FL_TRUNC, N_("all mount options") }, | |
100 | [COL_VFS_OPTIONS] = { "VFS-OPTIONS", 0.20, TT_FL_TRUNC, N_("VFS specific mount options") }, | |
101 | [COL_FS_OPTIONS] = { "FS-OPTIONS", 0.10, TT_FL_TRUNC, N_("FS specific mount options") }, | |
102 | [COL_LABEL] = { "LABEL", 0.10, 0, N_("filesystem label") }, | |
103 | [COL_UUID] = { "UUID", 36, 0, N_("filesystem UUID") }, | |
104 | [COL_MAJMIN] = { "MAJ:MIN", 6, 0, N_("major:minor device number") }, | |
105 | [COL_ACTION] = { "ACTION", 10, TT_FL_STRICTWIDTH, N_("action detected by --poll") }, | |
106 | [COL_OLD_OPTIONS] = { "OLD-OPTIONS", 0.10, TT_FL_TRUNC, N_("old mount options saved by --poll") }, | |
107 | [COL_OLD_TARGET] = { "OLD-TARGET", 0.30, 0, N_("old mountpoint saved by --poll") }, | |
a85ef33b DR |
108 | [COL_SIZE] = { "SIZE", 8, TT_FL_RIGHT, N_("filesystem size") }, |
109 | [COL_AVAIL] = { "AVAIL", 8, TT_FL_RIGHT, N_("filesystem size available") }, | |
110 | [COL_USED] = { "USED", 8, TT_FL_RIGHT, N_("filesystem size used") }, | |
111 | [COL_USEPERC] = { "USE%", 8, TT_FL_RIGHT, N_("filesystem use percentage") }, | |
04fd7a9f KZ |
112 | }; |
113 | ||
9d67679b | 114 | /* global flags */ |
af0dc7d3 KZ |
115 | static int flags; |
116 | static int tt_flags; | |
9d67679b | 117 | |
fdedb45e | 118 | /* array with IDs of enabled columns */ |
af0dc7d3 KZ |
119 | static int columns[FINDMNT_NCOLUMNS]; |
120 | static int ncolumns; | |
9d67679b | 121 | |
582a5006 | 122 | /* poll actions (parsed --poll=<list> */ |
af0dc7d3 KZ |
123 | #define FINDMNT_NACTIONS 4 /* mount, umount, move, remount */ |
124 | static int actions[FINDMNT_NACTIONS]; | |
125 | static int nactions; | |
582a5006 | 126 | |
9d67679b | 127 | /* libmount cache */ |
af0dc7d3 | 128 | static struct libmnt_cache *cache; |
04fd7a9f | 129 | |
00b4bcdf | 130 | static int get_column_id(int num) |
9d67679b | 131 | { |
9d67679b | 132 | assert(num < ncolumns); |
af0dc7d3 | 133 | assert(columns[num] < FINDMNT_NCOLUMNS); |
fdedb45e | 134 | return columns[num]; |
9d67679b KZ |
135 | } |
136 | ||
00b4bcdf | 137 | static struct colinfo *get_column_info(int num) |
9d67679b KZ |
138 | { |
139 | return &infos[ get_column_id(num) ]; | |
140 | } | |
141 | ||
00b4bcdf | 142 | static const char *column_id_to_name(int id) |
9d67679b | 143 | { |
af0dc7d3 | 144 | assert(id < FINDMNT_NCOLUMNS); |
9d67679b KZ |
145 | return infos[id].name; |
146 | } | |
147 | ||
00b4bcdf | 148 | static const char *get_column_name(int num) |
9d67679b | 149 | { |
fdedb45e | 150 | return get_column_info(num)->name; |
9d67679b KZ |
151 | } |
152 | ||
00b4bcdf | 153 | static float get_column_whint(int num) |
9d67679b | 154 | { |
fdedb45e | 155 | return get_column_info(num)->whint; |
9d67679b KZ |
156 | } |
157 | ||
32e5466a | 158 | static int get_column_flags(int num) |
9d67679b | 159 | { |
32e5466a | 160 | return get_column_info(num)->flags; |
9d67679b KZ |
161 | } |
162 | ||
00b4bcdf | 163 | static const char *get_match(int id) |
9d67679b | 164 | { |
af0dc7d3 | 165 | assert(id < FINDMNT_NCOLUMNS); |
9d67679b KZ |
166 | return infos[id].match; |
167 | } | |
168 | ||
00b4bcdf | 169 | static void set_match(int id, const char *match) |
9d67679b | 170 | { |
af0dc7d3 | 171 | assert(id < FINDMNT_NCOLUMNS); |
9d67679b KZ |
172 | infos[id].match = match; |
173 | } | |
174 | ||
32e5466a KZ |
175 | static int is_tabdiff_column(int id) |
176 | { | |
af0dc7d3 | 177 | assert(id < FINDMNT_NCOLUMNS); |
32e5466a KZ |
178 | |
179 | switch(id) { | |
180 | case COL_ACTION: | |
181 | case COL_OLD_TARGET: | |
182 | case COL_OLD_OPTIONS: | |
183 | return 1; | |
184 | default: | |
185 | break; | |
186 | } | |
187 | return 0; | |
188 | } | |
189 | ||
9d67679b KZ |
190 | /* |
191 | * "findmnt" without any filter | |
192 | */ | |
00b4bcdf | 193 | static int is_listall_mode(void) |
9d67679b KZ |
194 | { |
195 | return (!get_match(COL_SOURCE) && | |
196 | !get_match(COL_TARGET) && | |
197 | !get_match(COL_FSTYPE) && | |
198 | !get_match(COL_OPTIONS)); | |
199 | } | |
200 | ||
582a5006 KZ |
201 | /* |
202 | * Returns 1 if the @act is in the --poll=<list> | |
203 | */ | |
204 | static int has_poll_action(int act) | |
205 | { | |
206 | int i; | |
207 | ||
208 | if (!nactions) | |
209 | return 1; /* all actions enabled */ | |
210 | for (i = 0; i < nactions; i++) | |
211 | if (actions[i] == act) | |
212 | return 1; | |
213 | return 0; | |
214 | } | |
215 | ||
216 | static int poll_action_name_to_id(const char *name, size_t namesz) | |
217 | { | |
218 | int id = -1; | |
219 | ||
220 | if (strncasecmp(name, "move", namesz) == 0 && namesz == 4) | |
221 | id = MNT_TABDIFF_MOVE; | |
222 | else if (strncasecmp(name, "mount", namesz) == 0 && namesz == 5) | |
223 | id = MNT_TABDIFF_MOUNT; | |
224 | else if (strncasecmp(name, "umount", namesz) == 0 && namesz == 6) | |
225 | id = MNT_TABDIFF_UMOUNT; | |
226 | else if (strncasecmp(name, "remount", namesz) == 0 && namesz == 7) | |
227 | id = MNT_TABDIFF_REMOUNT; | |
228 | else | |
229 | warnx(_("unknown action: %s"), name); | |
230 | ||
231 | return id; | |
232 | } | |
233 | ||
9d67679b KZ |
234 | /* |
235 | * findmnt --first-only <devname|TAG=|mountpoint> | |
236 | * | |
237 | * ... it works like "mount <devname|TAG=|mountpoint>" | |
238 | */ | |
00b4bcdf | 239 | static int is_mount_compatible_mode(void) |
9d67679b KZ |
240 | { |
241 | if (!get_match(COL_SOURCE)) | |
242 | return 0; /* <devname|TAG=|mountpoint> is required */ | |
243 | if (get_match(COL_FSTYPE) || get_match(COL_OPTIONS)) | |
244 | return 0; /* cannot be restricted by -t or -O */ | |
245 | if (!(flags & FL_FIRSTONLY)) | |
246 | return 0; /* we have to return the first entry only */ | |
247 | ||
248 | return 1; /* ok */ | |
249 | } | |
250 | ||
32e5466a | 251 | static void disable_columns_truncate(void) |
9d67679b KZ |
252 | { |
253 | int i; | |
254 | ||
af0dc7d3 | 255 | for (i = 0; i < FINDMNT_NCOLUMNS; i++) |
32e5466a | 256 | infos[i].flags &= ~TT_FL_TRUNC; |
9d67679b KZ |
257 | } |
258 | ||
04fd7a9f KZ |
259 | /* |
260 | * converts @name to column ID | |
261 | */ | |
9d67679b | 262 | static int column_name_to_id(const char *name, size_t namesz) |
04fd7a9f KZ |
263 | { |
264 | int i; | |
265 | ||
af0dc7d3 | 266 | for (i = 0; i < FINDMNT_NCOLUMNS; i++) { |
9d67679b | 267 | const char *cn = column_id_to_name(i); |
04fd7a9f | 268 | |
9d67679b | 269 | if (!strncasecmp(name, cn, namesz) && !*(cn + namesz)) |
04fd7a9f KZ |
270 | return i; |
271 | } | |
fdedb45e | 272 | warnx(_("unknown column: %s"), name); |
04fd7a9f KZ |
273 | return -1; |
274 | } | |
275 | ||
fdedb45e | 276 | /* Returns LABEL or UUID */ |
68164f6c | 277 | static const char *get_tag(struct libmnt_fs *fs, const char *tagname) |
9d67679b KZ |
278 | { |
279 | const char *t, *v, *res; | |
280 | ||
281 | if (!mnt_fs_get_tag(fs, &t, &v) && !strcmp(t, tagname)) | |
282 | res = v; | |
283 | else { | |
284 | res = mnt_fs_get_source(fs); | |
285 | if (res) | |
286 | res = mnt_resolve_spec(res, cache); | |
287 | if (res) | |
288 | res = mnt_cache_find_tag_value(cache, res, tagname); | |
289 | } | |
290 | ||
291 | return res; | |
292 | } | |
293 | ||
a85ef33b DR |
294 | static const char *get_vfs_attr(struct libmnt_fs *fs, int sizetype) |
295 | { | |
296 | struct statvfs buf; | |
297 | uint64_t vfs_attr; | |
298 | char *sizestr; | |
299 | ||
300 | if (statvfs(mnt_fs_get_target(fs), &buf) != 0) | |
301 | return NULL; | |
302 | ||
303 | switch(sizetype) { | |
304 | case COL_SIZE: | |
305 | vfs_attr = buf.f_frsize * buf.f_blocks; | |
306 | break; | |
307 | case COL_AVAIL: | |
308 | vfs_attr = buf.f_frsize * buf.f_bfree; | |
309 | break; | |
310 | case COL_USED: | |
311 | vfs_attr = buf.f_frsize * (buf.f_blocks - buf.f_bfree); | |
312 | break; | |
313 | case COL_USEPERC: | |
314 | if (buf.f_blocks == 0) | |
315 | return "-"; | |
316 | ||
317 | if (asprintf(&sizestr, "%.0f%%", | |
318 | (double)(buf.f_blocks - buf.f_bfree) / | |
319 | buf.f_blocks * 100) == -1) | |
320 | err(EXIT_FAILURE, "failed to allocate string"); | |
321 | return sizestr; | |
322 | } | |
323 | ||
324 | return vfs_attr == 0 ? "0" : | |
325 | size_to_human_string(SIZE_SUFFIX_1LETTER, vfs_attr); | |
326 | } | |
327 | ||
46236388 KZ |
328 | /* reads FS data from libmount |
329 | * TODO: add function that will deallocate data allocated by get_data() | |
330 | */ | |
68164f6c | 331 | static const char *get_data(struct libmnt_fs *fs, int num) |
9d67679b KZ |
332 | { |
333 | const char *str = NULL; | |
a85ef33b | 334 | int col_id = get_column_id(num); |
9d67679b | 335 | |
a85ef33b | 336 | switch (col_id) { |
04fd7a9f | 337 | case COL_SOURCE: |
b2214e1f KZ |
338 | { |
339 | const char *root = mnt_fs_get_root(fs); | |
340 | ||
9d67679b | 341 | str = mnt_fs_get_srcpath(fs); |
04fd7a9f | 342 | |
9d67679b KZ |
343 | if (str && (flags & FL_CANONICALIZE)) |
344 | str = mnt_resolve_path(str, cache); | |
345 | if (!str) { | |
346 | str = mnt_fs_get_source(fs); | |
347 | ||
348 | if (str && (flags & FL_EVALUATE)) | |
349 | str = mnt_resolve_spec(str, cache); | |
350 | } | |
b2214e1f KZ |
351 | if (root && str && !(flags & FL_NOFSROOT) && strcmp(root, "/")) { |
352 | char *tmp; | |
353 | ||
6f312c89 | 354 | if (xasprintf(&tmp, "%s[%s]", str, root) > 0) |
b2214e1f KZ |
355 | str = tmp; |
356 | } | |
04fd7a9f | 357 | break; |
b2214e1f | 358 | } |
04fd7a9f | 359 | case COL_TARGET: |
fdedb45e | 360 | str = mnt_fs_get_target(fs); |
04fd7a9f KZ |
361 | break; |
362 | case COL_FSTYPE: | |
363 | str = mnt_fs_get_fstype(fs); | |
364 | break; | |
365 | case COL_OPTIONS: | |
d783ee0b | 366 | str = mnt_fs_get_options(fs); |
04fd7a9f | 367 | break; |
631280e0 | 368 | case COL_VFS_OPTIONS: |
411fe06e | 369 | str = mnt_fs_get_vfs_options(fs); |
631280e0 KZ |
370 | break; |
371 | case COL_FS_OPTIONS: | |
411fe06e | 372 | str = mnt_fs_get_fs_options(fs); |
631280e0 | 373 | break; |
9d67679b KZ |
374 | case COL_UUID: |
375 | str = get_tag(fs, "UUID"); | |
376 | break; | |
377 | case COL_LABEL: | |
378 | str = get_tag(fs, "LABEL"); | |
379 | break; | |
46236388 KZ |
380 | case COL_MAJMIN: |
381 | { | |
382 | dev_t devno = mnt_fs_get_devno(fs); | |
383 | if (devno) { | |
384 | char *tmp; | |
385 | int rc = 0; | |
49e9fd3a | 386 | if ((tt_flags & TT_FL_RAW) || (tt_flags & TT_FL_EXPORT)) |
6f312c89 | 387 | rc = xasprintf(&tmp, "%u:%u", |
68164f6c | 388 | major(devno), minor(devno)); |
46236388 | 389 | else |
6f312c89 | 390 | rc = xasprintf(&tmp, "%3u:%-3u", |
68164f6c | 391 | major(devno), minor(devno)); |
46236388 KZ |
392 | if (rc) |
393 | str = tmp; | |
394 | } | |
a85ef33b | 395 | break; |
46236388 | 396 | } |
a85ef33b DR |
397 | case COL_SIZE: |
398 | case COL_AVAIL: | |
399 | case COL_USED: | |
400 | case COL_USEPERC: | |
401 | str = get_vfs_attr(fs, col_id); | |
402 | break; | |
04fd7a9f | 403 | default: |
9d67679b | 404 | break; |
04fd7a9f | 405 | } |
fdedb45e | 406 | return str; |
9d67679b KZ |
407 | } |
408 | ||
32e5466a KZ |
409 | static const char *get_tabdiff_data(struct libmnt_fs *old_fs, |
410 | struct libmnt_fs *new_fs, | |
411 | int change, | |
412 | int num) | |
413 | { | |
414 | const char *str = NULL; | |
415 | ||
416 | switch (get_column_id(num)) { | |
417 | case COL_ACTION: | |
418 | switch (change) { | |
419 | case MNT_TABDIFF_MOUNT: | |
420 | str = _("mount"); | |
421 | break; | |
422 | case MNT_TABDIFF_UMOUNT: | |
423 | str = _("umount"); | |
424 | break; | |
425 | case MNT_TABDIFF_REMOUNT: | |
426 | str = _("remount"); | |
427 | break; | |
428 | case MNT_TABDIFF_MOVE: | |
429 | str = _("move"); | |
430 | break; | |
431 | default: | |
432 | str = _("unknown"); | |
433 | break; | |
434 | } | |
435 | break; | |
436 | case COL_OLD_OPTIONS: | |
77a1c5f7 KZ |
437 | if (old_fs && (change == MNT_TABDIFF_REMOUNT || |
438 | change == MNT_TABDIFF_UMOUNT)) | |
32e5466a KZ |
439 | str = mnt_fs_get_options(old_fs); |
440 | break; | |
441 | case COL_OLD_TARGET: | |
77a1c5f7 KZ |
442 | if (old_fs && (change == MNT_TABDIFF_MOVE || |
443 | change == MNT_TABDIFF_UMOUNT)) | |
32e5466a KZ |
444 | str = mnt_fs_get_target(old_fs); |
445 | break; | |
446 | default: | |
447 | if (new_fs) | |
448 | str = get_data(new_fs, num); | |
449 | else | |
450 | str = get_data(old_fs, num); | |
451 | break; | |
452 | } | |
453 | return str; | |
454 | } | |
455 | ||
fdedb45e | 456 | /* adds one line to the output @tab */ |
68164f6c | 457 | static struct tt_line *add_line(struct tt *tt, struct libmnt_fs *fs, |
fdedb45e | 458 | struct tt_line *parent) |
9d67679b | 459 | { |
fdedb45e KZ |
460 | int i; |
461 | struct tt_line *line = tt_add_line(tt, parent); | |
9d67679b | 462 | |
fdedb45e KZ |
463 | if (!line) { |
464 | warn(_("failed to add line to output")); | |
465 | return NULL; | |
9d67679b | 466 | } |
fdedb45e KZ |
467 | for (i = 0; i < ncolumns; i++) |
468 | tt_line_set_data(line, i, get_data(fs, i)); | |
9d67679b | 469 | |
049caefd | 470 | tt_line_set_userdata(line, fs); |
fdedb45e | 471 | return line; |
9d67679b KZ |
472 | } |
473 | ||
32e5466a KZ |
474 | static struct tt_line *add_tabdiff_line(struct tt *tt, struct libmnt_fs *new_fs, |
475 | struct libmnt_fs *old_fs, int change) | |
476 | { | |
477 | int i; | |
478 | struct tt_line *line = tt_add_line(tt, NULL); | |
479 | ||
480 | if (!line) { | |
481 | warn(_("failed to add line to output")); | |
482 | return NULL; | |
483 | } | |
484 | for (i = 0; i < ncolumns; i++) | |
485 | tt_line_set_data(line, i, | |
486 | get_tabdiff_data(old_fs, new_fs, change, i)); | |
487 | ||
488 | return line; | |
489 | } | |
490 | ||
68164f6c | 491 | static int has_line(struct tt *tt, struct libmnt_fs *fs) |
049caefd KZ |
492 | { |
493 | struct list_head *p; | |
494 | ||
495 | list_for_each(p, &tt->tb_lines) { | |
496 | struct tt_line *ln = list_entry(p, struct tt_line, ln_lines); | |
68164f6c | 497 | if ((struct libmnt_fs *) ln->userdata == fs) |
049caefd KZ |
498 | return 1; |
499 | } | |
500 | return 0; | |
501 | } | |
502 | ||
503 | /* reads filesystems from @tb (libmount) and fillin @tt (output table) */ | |
68164f6c KZ |
504 | static int create_treenode(struct tt *tt, struct libmnt_table *tb, |
505 | struct libmnt_fs *fs, struct tt_line *parent_line) | |
04fd7a9f | 506 | { |
68164f6c KZ |
507 | struct libmnt_fs *chld = NULL; |
508 | struct libmnt_iter *itr = NULL; | |
fdedb45e KZ |
509 | struct tt_line *line; |
510 | int rc = -1; | |
9d67679b | 511 | |
fdedb45e KZ |
512 | if (!fs) { |
513 | /* first call, get root FS */ | |
68164f6c | 514 | if (mnt_table_get_root_fs(tb, &fs)) |
fdedb45e KZ |
515 | goto leave; |
516 | parent_line = NULL; | |
049caefd KZ |
517 | |
518 | } else if ((flags & FL_SUBMOUNTS) && has_line(tt, fs)) | |
519 | return 0; | |
9d67679b | 520 | |
fdedb45e KZ |
521 | itr = mnt_new_iter(MNT_ITER_FORWARD); |
522 | if (!itr) | |
523 | goto leave; | |
9d67679b | 524 | |
fdedb45e KZ |
525 | line = add_line(tt, fs, parent_line); |
526 | if (!line) | |
527 | goto leave; | |
9d67679b | 528 | |
fdedb45e KZ |
529 | /* |
530 | * add all children to the output table | |
531 | */ | |
68164f6c | 532 | while(mnt_table_next_child_fs(tb, itr, fs, &chld) == 0) { |
fdedb45e KZ |
533 | if (create_treenode(tt, tb, chld, line)) |
534 | goto leave; | |
9d67679b | 535 | } |
fdedb45e KZ |
536 | rc = 0; |
537 | leave: | |
538 | mnt_free_iter(itr); | |
539 | return rc; | |
04fd7a9f KZ |
540 | } |
541 | ||
20055151 | 542 | /* error callback */ |
6e5c0fc2 KZ |
543 | static int parser_errcb(struct libmnt_table *tb __attribute__ ((__unused__)), |
544 | const char *filename, int line) | |
20055151 | 545 | { |
b1b9f1c1 | 546 | warnx(_("%s: parse error at line %d"), filename, line); |
20055151 KZ |
547 | return 0; |
548 | } | |
549 | ||
8c5eba3e KZ |
550 | static char **append_tabfile(char **files, int *nfiles, char *filename) |
551 | { | |
99d618c0 | 552 | files = xrealloc(files, sizeof(char *) * (*nfiles + 1)); |
8c5eba3e KZ |
553 | files[(*nfiles)++] = filename; |
554 | return files; | |
555 | } | |
556 | ||
fdedb45e | 557 | /* calls libmount fstab/mtab/mountinfo parser */ |
8c5eba3e KZ |
558 | static struct libmnt_table *parse_tabfiles(char **files, |
559 | int nfiles, | |
560 | int tabtype) | |
04fd7a9f | 561 | { |
8c5eba3e | 562 | struct libmnt_table *tb; |
762ef0e1 | 563 | int rc = 0; |
20055151 | 564 | |
8c5eba3e | 565 | tb = mnt_new_table(); |
fdedb45e | 566 | if (!tb) { |
32e5466a | 567 | warn(_("failed to initialize libmount table")); |
04fd7a9f | 568 | return NULL; |
fdedb45e | 569 | } |
68164f6c | 570 | mnt_table_set_parser_errcb(tb, parser_errcb); |
20055151 | 571 | |
8c5eba3e KZ |
572 | do { |
573 | /* NULL means that libmount will use default paths */ | |
574 | const char *path = nfiles ? *files++ : NULL; | |
575 | ||
576 | switch (tabtype) { | |
577 | case TABTYPE_FSTAB: | |
578 | rc = mnt_table_parse_fstab(tb, path); | |
579 | break; | |
580 | case TABTYPE_MTAB: | |
581 | rc = mnt_table_parse_mtab(tb, path); | |
582 | break; | |
583 | case TABTYPE_KERNEL: | |
584 | if (!path) | |
585 | path = access(_PATH_PROC_MOUNTINFO, R_OK) == 0 ? | |
586 | _PATH_PROC_MOUNTINFO : | |
587 | _PATH_PROC_MOUNTS; | |
588 | ||
589 | rc = mnt_table_parse_file(tb, path); | |
590 | break; | |
591 | } | |
592 | if (rc) { | |
593 | mnt_free_table(tb); | |
594 | warn(_("can't read %s"), path); | |
595 | return NULL; | |
596 | } | |
597 | } while (--nfiles > 0); | |
20055151 | 598 | |
04fd7a9f | 599 | return tb; |
04fd7a9f KZ |
600 | } |
601 | ||
2f1ac44b KZ |
602 | /* checks if @tb contains parent->child relations */ |
603 | static int tab_is_tree(struct libmnt_table *tb) | |
604 | { | |
605 | struct libmnt_fs *fs = NULL; | |
606 | struct libmnt_iter *itr = NULL; | |
607 | int rc = 0; | |
608 | ||
609 | itr = mnt_new_iter(MNT_ITER_BACKWARD); | |
610 | if (!itr) | |
611 | return 0; | |
612 | ||
613 | if (mnt_table_next_fs(tb, itr, &fs) == 0) | |
614 | rc = mnt_fs_get_id(fs) > 0 && mnt_fs_get_parent_id(fs) > 0; | |
615 | ||
616 | mnt_free_iter(itr); | |
617 | return rc; | |
618 | } | |
619 | ||
68164f6c | 620 | /* filter function for libmount (mnt_table_find_next_fs()) */ |
6e5c0fc2 KZ |
621 | static int match_func(struct libmnt_fs *fs, |
622 | void *data __attribute__ ((__unused__))) | |
04fd7a9f | 623 | { |
04fd7a9f | 624 | int rc = flags & FL_INVERT ? 1 : 0; |
9d67679b | 625 | const char *m; |
04fd7a9f | 626 | |
9d67679b KZ |
627 | m = get_match(COL_TARGET); |
628 | if (m && !mnt_fs_match_target(fs, m, cache)) | |
04fd7a9f | 629 | return rc; |
9d67679b KZ |
630 | |
631 | m = get_match(COL_SOURCE); | |
632 | if (m && !mnt_fs_match_source(fs, m, cache)) | |
04fd7a9f | 633 | return rc; |
9d67679b KZ |
634 | |
635 | m = get_match(COL_FSTYPE); | |
636 | if (m && !mnt_fs_match_fstype(fs, m)) | |
04fd7a9f | 637 | return rc; |
9d67679b KZ |
638 | |
639 | m = get_match(COL_OPTIONS); | |
640 | if (m && !mnt_fs_match_options(fs, m)) | |
04fd7a9f KZ |
641 | return rc; |
642 | ||
643 | return !rc; | |
644 | } | |
645 | ||
fdedb45e | 646 | /* iterate over filesystems in @tb */ |
68164f6c KZ |
647 | static struct libmnt_fs *get_next_fs(struct libmnt_table *tb, |
648 | struct libmnt_iter *itr) | |
04fd7a9f | 649 | { |
68164f6c | 650 | struct libmnt_fs *fs = NULL; |
9d67679b KZ |
651 | |
652 | if (is_listall_mode()) { | |
653 | /* | |
654 | * Print whole file | |
655 | */ | |
e3963f60 KZ |
656 | if (mnt_table_next_fs(tb, itr, &fs) != 0) |
657 | return NULL; | |
9d67679b KZ |
658 | |
659 | } else if (is_mount_compatible_mode()) { | |
660 | /* | |
661 | * Look up for FS in the same way how mount(8) searchs in fstab | |
662 | * | |
663 | * findmnt -f <spec> | |
664 | */ | |
68164f6c | 665 | fs = mnt_table_find_source(tb, get_match(COL_SOURCE), |
9d67679b | 666 | mnt_iter_get_direction(itr)); |
9a30c6ef KZ |
667 | |
668 | if (!fs && !(flags & FL_NOSWAPMATCH)) | |
68164f6c | 669 | fs = mnt_table_find_target(tb, get_match(COL_SOURCE), |
9d67679b KZ |
670 | mnt_iter_get_direction(itr)); |
671 | } else { | |
672 | /* | |
673 | * Look up for all matching entries | |
674 | * | |
675 | * findmnt [-l] <source> <target> [-O <options>] [-t <types>] | |
676 | * findmnt [-l] <spec> [-O <options>] [-t <types>] | |
677 | */ | |
678 | again: | |
68164f6c | 679 | mnt_table_find_next_fs(tb, itr, match_func, NULL, &fs); |
9d67679b KZ |
680 | |
681 | if (!fs && | |
682 | !(flags & FL_NOSWAPMATCH) && | |
683 | !get_match(COL_TARGET) && get_match(COL_SOURCE)) { | |
684 | ||
685 | /* swap 'spec' and target. */ | |
686 | set_match(COL_TARGET, get_match(COL_SOURCE)); | |
687 | set_match(COL_SOURCE, NULL); | |
688 | mnt_reset_iter(itr, -1); | |
689 | ||
690 | goto again; | |
691 | } | |
692 | } | |
9d67679b | 693 | |
fdedb45e | 694 | return fs; |
04fd7a9f KZ |
695 | } |
696 | ||
68164f6c KZ |
697 | static int add_matching_lines(struct libmnt_table *tb, |
698 | struct tt *tt, int direction) | |
049caefd | 699 | { |
68164f6c KZ |
700 | struct libmnt_iter *itr = NULL; |
701 | struct libmnt_fs *fs; | |
049caefd KZ |
702 | int nlines = 0, rc = -1; |
703 | ||
704 | itr = mnt_new_iter(direction); | |
705 | if (!itr) { | |
706 | warn(_("failed to initialize libmount iterator")); | |
707 | goto done; | |
708 | } | |
709 | ||
710 | while((fs = get_next_fs(tb, itr))) { | |
711 | if ((tt_flags & TT_FL_TREE) || (flags & FL_SUBMOUNTS)) | |
712 | rc = create_treenode(tt, tb, fs, NULL); | |
713 | else | |
714 | rc = !add_line(tt, fs, NULL); | |
715 | if (rc) | |
716 | goto done; | |
717 | nlines++; | |
718 | if (flags & FL_FIRSTONLY) | |
719 | break; | |
720 | flags |= FL_NOSWAPMATCH; | |
721 | } | |
722 | ||
723 | if (nlines) | |
724 | rc = 0; | |
725 | done: | |
726 | mnt_free_iter(itr); | |
727 | return rc; | |
728 | } | |
729 | ||
582a5006 KZ |
730 | static int poll_match(struct libmnt_fs *fs) |
731 | { | |
732 | int rc = match_func(fs, NULL); | |
733 | ||
734 | if (rc == 0 && !(flags & FL_NOSWAPMATCH) && | |
735 | get_match(COL_SOURCE) && !get_match(COL_TARGET)) { | |
736 | /* | |
737 | * findmnt --poll /foo | |
738 | * The '/foo' source as well as target. | |
739 | */ | |
740 | const char *str = get_match(COL_SOURCE); | |
741 | ||
742 | set_match(COL_TARGET, str); /* swap */ | |
743 | set_match(COL_SOURCE, NULL); | |
744 | ||
745 | rc = match_func(fs, NULL); | |
746 | ||
747 | set_match(COL_TARGET, NULL); /* restore */ | |
748 | set_match(COL_SOURCE, str); | |
749 | ||
750 | } | |
751 | return rc; | |
752 | } | |
753 | ||
32e5466a KZ |
754 | static int poll_table(struct libmnt_table *tb, const char *tabfile, |
755 | int timeout, struct tt *tt, int direction) | |
756 | { | |
d1cabd5c | 757 | FILE *f = NULL; |
32e5466a KZ |
758 | int rc = -1; |
759 | struct libmnt_iter *itr = NULL; | |
760 | struct libmnt_table *tb_new = NULL; | |
761 | struct libmnt_tabdiff *diff = NULL; | |
762 | struct pollfd fds[1]; | |
763 | ||
764 | tb_new = mnt_new_table(); | |
765 | if (!tb_new) { | |
766 | warn(_("failed to initialize libmount table")); | |
767 | goto done; | |
768 | } | |
769 | ||
770 | itr = mnt_new_iter(direction); | |
771 | if (!itr) { | |
772 | warn(_("failed to initialize libmount iterator")); | |
773 | goto done; | |
774 | } | |
775 | ||
776 | diff = mnt_new_tabdiff(); | |
777 | if (!diff) { | |
778 | warn(_("failed to initialize libmount tabdiff")); | |
779 | goto done; | |
780 | } | |
781 | ||
782 | /* cache is unnecessary to detect changes */ | |
783 | mnt_table_set_cache(tb, NULL); | |
784 | mnt_table_set_cache(tb_new, NULL); | |
785 | ||
786 | f = fopen(tabfile, "r"); | |
787 | if (!f) { | |
788 | warn(_("%s: open failed"), tabfile); | |
789 | goto done; | |
790 | } | |
791 | ||
792 | mnt_table_set_parser_errcb(tb_new, parser_errcb); | |
793 | ||
794 | fds[0].fd = fileno(f); | |
795 | fds[0].events = POLLPRI; | |
796 | ||
797 | while (1) { | |
798 | struct libmnt_table *tmp; | |
799 | struct libmnt_fs *old, *new; | |
582a5006 | 800 | int change, count; |
32e5466a | 801 | |
582a5006 KZ |
802 | count = poll(fds, 1, timeout); |
803 | if (count == 0) | |
ad38fb9f | 804 | break; /* timeout */ |
582a5006 | 805 | if (count < 0) { |
32e5466a KZ |
806 | warn(_("poll() failed")); |
807 | goto done; | |
808 | } | |
809 | ||
810 | rewind(f); | |
811 | rc = mnt_table_parse_stream(tb_new, f, tabfile); | |
812 | if (!rc) | |
813 | rc = mnt_diff_tables(diff, tb, tb_new); | |
814 | if (rc < 0) | |
815 | goto done; | |
816 | ||
582a5006 | 817 | count = 0; |
32e5466a KZ |
818 | mnt_reset_iter(itr, direction); |
819 | while(mnt_tabdiff_next_change( | |
820 | diff, itr, &old, &new, &change) == 0) { | |
821 | ||
582a5006 KZ |
822 | if (!has_poll_action(change)) |
823 | continue; | |
824 | if (!poll_match(new ? new : old)) | |
825 | continue; | |
826 | count++; | |
32e5466a KZ |
827 | rc = !add_tabdiff_line(tt, new, old, change); |
828 | if (rc) | |
829 | goto done; | |
830 | if (flags & FL_FIRSTONLY) | |
831 | break; | |
832 | } | |
833 | ||
582a5006 KZ |
834 | if (count) { |
835 | rc = tt_print_table(tt); | |
836 | if (rc) | |
837 | goto done; | |
838 | } | |
32e5466a KZ |
839 | |
840 | /* swap tables */ | |
841 | tmp = tb; | |
842 | tb = tb_new; | |
843 | tb_new = tmp; | |
844 | ||
845 | tt_remove_lines(tt); | |
846 | mnt_reset_table(tb_new); | |
582a5006 KZ |
847 | |
848 | if (count && (flags & FL_FIRSTONLY)) | |
849 | break; | |
32e5466a KZ |
850 | } |
851 | ||
852 | rc = 0; | |
853 | done: | |
854 | mnt_free_table(tb_new); | |
855 | mnt_free_tabdiff(diff); | |
856 | mnt_free_iter(itr); | |
d1cabd5c KZ |
857 | if (f) |
858 | fclose(f); | |
32e5466a KZ |
859 | return rc; |
860 | } | |
861 | ||
abafd686 | 862 | static void __attribute__((__noreturn__)) usage(FILE *out) |
04fd7a9f | 863 | { |
9ead0006 KZ |
864 | int i; |
865 | ||
9d67679b KZ |
866 | fprintf(out, _( |
867 | "\nUsage:\n" | |
868 | " %1$s [options]\n" | |
869 | " %1$s [options] <device> | <mountpoint>\n" | |
870 | " %1$s [options] <device> <mountpoint>\n" | |
871 | " %1$s [options] [--source <device>] [--target <mountpoint>]\n"), | |
872 | program_invocation_short_name); | |
04fd7a9f KZ |
873 | |
874 | fprintf(out, _( | |
9d67679b | 875 | "\nOptions:\n" |
2f1ac44b | 876 | " -s, --fstab search in static table of filesystems\n" |
cbec3cbf | 877 | " -m, --mtab search in table of mounted filesystems\n" |
c3214059 | 878 | " -k, --kernel search in kernel table of mounted\n" |
415b61fc | 879 | " filesystems (default)\n\n")); |
04fd7a9f | 880 | |
415b61fc | 881 | fprintf(out, _( |
582a5006 | 882 | " -p, --poll[=<list>] monitor changes in table of mounted filesystems\n" |
415b61fc | 883 | " -w, --timeout <num> upper limit in milliseconds that --poll will block\n\n")); |
32e5466a | 884 | |
415b61fc | 885 | fprintf(out, _( |
c3214059 | 886 | " -a, --ascii use ASCII chars for tree formatting\n" |
04fd7a9f | 887 | " -c, --canonicalize canonicalize printed paths\n" |
c3214059 BS |
888 | " -d, --direction <word> direction of search, 'forward' or 'backward'\n" |
889 | " -e, --evaluate convert tags (LABEL/UUID) to device names\n" | |
2f1ac44b | 890 | " -F, --tab-file <path> alternative file for --fstab, --mtab or --kernel options\n" |
415b61fc BS |
891 | " -f, --first-only print the first found filesystem only\n")); |
892 | ||
893 | fprintf(out, _( | |
c3214059 BS |
894 | " -h, --help display this help text and exit\n" |
895 | " -i, --invert invert the sense of matching\n" | |
46236388 | 896 | " -l, --list use list format output\n" |
c3214059 | 897 | " -n, --noheadings don't print column headings\n" |
415b61fc BS |
898 | " -u, --notruncate don't truncate text in columns\n")); |
899 | fprintf(out, _( | |
04fd7a9f | 900 | " -O, --options <list> limit the set of filesystems by mount options\n" |
c3214059 | 901 | " -o, --output <list> the output columns to be shown\n" |
49e9fd3a KZ |
902 | " -P, --pairs use key=\"value\" output format\n" |
903 | " -r, --raw use raw output format\n" | |
415b61fc BS |
904 | " -t, --types <list> limit the set of filesystems by FS types\n")); |
905 | fprintf(out, _( | |
b2214e1f | 906 | " -v, --nofsroot don't print [/dir] for bind or btrfs mounts\n" |
c3214059 BS |
907 | " -R, --submounts print all submounts for the matching filesystems\n" |
908 | " -S, --source <string> the device to mount (by name, LABEL= or UUID=)\n" | |
909 | " -T, --target <string> the mountpoint to use\n\n")); | |
04fd7a9f | 910 | |
9ead0006 KZ |
911 | |
912 | fprintf(out, _("\nAvailable columns:\n")); | |
913 | ||
b152e359 KZ |
914 | for (i = 0; i < FINDMNT_NCOLUMNS; i++) |
915 | fprintf(out, " %11s %s\n", infos[i].name, _(infos[i].help)); | |
9ead0006 | 916 | |
9ead0006 | 917 | |
04fd7a9f KZ |
918 | fprintf(out, _("\nFor more information see findmnt(1).\n")); |
919 | ||
920 | exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); | |
921 | } | |
922 | ||
abafd686 | 923 | static void __attribute__((__noreturn__)) |
9d67679b KZ |
924 | errx_mutually_exclusive(const char *opts) |
925 | { | |
926 | errx(EXIT_FAILURE, "%s %s", opts, _("options are mutually exclusive")); | |
927 | } | |
928 | ||
04fd7a9f KZ |
929 | int main(int argc, char *argv[]) |
930 | { | |
68164f6c | 931 | struct libmnt_table *tb = NULL; |
8c5eba3e | 932 | char **tabfiles = NULL; |
9d67679b | 933 | int direction = MNT_ITER_FORWARD; |
ad38fb9f | 934 | int i, c, rc = -1, timeout = -1; |
8c5eba3e | 935 | int ntabfiles = 0, tabtype = 0; |
fdedb45e KZ |
936 | |
937 | /* table.h */ | |
938 | struct tt *tt = NULL; | |
fdedb45e | 939 | |
6c7d5ae9 | 940 | static const struct option longopts[] = { |
9d67679b | 941 | { "ascii", 0, 0, 'a' }, |
04fd7a9f KZ |
942 | { "canonicalize", 0, 0, 'c' }, |
943 | { "direction", 1, 0, 'd' }, | |
944 | { "evaluate", 0, 0, 'e' }, | |
9d67679b | 945 | { "first-only", 0, 0, 'f' }, |
2f1ac44b | 946 | { "fstab", 0, 0, 's' }, |
04fd7a9f KZ |
947 | { "help", 0, 0, 'h' }, |
948 | { "invert", 0, 0, 'i' }, | |
9d67679b KZ |
949 | { "kernel", 0, 0, 'k' }, |
950 | { "list", 0, 0, 'l' }, | |
951 | { "mtab", 0, 0, 'm' }, | |
952 | { "noheadings", 0, 0, 'n' }, | |
953 | { "notruncate", 0, 0, 'u' }, | |
04fd7a9f | 954 | { "options", 1, 0, 'O' }, |
9d67679b | 955 | { "output", 1, 0, 'o' }, |
582a5006 | 956 | { "poll", 2, 0, 'p' }, |
49e9fd3a | 957 | { "pairs", 0, 0, 'P' }, |
9d67679b | 958 | { "raw", 0, 0, 'r' }, |
04fd7a9f | 959 | { "types", 1, 0, 't' }, |
b2214e1f | 960 | { "fsroot", 0, 0, 'v' }, |
049caefd | 961 | { "submounts", 0, 0, 'R' }, |
9d67679b | 962 | { "source", 1, 0, 'S' }, |
2f1ac44b | 963 | { "tab-file", 1, 0, 'F' }, |
9d67679b | 964 | { "target", 1, 0, 'T' }, |
ad38fb9f | 965 | { "timeout", 1, 0, 'w' }, |
9d67679b | 966 | |
04fd7a9f KZ |
967 | { NULL, 0, 0, 0 } |
968 | }; | |
969 | ||
af0dc7d3 | 970 | assert(ARRAY_SIZE(columns) == FINDMNT_NCOLUMNS); |
9d67679b | 971 | |
04fd7a9f KZ |
972 | setlocale(LC_ALL, ""); |
973 | bindtextdomain(PACKAGE, LOCALEDIR); | |
974 | textdomain(PACKAGE); | |
975 | ||
9d67679b | 976 | /* default output format */ |
fdedb45e | 977 | tt_flags |= TT_FL_TREE; |
04fd7a9f | 978 | |
9d67679b | 979 | while ((c = getopt_long(argc, argv, |
2f1ac44b | 980 | "acd:ehifF:o:O:p::Pklmnrst:uvRS:T:w:", |
d466c6a1 | 981 | longopts, NULL)) != -1) { |
04fd7a9f | 982 | switch(c) { |
9d67679b | 983 | case 'a': |
fdedb45e | 984 | tt_flags |= TT_FL_ASCII; |
9d67679b | 985 | break; |
04fd7a9f KZ |
986 | case 'c': |
987 | flags |= FL_CANONICALIZE; | |
988 | break; | |
989 | case 'd': | |
4e6bd74c | 990 | if (!strcmp(optarg, "forward")) |
04fd7a9f | 991 | direction = MNT_ITER_FORWARD; |
4e6bd74c | 992 | else if (!strcmp(optarg, "backward")) |
04fd7a9f KZ |
993 | direction = MNT_ITER_BACKWARD; |
994 | else | |
995 | errx(EXIT_FAILURE, | |
8e350e48 | 996 | _("unknown direction '%s'"), optarg); |
04fd7a9f KZ |
997 | break; |
998 | case 'e': | |
999 | flags |= FL_EVALUATE; | |
1000 | break; | |
1001 | case 'h': | |
1002 | usage(stdout); | |
1003 | break; | |
1004 | case 'i': | |
1005 | flags |= FL_INVERT; | |
1006 | break; | |
9d67679b | 1007 | case 'f': |
04fd7a9f KZ |
1008 | flags |= FL_FIRSTONLY; |
1009 | break; | |
2f1ac44b | 1010 | case 'F': |
8c5eba3e | 1011 | tabfiles = append_tabfile(tabfiles, &ntabfiles, optarg); |
2f1ac44b | 1012 | break; |
9d67679b | 1013 | case 'u': |
32e5466a | 1014 | disable_columns_truncate(); |
9d67679b | 1015 | break; |
04fd7a9f | 1016 | case 'o': |
c87638ad | 1017 | ncolumns = string_to_idarray(optarg, |
bdc3ed66 KZ |
1018 | columns, ARRAY_SIZE(columns), |
1019 | column_name_to_id); | |
1020 | if (ncolumns < 0) | |
fdedb45e | 1021 | exit(EXIT_FAILURE); |
04fd7a9f KZ |
1022 | break; |
1023 | case 'O': | |
9d67679b | 1024 | set_match(COL_OPTIONS, optarg); |
04fd7a9f | 1025 | break; |
32e5466a | 1026 | case 'p': |
bdc3ed66 | 1027 | if (optarg) { |
c87638ad | 1028 | nactions = string_to_idarray(optarg, |
bdc3ed66 KZ |
1029 | actions, ARRAY_SIZE(actions), |
1030 | poll_action_name_to_id); | |
1031 | if (nactions < 0) | |
1032 | exit(EXIT_FAILURE); | |
1033 | } | |
32e5466a KZ |
1034 | flags |= FL_POLL; |
1035 | tt_flags &= ~TT_FL_TREE; | |
1036 | break; | |
49e9fd3a KZ |
1037 | case 'P': |
1038 | tt_flags |= TT_FL_EXPORT; | |
1039 | tt_flags &= ~TT_FL_TREE; | |
1040 | break; | |
fdedb45e | 1041 | case 'm': /* mtab */ |
8c5eba3e | 1042 | if (tabtype) |
9d67679b | 1043 | errx_mutually_exclusive("--{fstab,mtab,kernel}"); |
8c5eba3e | 1044 | tabtype = TABTYPE_MTAB; |
fdedb45e | 1045 | tt_flags &= ~TT_FL_TREE; |
04fd7a9f | 1046 | break; |
fdedb45e | 1047 | case 's': /* fstab */ |
8c5eba3e | 1048 | if (tabtype) |
9d67679b | 1049 | errx_mutually_exclusive("--{fstab,mtab,kernel}"); |
8c5eba3e | 1050 | tabtype = TABTYPE_FSTAB; |
ac808156 | 1051 | tt_flags &= ~TT_FL_TREE; |
04fd7a9f | 1052 | break; |
fdedb45e | 1053 | case 'k': /* kernel (mountinfo) */ |
8c5eba3e | 1054 | if (tabtype) |
9d67679b | 1055 | errx_mutually_exclusive("--{fstab,mtab,kernel}"); |
8c5eba3e | 1056 | tabtype = TABTYPE_KERNEL; |
04fd7a9f KZ |
1057 | break; |
1058 | case 't': | |
9d67679b KZ |
1059 | set_match(COL_FSTYPE, optarg); |
1060 | break; | |
1061 | case 'r': | |
fdedb45e KZ |
1062 | tt_flags &= ~TT_FL_TREE; /* disable the default */ |
1063 | tt_flags |= TT_FL_RAW; /* enable raw */ | |
9d67679b KZ |
1064 | break; |
1065 | case 'l': | |
49e9fd3a KZ |
1066 | if ((tt_flags & TT_FL_RAW) && (tt_flags & TT_FL_EXPORT)) |
1067 | errx_mutually_exclusive("--{raw,list,pairs}"); | |
9d67679b | 1068 | |
fdedb45e | 1069 | tt_flags &= ~TT_FL_TREE; /* disable the default */ |
9d67679b KZ |
1070 | break; |
1071 | case 'n': | |
fdedb45e | 1072 | tt_flags |= TT_FL_NOHEADINGS; |
9d67679b | 1073 | break; |
b2214e1f KZ |
1074 | case 'v': |
1075 | flags |= FL_NOFSROOT; | |
1076 | break; | |
049caefd KZ |
1077 | case 'R': |
1078 | flags |= FL_SUBMOUNTS; | |
1079 | break; | |
9d67679b KZ |
1080 | case 'S': |
1081 | set_match(COL_SOURCE, optarg); | |
1082 | flags |= FL_NOSWAPMATCH; | |
1083 | break; | |
1084 | case 'T': | |
1085 | set_match(COL_TARGET, optarg); | |
1086 | flags |= FL_NOSWAPMATCH; | |
04fd7a9f | 1087 | break; |
ad38fb9f KZ |
1088 | case 'w': |
1089 | timeout = strtol_or_err(optarg, | |
1090 | _("failed to parse timeout")); | |
1091 | break; | |
04fd7a9f KZ |
1092 | default: |
1093 | usage(stderr); | |
1094 | break; | |
1095 | } | |
1096 | } | |
1097 | ||
32e5466a KZ |
1098 | /* default columns */ |
1099 | if (!ncolumns) { | |
1100 | if (flags & FL_POLL) | |
1101 | columns[ncolumns++] = COL_ACTION; | |
1102 | ||
1103 | columns[ncolumns++] = COL_TARGET; | |
1104 | columns[ncolumns++] = COL_SOURCE; | |
1105 | columns[ncolumns++] = COL_FSTYPE; | |
1106 | columns[ncolumns++] = COL_OPTIONS; | |
1107 | } | |
1108 | ||
8c5eba3e KZ |
1109 | if (!tabtype) |
1110 | tabtype = TABTYPE_KERNEL; | |
2f1ac44b | 1111 | |
9d67679b | 1112 | |
8c5eba3e KZ |
1113 | if (flags & FL_POLL) { |
1114 | if (tabtype != TABTYPE_KERNEL) | |
1115 | errx_mutually_exclusive("--{poll,fstab,mtab}"); | |
1116 | if (ntabfiles > 1) | |
aec5c2a6 | 1117 | errx(EXIT_FAILURE, _("--poll accepts only one file, but more specified by --tab-file")); |
fdedb45e | 1118 | } |
b2214e1f | 1119 | |
9d67679b KZ |
1120 | if (optind < argc && (get_match(COL_SOURCE) || get_match(COL_TARGET))) |
1121 | errx(EXIT_FAILURE, _( | |
1122 | "options --target and --source can't be used together " | |
1123 | "with command line element that is not an option")); | |
1124 | ||
04fd7a9f | 1125 | if (optind < argc) |
9d67679b | 1126 | set_match(COL_SOURCE, argv[optind++]); /* dev/tag/mountpoint */ |
04fd7a9f | 1127 | if (optind < argc) |
9d67679b | 1128 | set_match(COL_TARGET, argv[optind++]); /* mountpoint */ |
04fd7a9f | 1129 | |
049caefd KZ |
1130 | if ((flags & FL_SUBMOUNTS) && is_listall_mode()) |
1131 | /* don't care about submounts if list all mounts */ | |
1132 | flags &= ~FL_SUBMOUNTS; | |
1133 | ||
1134 | if (!(flags & FL_SUBMOUNTS) && | |
1135 | (!is_listall_mode() || (flags & FL_FIRSTONLY))) | |
fdedb45e KZ |
1136 | tt_flags &= ~TT_FL_TREE; |
1137 | ||
ac808156 KZ |
1138 | if (!(flags & FL_NOSWAPMATCH) && |
1139 | !get_match(COL_TARGET) && get_match(COL_SOURCE)) { | |
1140 | /* | |
1141 | * Check if we can swap source and target, it's | |
1142 | * not possible if the source is LABEL=/UUID= | |
1143 | */ | |
1144 | const char *x = get_match(COL_SOURCE); | |
1145 | ||
1146 | if (!strncmp(x, "LABEL=", 6) || !strncmp(x, "UUID=", 5)) | |
1147 | flags |= FL_NOSWAPMATCH; | |
1148 | } | |
1149 | ||
fdedb45e KZ |
1150 | /* |
1151 | * initialize libmount | |
1152 | */ | |
ac808156 KZ |
1153 | mnt_init_debug(0); |
1154 | ||
8c5eba3e | 1155 | tb = parse_tabfiles(tabfiles, ntabfiles, tabtype); |
04fd7a9f | 1156 | if (!tb) |
fdedb45e | 1157 | goto leave; |
04fd7a9f | 1158 | |
2f1ac44b KZ |
1159 | if ((tt_flags & TT_FL_TREE) && !tab_is_tree(tb)) |
1160 | tt_flags &= ~TT_FL_TREE; | |
1161 | ||
04fd7a9f | 1162 | cache = mnt_new_cache(); |
fdedb45e KZ |
1163 | if (!cache) { |
1164 | warn(_("failed to initialize libmount cache")); | |
1165 | goto leave; | |
1166 | } | |
68164f6c | 1167 | mnt_table_set_cache(tb, cache); |
04fd7a9f | 1168 | |
fdedb45e | 1169 | /* |
00b4bcdf | 1170 | * initialize output formatting (tt.h) |
fdedb45e KZ |
1171 | */ |
1172 | tt = tt_new_table(tt_flags); | |
1173 | if (!tt) { | |
1174 | warn(_("failed to initialize output table")); | |
1175 | goto leave; | |
1176 | } | |
ac808156 | 1177 | |
fdedb45e | 1178 | for (i = 0; i < ncolumns; i++) { |
32e5466a KZ |
1179 | int fl = get_column_flags(i); |
1180 | int id = get_column_id(i); | |
1181 | ||
1182 | if (!(tt_flags & TT_FL_TREE)) | |
1183 | fl &= ~TT_FL_TREE; | |
04fd7a9f | 1184 | |
32e5466a | 1185 | if (!(flags & FL_POLL) && is_tabdiff_column(id)) { |
77a1c5f7 | 1186 | warnx(_("%s column is requested, but --poll " |
32e5466a KZ |
1187 | "is not enabled"), get_column_name(i)); |
1188 | goto leave; | |
1189 | } | |
fdedb45e KZ |
1190 | if (!tt_define_column(tt, get_column_name(i), |
1191 | get_column_whint(i), fl)) { | |
1192 | warn(_("failed to initialize output column")); | |
1193 | goto leave; | |
9d67679b | 1194 | } |
fdedb45e | 1195 | } |
9d67679b | 1196 | |
fdedb45e KZ |
1197 | /* |
1198 | * Fill in data to the output table | |
1199 | */ | |
275c9a48 | 1200 | if (flags & FL_POLL) { |
8c5eba3e | 1201 | /* poll mode (accept the first tabfile only) */ |
275c9a48 KZ |
1202 | if (tabfiles && ntabfiles > 0) |
1203 | rc = poll_table(tb, *tabfiles, timeout, tt, direction); | |
32e5466a | 1204 | |
275c9a48 | 1205 | } else if ((tt_flags & TT_FL_TREE) && is_listall_mode()) |
049caefd KZ |
1206 | /* whole tree */ |
1207 | rc = create_treenode(tt, tb, NULL, NULL); | |
1208 | else | |
1209 | /* whole lits of sub-tree */ | |
1210 | rc = add_matching_lines(tb, tt, direction); | |
fdedb45e KZ |
1211 | |
1212 | /* | |
32e5466a | 1213 | * Print the output table for non-poll modes |
fdedb45e | 1214 | */ |
32e5466a | 1215 | if (!rc && !(flags & FL_POLL)) |
049caefd | 1216 | tt_print_table(tt); |
fdedb45e KZ |
1217 | leave: |
1218 | tt_free_table(tt); | |
1219 | ||
68164f6c | 1220 | mnt_free_table(tb); |
04fd7a9f | 1221 | mnt_free_cache(cache); |
8c5eba3e | 1222 | free(tabfiles); |
04fd7a9f | 1223 | |
049caefd | 1224 | return rc ? EXIT_FAILURE : EXIT_SUCCESS; |
04fd7a9f | 1225 | } |