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