]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libmount/src/tab_update.c
libmount: don't support /etc/mtab by default
[thirdparty/util-linux.git] / libmount / src / tab_update.c
CommitLineData
6c40a53d
KZ
1/*
2 * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
3 *
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
6 */
7
8/**
30493710 9 * SECTION: update
63de90d4
KZ
10 * @title: Tables update
11 * @short_description: userspace mount information management
0f32f1e2 12 *
d58b3157
OO
13 * The struct libmnt_update provides an abstraction to manage mount options in
14 * userspace independently of system configuration. This low-level API works on
15 * systems both with and without /etc/mtab. On systems without the regular /etc/mtab
16 * file, the userspace mount options (e.g. user=) are stored in the /run/mount/utab
63de90d4 17 * file.
0f32f1e2 18 *
68164f6c 19 * It's recommended to use high-level struct libmnt_context API.
6c40a53d 20 */
1d0cd73f
KZ
21#include <sys/file.h>
22#include <fcntl.h>
8f60ea34 23#include <signal.h>
6c40a53d 24
6c40a53d
KZ
25#include "mountP.h"
26#include "mangle.h"
27#include "pathnames.h"
28
68164f6c 29struct libmnt_update {
1d0cd73f 30 char *target;
68164f6c 31 struct libmnt_fs *fs;
77417bc0 32 char *filename;
1d0cd73f
KZ
33 unsigned long mountflags;
34 int userspace_only;
35 int ready;
c4c66355
KZ
36
37 struct libmnt_table *mountinfo;
6c40a53d
KZ
38};
39
c4c66355
KZ
40static int set_fs_root(struct libmnt_update *upd, struct libmnt_fs *fs, unsigned long mountflags);
41static int utab_new_entry(struct libmnt_update *upd, struct libmnt_fs *fs, unsigned long mountflags);
1d0cd73f 42
6c40a53d 43/**
30493710 44 * mnt_new_update:
6c40a53d 45 *
1d0cd73f 46 * Returns: newly allocated update handler
6c40a53d 47 */
68164f6c 48struct libmnt_update *mnt_new_update(void)
6c40a53d 49{
68164f6c 50 struct libmnt_update *upd;
6c40a53d 51
68164f6c 52 upd = calloc(1, sizeof(*upd));
30493710 53 if (!upd)
6c40a53d
KZ
54 return NULL;
55
83a78332 56 DBG(UPDATE, ul_debugobj(upd, "allocate"));
30493710 57 return upd;
6c40a53d
KZ
58}
59
60/**
30493710
KZ
61 * mnt_free_update:
62 * @upd: update
6c40a53d 63 *
68164f6c 64 * Deallocates struct libmnt_update handler.
6c40a53d 65 */
68164f6c 66void mnt_free_update(struct libmnt_update *upd)
6c40a53d 67{
30493710 68 if (!upd)
6c40a53d
KZ
69 return;
70
83a78332 71 DBG(UPDATE, ul_debugobj(upd, "free"));
6c40a53d 72
26d0c0ae 73 mnt_unref_fs(upd->fs);
c9f1585e 74 mnt_unref_table(upd->mountinfo);
1d0cd73f 75 free(upd->target);
77417bc0 76 free(upd->filename);
30493710 77 free(upd);
6c40a53d
KZ
78}
79
77417bc0 80/*
6f5788c5 81 * Returns 0 on success, <0 in case of error.
77417bc0 82 */
c570f567
KZ
83int mnt_update_set_filename(struct libmnt_update *upd, const char *filename,
84 int userspace_only)
77417bc0
KZ
85{
86 const char *path = NULL;
87 int rw = 0;
88
ba2bdf41
KZ
89 if (!upd)
90 return -EINVAL;
77417bc0
KZ
91
92 /* filename explicitly defined */
93 if (filename) {
94 char *p = strdup(filename);
95 if (!p)
96 return -ENOMEM;
97
98 upd->userspace_only = userspace_only;
99 free(upd->filename);
100 upd->filename = p;
101 }
102
103 if (upd->filename)
104 return 0;
105
a362ae60 106 /* detect tab filename -- /etc/mtab or /run/mount/utab
77417bc0 107 */
e778642a 108#ifdef USE_LIBMOUNT_SUPPORT_MTAB
77417bc0 109 mnt_has_regular_mtab(&path, &rw);
e778642a 110#endif
77417bc0
KZ
111 if (!rw) {
112 path = NULL;
113 mnt_has_regular_utab(&path, &rw);
114 if (!rw)
6f5788c5 115 return -EACCES;
77417bc0
KZ
116 upd->userspace_only = TRUE;
117 }
118 upd->filename = strdup(path);
119 if (!upd->filename)
120 return -ENOMEM;
121
122 return 0;
123}
124
36bda5cb
KZ
125/**
126 * mnt_update_get_filename:
127 * @upd: update
128 *
d58b3157 129 * This function returns the file name (e.g. /etc/mtab) of the up-dated file.
36bda5cb
KZ
130 *
131 * Returns: pointer to filename that will be updated or NULL in case of error.
132 */
68164f6c 133const char *mnt_update_get_filename(struct libmnt_update *upd)
36bda5cb 134{
86cd5870 135 return upd ? upd->filename : NULL;
36bda5cb
KZ
136}
137
6c40a53d 138/**
1d0cd73f
KZ
139 * mnt_update_is_ready:
140 * @upd: update handler
d300992d 141 *
1d0cd73f 142 * Returns: 1 if entry described by @upd is successfully prepared and will be
d58b3157 143 * written to the mtab/utab file.
d300992d 144 */
68164f6c 145int mnt_update_is_ready(struct libmnt_update *upd)
d300992d 146{
1d0cd73f 147 return upd ? upd->ready : FALSE;
6c40a53d
KZ
148}
149
6c40a53d 150/**
30493710 151 * mnt_update_set_fs:
1d0cd73f
KZ
152 * @upd: update handler
153 * @mountflags: MS_* flags
f12aac6e 154 * @target: umount target, must be NULL for mount
2915bdc0 155 * @fs: mount filesystem description, must be NULL for umount
d300992d 156 *
6f5788c5 157 * Returns: <0 in case on error, 0 on success, 1 if update is unnecessary.
6c40a53d 158 */
68164f6c
KZ
159int mnt_update_set_fs(struct libmnt_update *upd, unsigned long mountflags,
160 const char *target, struct libmnt_fs *fs)
6c40a53d 161{
77417bc0
KZ
162 int rc;
163
30493710 164 if (!upd)
3a5b1b1d 165 return -EINVAL;
2915bdc0
KZ
166 if ((mountflags & MS_MOVE) && (!fs || !mnt_fs_get_srcpath(fs)))
167 return -EINVAL;
168 if (target && fs)
169 return -EINVAL;
6c40a53d 170
83a78332 171 DBG(UPDATE, ul_debugobj(upd,
26e42d81 172 "resetting FS [fs=0x%p, target=%s, flags=0x%08lx]",
1d0cd73f 173 fs, target, mountflags));
87a07a4c 174 if (fs) {
83a78332 175 DBG(UPDATE, ul_debugobj(upd, "FS template:"));
87a07a4c
KZ
176 DBG(UPDATE, mnt_fs_print_debug(fs, stderr));
177 }
6c40a53d 178
26d0c0ae 179 mnt_unref_fs(upd->fs);
1d0cd73f
KZ
180 free(upd->target);
181 upd->ready = FALSE;
182 upd->fs = NULL;
183 upd->target = NULL;
36bda5cb
KZ
184 upd->mountflags = 0;
185
186 if (mountflags & MS_PROPAGATION)
187 return 1;
188
1d0cd73f 189 upd->mountflags = mountflags;
6c40a53d 190
77417bc0 191 rc = mnt_update_set_filename(upd, NULL, 0);
6f5788c5 192 if (rc) {
83a78332 193 DBG(UPDATE, ul_debugobj(upd, "no writable file available [rc=%d]", rc));
77417bc0 194 return rc; /* error or no file available (rc = 1) */
6f5788c5 195 }
2915bdc0
KZ
196 if (target) {
197 upd->target = strdup(target);
198 if (!upd->target)
199 return -ENOMEM;
200
201 } else if (fs) {
1d0cd73f 202 if (upd->userspace_only && !(mountflags & MS_MOVE)) {
8228372b 203 rc = utab_new_entry(upd, fs, mountflags);
1d0cd73f
KZ
204 if (rc)
205 return rc;
206 } else {
f84fa6f7 207 upd->fs = mnt_copy_mtab_fs(fs);
1d0cd73f
KZ
208 if (!upd->fs)
209 return -ENOMEM;
f84fa6f7 210
1d0cd73f
KZ
211 }
212 }
6c40a53d 213
1d0cd73f 214
83a78332 215 DBG(UPDATE, ul_debugobj(upd, "ready"));
1d0cd73f 216 upd->ready = TRUE;
7714c689 217 return 0;
6c40a53d
KZ
218}
219
36bda5cb 220/**
f84fa6f7
KZ
221 * mnt_update_get_fs:
222 * @upd: update
223 *
224 * Returns: update filesystem entry or NULL
97e23b5e 225 */
68164f6c 226struct libmnt_fs *mnt_update_get_fs(struct libmnt_update *upd)
97e23b5e
KZ
227{
228 return upd ? upd->fs : NULL;
229}
1d0cd73f 230
36bda5cb 231/**
68164f6c 232 * mnt_update_get_mflags:
36bda5cb
KZ
233 * @upd: update
234 *
235 * Returns: mount flags as was set by mnt_update_set_fs()
236 */
68164f6c 237unsigned long mnt_update_get_mflags(struct libmnt_update *upd)
36bda5cb
KZ
238{
239 return upd ? upd->mountflags : 0;
240}
241
242/**
243 * mnt_update_force_rdonly:
244 * @upd: update
245 * @rdonly: is read-only?
246 *
247 * Returns: 0 on success and negative number in case of error.
248 */
68164f6c 249int mnt_update_force_rdonly(struct libmnt_update *upd, int rdonly)
36bda5cb
KZ
250{
251 int rc = 0;
252
253 if (!upd || !upd->fs)
254 return -EINVAL;
255
256 if (rdonly && (upd->mountflags & MS_RDONLY))
257 return 0;
258 if (!rdonly && !(upd->mountflags & MS_RDONLY))
259 return 0;
260
261 if (!upd->userspace_only) {
262 /* /etc/mtab -- we care about VFS options there */
f2b3a3a3 263 const char *o = mnt_fs_get_options(upd->fs);
36bda5cb
KZ
264 char *n = o ? strdup(o) : NULL;
265
266 if (n)
267 mnt_optstr_remove_option(&n, rdonly ? "rw" : "ro");
268 if (!mnt_optstr_prepend_option(&n, rdonly ? "ro" : "rw", NULL))
f2b3a3a3 269 rc = mnt_fs_set_options(upd->fs, n);
36bda5cb
KZ
270
271 free(n);
272 }
273
274 if (rdonly)
275 upd->mountflags &= ~MS_RDONLY;
276 else
277 upd->mountflags |= MS_RDONLY;
278
279 return rc;
280}
281
7e0c0619 282
6c40a53d 283/*
d58b3157 284 * Allocates an utab entry (upd->fs) for mount/remount. This function should be
c4c66355 285 * called *before* mount(2) syscall. The @fs is used as a read-only template.
1d0cd73f 286 *
d58b3157 287 * Returns: 0 on success, negative number on error, 1 if utab's update is
1d0cd73f 288 * unnecessary.
6c40a53d 289 */
c4c66355
KZ
290static int utab_new_entry(struct libmnt_update *upd, struct libmnt_fs *fs,
291 unsigned long mountflags)
6c40a53d 292{
1d0cd73f 293 int rc = 0;
76a06ca4 294 const char *o = NULL, *a = NULL;
f84fa6f7 295 char *u = NULL;
6c40a53d
KZ
296
297 assert(fs);
c4c66355
KZ
298 assert(upd);
299 assert(upd->fs == NULL);
1d0cd73f 300 assert(!(mountflags & MS_MOVE));
6c40a53d 301
83a78332 302 DBG(UPDATE, ul_debug("prepare utab entry"));
6c40a53d 303
68164f6c 304 o = mnt_fs_get_user_options(fs);
76a06ca4 305 a = mnt_fs_get_attributes(fs);
c4c66355 306 upd->fs = NULL;
76a06ca4 307
f84fa6f7
KZ
308 if (o) {
309 /* remove non-mtab options */
310 rc = mnt_optstr_get_options(o, &u,
311 mnt_get_builtin_optmap(MNT_USERSPACE_MAP),
312 MNT_NOMTAB);
313 if (rc)
314 goto err;
315 }
316
317 if (!u && !a) {
83a78332 318 DBG(UPDATE, ul_debug("utab entry unnecessary (no options)"));
f84fa6f7
KZ
319 return 1;
320 }
1d0cd73f
KZ
321
322 /* allocate the entry */
c4c66355
KZ
323 upd->fs = mnt_copy_fs(NULL, fs);
324 if (!upd->fs) {
1d0cd73f
KZ
325 rc = -ENOMEM;
326 goto err;
6c40a53d
KZ
327 }
328
c4c66355 329 rc = mnt_fs_set_options(upd->fs, u);
76a06ca4
KZ
330 if (rc)
331 goto err;
c4c66355 332 rc = mnt_fs_set_attributes(upd->fs, a);
1d0cd73f
KZ
333 if (rc)
334 goto err;
6c40a53d 335
1d0cd73f 336 if (!(mountflags & MS_REMOUNT)) {
c4c66355 337 rc = set_fs_root(upd, fs, mountflags);
1d0cd73f
KZ
338 if (rc)
339 goto err;
340 }
6c40a53d 341
f84fa6f7 342 free(u);
83a78332 343 DBG(UPDATE, ul_debug("utab entry OK"));
6c40a53d 344 return 0;
1d0cd73f 345err:
f84fa6f7 346 free(u);
26d0c0ae 347 mnt_unref_fs(upd->fs);
c4c66355 348 upd->fs = NULL;
1d0cd73f 349 return rc;
6c40a53d
KZ
350}
351
c4c66355
KZ
352/*
353 * Sets fs-root and fs-type to @upd->fs according to the @fs template and
d58b3157 354 * @mountfalgs. For MS_BIND mountflag it reads information about the source
c4c66355
KZ
355 * filesystem from /proc/self/mountinfo.
356 */
357static int set_fs_root(struct libmnt_update *upd, struct libmnt_fs *fs,
358 unsigned long mountflags)
6c40a53d 359{
c4c66355
KZ
360 struct libmnt_fs *src_fs;
361 char *fsroot = NULL;
e9cd2e2b 362 const char *src, *fstype;
c4c66355 363 int rc = 0;
1d0cd73f 364
83a78332 365 DBG(UPDATE, ul_debug("setting FS root"));
6c40a53d 366
c4c66355
KZ
367 assert(upd);
368 assert(upd->fs);
369 assert(fs);
6c40a53d 370
e9cd2e2b
KZ
371 fstype = mnt_fs_get_fstype(fs);
372
1d0cd73f 373 if (mountflags & MS_BIND) {
c4c66355
KZ
374 if (!upd->mountinfo)
375 upd->mountinfo = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO);
6c40a53d 376 src = mnt_fs_get_srcpath(fs);
dd369652 377 if (src) {
c4c66355
KZ
378 rc = mnt_fs_set_bindsrc(upd->fs, src);
379 if (rc)
380 goto err;
f84fa6f7 381 }
e9cd2e2b
KZ
382
383 } else if (fstype && (strcmp(fstype, "btrfs") == 0 || strcmp(fstype, "auto") == 0)) {
384 if (!upd->mountinfo)
385 upd->mountinfo = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO);
c4c66355 386 }
6c40a53d 387
c4c66355
KZ
388 src_fs = mnt_table_get_fs_root(upd->mountinfo, fs,
389 mountflags, &fsroot);
390 if (src_fs) {
6c40a53d 391 src = mnt_fs_get_srcpath(src_fs);
c4c66355 392 rc = mnt_fs_set_source(upd->fs, src);
dd369652
KZ
393 if (rc)
394 goto err;
6c40a53d 395
c4c66355 396 mnt_fs_set_fstype(upd->fs, mnt_fs_get_fstype(src_fs));
6c40a53d
KZ
397 }
398
c4c66355 399 upd->fs->root = fsroot;
6c40a53d
KZ
400 return 0;
401err:
c4c66355 402 free(fsroot);
1d0cd73f 403 return rc;
d300992d
KZ
404}
405
68af0bcc
KZ
406/* mtab and fstab update -- returns zero on success
407 */
68164f6c 408static int fprintf_mtab_fs(FILE *f, struct libmnt_fs *fs)
6c40a53d 409{
cb90e24e 410 const char *o, *src, *fstype, *comm;
1d0cd73f
KZ
411 char *m1, *m2, *m3, *m4;
412 int rc;
6c40a53d 413
1d0cd73f
KZ
414 assert(fs);
415 assert(f);
1b56aae8 416
cb90e24e 417 comm = mnt_fs_get_comment(fs);
b5962110
KZ
418 src = mnt_fs_get_source(fs);
419 fstype = mnt_fs_get_fstype(fs);
420 o = mnt_fs_get_options(fs);
76a06ca4 421
b5962110 422 m1 = src ? mangle(src) : "none";
1d0cd73f 423 m2 = mangle(mnt_fs_get_target(fs));
b5962110
KZ
424 m3 = fstype ? mangle(fstype) : "none";
425 m4 = o ? mangle(o) : "rw";
1b56aae8 426
68af0bcc 427 if (m1 && m2 && m3 && m4) {
cb90e24e
OO
428 if (comm)
429 fputs(comm, f);
68af0bcc 430 rc = fprintf(f, "%s %s %s %s %d %d\n",
1d0cd73f
KZ
431 m1, m2, m3, m4,
432 mnt_fs_get_freq(fs),
433 mnt_fs_get_passno(fs));
68af0bcc
KZ
434 if (rc > 0)
435 rc = 0;
436 } else
1d0cd73f 437 rc = -ENOMEM;
6c40a53d 438
b5962110
KZ
439 if (src)
440 free(m1);
1d0cd73f 441 free(m2);
b5962110
KZ
442 if (fstype)
443 free(m3);
444 if (o)
445 free(m4);
3a5b1b1d 446
1d0cd73f
KZ
447 return rc;
448}
6c40a53d 449
68164f6c 450static int fprintf_utab_fs(FILE *f, struct libmnt_fs *fs)
1d0cd73f 451{
dd369652 452 char *p;
68af0bcc 453 int rc = 0;
4e92d2b0 454
1d0cd73f
KZ
455 if (!fs || !f)
456 return -EINVAL;
dd369652
KZ
457
458 p = mangle(mnt_fs_get_source(fs));
459 if (p) {
68af0bcc 460 rc = fprintf(f, "SRC=%s ", p);
dd369652
KZ
461 free(p);
462 }
68af0bcc
KZ
463 if (rc >= 0) {
464 p = mangle(mnt_fs_get_target(fs));
465 if (p) {
466 rc = fprintf(f, "TARGET=%s ", p);
467 free(p);
468 }
dd369652 469 }
68af0bcc
KZ
470 if (rc >= 0) {
471 p = mangle(mnt_fs_get_root(fs));
472 if (p) {
473 rc = fprintf(f, "ROOT=%s ", p);
474 free(p);
475 }
dd369652 476 }
68af0bcc
KZ
477 if (rc >= 0) {
478 p = mangle(mnt_fs_get_bindsrc(fs));
479 if (p) {
480 rc = fprintf(f, "BINDSRC=%s ", p);
481 free(p);
482 }
dd369652 483 }
68af0bcc
KZ
484 if (rc >= 0) {
485 p = mangle(mnt_fs_get_attributes(fs));
486 if (p) {
487 rc = fprintf(f, "ATTRS=%s ", p);
488 free(p);
489 }
76a06ca4 490 }
68af0bcc
KZ
491 if (rc >= 0) {
492 p = mangle(mnt_fs_get_user_options(fs));
493 if (p) {
494 rc = fprintf(f, "OPTS=%s", p);
495 free(p);
496 }
dd369652 497 }
68af0bcc
KZ
498 if (rc >= 0)
499 rc = fprintf(f, "\n");
dd369652 500
68af0bcc
KZ
501 if (rc > 0)
502 rc = 0; /* success */
503 return rc;
6c40a53d
KZ
504}
505
68164f6c 506static int update_table(struct libmnt_update *upd, struct libmnt_table *tb)
6c40a53d
KZ
507{
508 FILE *f;
1d0cd73f
KZ
509 int rc, fd;
510 char *uq = NULL;
6c40a53d 511
77417bc0 512 if (!tb || !upd->filename)
1d0cd73f 513 return -EINVAL;
6c40a53d 514
83a78332 515 DBG(UPDATE, ul_debugobj(upd, "%s: updating", upd->filename));
3f31a959 516
4b6cf485 517 fd = mnt_open_uniq_filename(upd->filename, &uq);
1d0cd73f
KZ
518 if (fd < 0)
519 return fd; /* error */
520
1eb8539d 521 f = fdopen(fd, "w" UL_CLOEXECSTR);
6c40a53d 522 if (f) {
1d0cd73f 523 struct stat st;
68164f6c
KZ
524 struct libmnt_iter itr;
525 struct libmnt_fs *fs;
1d0cd73f
KZ
526
527 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
cb90e24e
OO
528
529 if (tb->comms && mnt_table_get_intro_comment(tb))
530 fputs(mnt_table_get_intro_comment(tb), f);
531
68164f6c 532 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
1d0cd73f 533 if (upd->userspace_only)
68af0bcc 534 rc = fprintf_utab_fs(f, fs);
1d0cd73f 535 else
68af0bcc
KZ
536 rc = fprintf_mtab_fs(f, fs);
537 if (rc) {
83a78332 538 DBG(UPDATE, ul_debugobj(upd,
68af0bcc
KZ
539 "%s: write entry failed: %m", uq));
540 goto leave;
541 }
542 }
3035ba93
OO
543 if (tb->comms && mnt_table_get_trailing_comment(tb))
544 fputs(mnt_table_get_trailing_comment(tb), f);
68af0bcc
KZ
545
546 if (fflush(f) != 0) {
547 rc = -errno;
83a78332 548 DBG(UPDATE, ul_debugobj(upd, "%s: fflush failed: %m", uq));
68af0bcc 549 goto leave;
1d0cd73f 550 }
68af0bcc 551
1d0cd73f
KZ
552 rc = fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) ? -errno : 0;
553
77417bc0 554 if (!rc && stat(upd->filename, &st) == 0)
1d0cd73f
KZ
555 /* Copy uid/gid from the present file before renaming. */
556 rc = fchown(fd, st.st_uid, st.st_gid) ? -errno : 0;
557
6c40a53d 558 fclose(f);
80140144 559 f = NULL;
a9ddf316
KZ
560
561 if (!rc)
562 rc = rename(uq, upd->filename) ? -errno : 0;
1d0cd73f
KZ
563 } else {
564 rc = -errno;
565 close(fd);
6c40a53d 566 }
1d0cd73f 567
68af0bcc 568leave:
80140144
KZ
569 if (f)
570 fclose(f);
571
1d0cd73f
KZ
572 unlink(uq); /* be paranoid */
573 free(uq);
6c40a53d
KZ
574 return rc;
575}
576
d22f2822
OO
577/**
578 * mnt_table_write_file
579 * @tb: parsed file (e.g. fstab)
580 * @file: target
581 *
582 * This function writes @tb to @file.
583 *
584 * Returns: 0 on success, negative number on error.
585 */
586int mnt_table_write_file(struct libmnt_table *tb, FILE *file)
587{
588 int rc = 0;
589 struct libmnt_iter itr;
590 struct libmnt_fs *fs;
591
592 if (tb->comms && mnt_table_get_intro_comment(tb))
593 fputs(mnt_table_get_intro_comment(tb), file);
594
595 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
596 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
597 rc = fprintf_mtab_fs(file, fs);
598 if (rc)
599 return rc;
600 }
3035ba93
OO
601 if (tb->comms && mnt_table_get_trailing_comment(tb))
602 fputs(mnt_table_get_trailing_comment(tb), file);
d22f2822
OO
603
604 if (fflush(file) != 0)
605 rc = -errno;
606
83a78332 607 DBG(TAB, ul_debugobj(tb, "write file done [rc=%d]", rc));
d22f2822
OO
608 return rc;
609}
610
611/**
612 * mnt_table_replace_file
613 * @tb: parsed file (e.g. fstab)
614 * @filename: target
615 *
d58b3157 616 * This function replaces @file by the new content from @tb.
d22f2822
OO
617 *
618 * Returns: 0 on success, negative number on error.
619 */
620int mnt_table_replace_file(struct libmnt_table *tb, const char *filename)
621{
622 int fd, rc = 0;
623 FILE *f;
624 char *uq = NULL;
625
83a78332 626 DBG(TAB, ul_debugobj(tb, "%s: replacing", filename));
d22f2822
OO
627
628 fd = mnt_open_uniq_filename(filename, &uq);
629 if (fd < 0)
630 return fd; /* error */
631
632 f = fdopen(fd, "w" UL_CLOEXECSTR);
633 if (f) {
634 struct stat st;
635
636 mnt_table_write_file(tb, f);
637
a84ec176
KZ
638 if (fflush(f) != 0) {
639 rc = -errno;
83a78332 640 DBG(UPDATE, ul_debug("%s: fflush failed: %m", uq));
a84ec176
KZ
641 goto leave;
642 }
643
d22f2822
OO
644 rc = fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) ? -errno : 0;
645
646 if (!rc && stat(filename, &st) == 0)
647 /* Copy uid/gid from the present file before renaming. */
648 rc = fchown(fd, st.st_uid, st.st_gid) ? -errno : 0;
649
650 fclose(f);
a84ec176
KZ
651 f = NULL;
652
d22f2822 653 if (!rc)
a84ec176 654 rc = rename(uq, filename) ? -errno : 0;
d22f2822
OO
655 } else {
656 rc = -errno;
657 close(fd);
658 }
659
a84ec176
KZ
660leave:
661 if (f)
662 fclose(f);
d22f2822
OO
663 unlink(uq);
664 free(uq);
665
83a78332 666 DBG(TAB, ul_debugobj(tb, "replace done [rc=%d]", rc));
d22f2822
OO
667 return rc;
668}
a84ec176 669
c3085df6
KZ
670static int add_file_entry(struct libmnt_table *tb, struct libmnt_update *upd)
671{
4569bbea
KZ
672 struct libmnt_fs *fs;
673
674 assert(upd);
c3085df6 675
4569bbea 676 fs = mnt_copy_fs(NULL, upd->fs);
c3085df6
KZ
677 if (!fs)
678 return -ENOMEM;
679
680 mnt_table_add_fs(tb, fs);
26d0c0ae
KZ
681 mnt_unref_fs(fs);
682
c3085df6
KZ
683 return update_table(upd, tb);
684}
685
68164f6c 686static int update_add_entry(struct libmnt_update *upd, struct libmnt_lock *lc)
6c40a53d 687{
68af0bcc 688 struct libmnt_table *tb;
8f60ea34 689 int rc = 0;
6c40a53d 690
30493710 691 assert(upd);
1d0cd73f 692 assert(upd->fs);
6c40a53d 693
83a78332 694 DBG(UPDATE, ul_debugobj(upd, "%s: add entry", upd->filename));
6c40a53d 695
86cd5870 696 if (lc)
8f60ea34
KZ
697 rc = mnt_lock_file(lc);
698 if (rc)
699 return rc;
6c40a53d 700
68af0bcc
KZ
701 tb = __mnt_new_table_from_file(upd->filename,
702 upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
c3085df6
KZ
703 if (tb)
704 rc = add_file_entry(tb, upd);
86cd5870 705 if (lc)
1d0cd73f 706 mnt_unlock_file(lc);
68af0bcc 707
c9f1585e 708 mnt_unref_table(tb);
1d0cd73f
KZ
709 return rc;
710}
6c40a53d 711
68164f6c 712static int update_remove_entry(struct libmnt_update *upd, struct libmnt_lock *lc)
1d0cd73f 713{
68164f6c 714 struct libmnt_table *tb;
8f60ea34 715 int rc = 0;
6c40a53d 716
1d0cd73f
KZ
717 assert(upd);
718 assert(upd->target);
719
83a78332 720 DBG(UPDATE, ul_debugobj(upd, "%s: remove entry", upd->filename));
1d0cd73f 721
86cd5870 722 if (lc)
8f60ea34
KZ
723 rc = mnt_lock_file(lc);
724 if (rc)
725 return rc;
1d0cd73f 726
68164f6c 727 tb = __mnt_new_table_from_file(upd->filename,
dd369652 728 upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
1d0cd73f 729 if (tb) {
68164f6c 730 struct libmnt_fs *rem = mnt_table_find_target(tb, upd->target, MNT_ITER_BACKWARD);
1d0cd73f 731 if (rem) {
68164f6c
KZ
732 mnt_table_remove_fs(tb, rem);
733 rc = update_table(upd, tb);
1d0cd73f 734 }
1d0cd73f 735 }
86cd5870 736 if (lc)
1d0cd73f 737 mnt_unlock_file(lc);
6f5788c5 738
c9f1585e 739 mnt_unref_table(tb);
6c40a53d
KZ
740 return rc;
741}
742
68164f6c 743static int update_modify_target(struct libmnt_update *upd, struct libmnt_lock *lc)
6c40a53d 744{
68164f6c 745 struct libmnt_table *tb = NULL;
8f60ea34 746 int rc = 0;
1d0cd73f 747
4569bbea 748 assert(upd);
83a78332 749 DBG(UPDATE, ul_debugobj(upd, "%s: modify target", upd->filename));
1d0cd73f 750
86cd5870 751 if (lc)
8f60ea34
KZ
752 rc = mnt_lock_file(lc);
753 if (rc)
754 return rc;
1d0cd73f 755
68164f6c 756 tb = __mnt_new_table_from_file(upd->filename,
dd369652 757 upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
1d0cd73f 758 if (tb) {
68164f6c 759 struct libmnt_fs *cur = mnt_table_find_target(tb,
2915bdc0 760 mnt_fs_get_srcpath(upd->fs), MNT_ITER_BACKWARD);
1d0cd73f
KZ
761 if (cur) {
762 rc = mnt_fs_set_target(cur, mnt_fs_get_target(upd->fs));
763 if (!rc)
68164f6c 764 rc = update_table(upd, tb);
1d0cd73f 765 }
1d0cd73f 766 }
8f60ea34 767
86cd5870 768 if (lc)
1d0cd73f 769 mnt_unlock_file(lc);
6f5788c5 770
c9f1585e 771 mnt_unref_table(tb);
1d0cd73f
KZ
772 return rc;
773}
6c40a53d 774
68164f6c 775static int update_modify_options(struct libmnt_update *upd, struct libmnt_lock *lc)
1d0cd73f 776{
68164f6c 777 struct libmnt_table *tb = NULL;
8f60ea34 778 int rc = 0;
68164f6c 779 struct libmnt_fs *fs;
6c40a53d 780
1d0cd73f
KZ
781 assert(upd);
782 assert(upd->fs);
6c40a53d 783
83a78332 784 DBG(UPDATE, ul_debugobj(upd, "%s: modify options", upd->filename));
1d0cd73f 785
76a06ca4
KZ
786 fs = upd->fs;
787
86cd5870 788 if (lc)
8f60ea34
KZ
789 rc = mnt_lock_file(lc);
790 if (rc)
791 return rc;
1d0cd73f 792
68164f6c 793 tb = __mnt_new_table_from_file(upd->filename,
dd369652 794 upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
1d0cd73f 795 if (tb) {
68164f6c 796 struct libmnt_fs *cur = mnt_table_find_target(tb,
76a06ca4 797 mnt_fs_get_target(fs),
1d0cd73f
KZ
798 MNT_ITER_BACKWARD);
799 if (cur) {
76a06ca4
KZ
800 if (upd->userspace_only)
801 rc = mnt_fs_set_attributes(cur, mnt_fs_get_attributes(fs));
76a06ca4 802 if (!rc)
f2b3a3a3 803 rc = mnt_fs_set_options(cur, mnt_fs_get_options(fs));
1d0cd73f 804 if (!rc)
68164f6c 805 rc = update_table(upd, tb);
c3085df6
KZ
806 } else
807 rc = add_file_entry(tb, upd); /* not found, add new */
6c40a53d 808 }
76a06ca4 809
86cd5870 810 if (lc)
1d0cd73f 811 mnt_unlock_file(lc);
6f5788c5 812
c9f1585e 813 mnt_unref_table(tb);
6c40a53d
KZ
814 return rc;
815}
816
817/**
68164f6c 818 * mnt_update_table:
0f32f1e2 819 * @upd: update
5976114f 820 * @lc: lock or NULL
6c40a53d 821 *
a362ae60 822 * High-level API to update /etc/mtab (or private /run/mount/utab file).
6c40a53d 823 *
5976114f 824 * The @lc lock is optional and will be created if necessary. Note that
d58b3157 825 * an automatically created lock blocks all signals.
5976114f
KZ
826 *
827 * See also mnt_lock_block_signals() and mnt_context_get_lock().
828 *
1d0cd73f 829 * Returns: 0 on success, negative number on error.
6c40a53d 830 */
68164f6c 831int mnt_update_table(struct libmnt_update *upd, struct libmnt_lock *lc)
6c40a53d 832{
c570f567 833 struct libmnt_lock *lc0 = lc;
1d0cd73f
KZ
834 int rc = -EINVAL;
835
8726371f 836 if (!upd || !upd->filename)
1d0cd73f
KZ
837 return -EINVAL;
838 if (!upd->ready)
d300992d 839 return 0;
6c40a53d 840
83a78332 841 DBG(UPDATE, ul_debugobj(upd, "%s: update tab", upd->filename));
f84fa6f7
KZ
842 if (upd->fs) {
843 DBG(UPDATE, mnt_fs_print_debug(upd->fs, stderr));
844 }
86cd5870 845 if (!lc) {
c570f567 846 lc = mnt_new_lock(upd->filename, 0);
5976114f
KZ
847 if (lc)
848 mnt_lock_block_signals(lc, TRUE);
849 }
86cd5870
KZ
850 if (lc && upd->userspace_only)
851 mnt_lock_use_simplelock(lc, TRUE); /* use flock */
c570f567 852
1d0cd73f 853 if (!upd->fs && upd->target)
77417bc0 854 rc = update_remove_entry(upd, lc); /* umount */
1d0cd73f 855 else if (upd->mountflags & MS_MOVE)
77417bc0 856 rc = update_modify_target(upd, lc); /* move */
1d0cd73f 857 else if (upd->mountflags & MS_REMOUNT)
77417bc0 858 rc = update_modify_options(upd, lc); /* remount */
1d0cd73f 859 else if (upd->fs)
77417bc0 860 rc = update_add_entry(upd, lc); /* mount */
1d0cd73f
KZ
861
862 upd->ready = FALSE;
83a78332 863 DBG(UPDATE, ul_debugobj(upd, "%s: update tab: done [rc=%d]",
77417bc0 864 upd->filename, rc));
c570f567
KZ
865 if (lc != lc0)
866 mnt_free_lock(lc);
1d0cd73f 867 return rc;
6c40a53d
KZ
868}
869
7e0c0619
KZ
870int mnt_update_already_done(struct libmnt_update *upd, struct libmnt_lock *lc)
871{
872 struct libmnt_table *tb = NULL;
873 struct libmnt_lock *lc0 = lc;
874 int rc = 0;
875
876 if (!upd || !upd->filename || (!upd->fs && !upd->target))
877 return -EINVAL;
878
83a78332 879 DBG(UPDATE, ul_debugobj(upd, "%s: checking for previous update", upd->filename));
7e0c0619
KZ
880
881 if (!lc) {
882 lc = mnt_new_lock(upd->filename, 0);
883 if (lc)
884 mnt_lock_block_signals(lc, TRUE);
885 }
886 if (lc && upd->userspace_only)
887 mnt_lock_use_simplelock(lc, TRUE); /* use flock */
888 if (lc)
889 rc = mnt_lock_file(lc);
890 if (rc)
891 goto done;
892
893 tb = __mnt_new_table_from_file(upd->filename,
894 upd->userspace_only ? MNT_FMT_UTAB : MNT_FMT_MTAB);
895 if (lc)
896 mnt_unlock_file(lc);
897 if (!tb)
898 goto done;
899
900 if (upd->fs) {
901 /* mount */
902 const char *tgt = mnt_fs_get_target(upd->fs);
903 const char *src = mnt_fs_get_bindsrc(upd->fs) ?
904 mnt_fs_get_bindsrc(upd->fs) :
905 mnt_fs_get_source(upd->fs);
906
907 if (mnt_table_find_pair(tb, src, tgt, MNT_ITER_BACKWARD)) {
83a78332 908 DBG(UPDATE, ul_debugobj(upd, "%s: found %s %s",
7e0c0619
KZ
909 upd->filename, src, tgt));
910 rc = 1;
911 }
912 } else if (upd->target) {
913 /* umount */
914 if (!mnt_table_find_target(tb, upd->target, MNT_ITER_BACKWARD)) {
83a78332 915 DBG(UPDATE, ul_debugobj(upd, "%s: not-found (umounted) %s",
7e0c0619
KZ
916 upd->filename, upd->target));
917 rc = 1;
918 }
919 }
920
921 mnt_unref_table(tb);
922done:
923 if (lc && lc != lc0)
924 mnt_free_lock(lc);
83a78332 925 DBG(UPDATE, ul_debugobj(upd, "%s: previous update check done [rc=%d]",
7e0c0619
KZ
926 upd->filename, rc));
927 return rc;
928}
929
930
6c40a53d
KZ
931#ifdef TEST_PROGRAM
932
68164f6c 933static int update(const char *target, struct libmnt_fs *fs, unsigned long mountflags)
6c40a53d 934{
36bda5cb 935 int rc;
68164f6c 936 struct libmnt_update *upd;
6c40a53d 937
83a78332 938 DBG(UPDATE, ul_debug("update test"));
3a5b1b1d 939
77417bc0
KZ
940 upd = mnt_new_update();
941 if (!upd)
942 return -ENOMEM;
7714c689 943
1d0cd73f 944 rc = mnt_update_set_fs(upd, mountflags, target, fs);
1d0cd73f 945 if (rc == 1) {
7c118af7 946 /* update is unnecessary */
1d0cd73f
KZ
947 rc = 0;
948 goto done;
949 }
7c118af7
KZ
950 if (rc) {
951 fprintf(stderr, "failed to set FS\n");
952 goto done;
953 }
30493710 954
d58b3157 955 /* [... mount(2) call should be here...] */
30493710 956
5976114f 957 rc = mnt_update_table(upd, NULL);
1d0cd73f 958done:
8dece036 959 mnt_free_update(upd);
30493710
KZ
960 return rc;
961}
962
68164f6c 963static int test_add(struct libmnt_test *ts, int argc, char *argv[])
30493710 964{
68164f6c 965 struct libmnt_fs *fs = mnt_new_fs();
1d0cd73f 966 int rc;
30493710 967
1d0cd73f 968 if (argc < 5 || !fs)
30493710
KZ
969 return -1;
970 mnt_fs_set_source(fs, argv[1]);
971 mnt_fs_set_target(fs, argv[2]);
972 mnt_fs_set_fstype(fs, argv[3]);
76a06ca4 973 mnt_fs_set_options(fs, argv[4]);
30493710 974
1d0cd73f 975 rc = update(NULL, fs, 0);
26d0c0ae 976 mnt_unref_fs(fs);
6c40a53d
KZ
977 return rc;
978}
979
68164f6c 980static int test_remove(struct libmnt_test *ts, int argc, char *argv[])
6c40a53d 981{
1d0cd73f 982 if (argc < 2)
6c40a53d 983 return -1;
1d0cd73f 984 return update(argv[1], NULL, 0);
6c40a53d
KZ
985}
986
68164f6c 987static int test_move(struct libmnt_test *ts, int argc, char *argv[])
6c40a53d 988{
68164f6c 989 struct libmnt_fs *fs = mnt_new_fs();
1d0cd73f 990 int rc;
6c40a53d 991
1d0cd73f 992 if (argc < 3)
6c40a53d 993 return -1;
25bca458 994 mnt_fs_set_source(fs, argv[1]);
7714c689 995 mnt_fs_set_target(fs, argv[2]);
25bca458
KZ
996
997 rc = update(NULL, fs, MS_MOVE);
7714c689 998
26d0c0ae 999 mnt_unref_fs(fs);
6c40a53d
KZ
1000 return rc;
1001}
1002
68164f6c 1003static int test_remount(struct libmnt_test *ts, int argc, char *argv[])
6c40a53d 1004{
68164f6c 1005 struct libmnt_fs *fs = mnt_new_fs();
1d0cd73f 1006 int rc;
6c40a53d 1007
1d0cd73f 1008 if (argc < 3)
6c40a53d 1009 return -1;
7714c689 1010 mnt_fs_set_target(fs, argv[1]);
76a06ca4 1011 mnt_fs_set_options(fs, argv[2]);
7714c689 1012
1d0cd73f 1013 rc = update(NULL, fs, MS_REMOUNT);
26d0c0ae 1014 mnt_unref_fs(fs);
6c40a53d
KZ
1015 return rc;
1016}
1017
d22f2822
OO
1018static int test_replace(struct libmnt_test *ts, int argc, char *argv[])
1019{
1020 struct libmnt_fs *fs = mnt_new_fs();
1021 struct libmnt_table *tb = mnt_new_table();
1022 int rc;
1023
1024 if (argc < 3)
1025 return -1;
1026
1027 mnt_table_enable_comments(tb, TRUE);
1028 mnt_table_parse_fstab(tb, NULL);
1029
1030 mnt_fs_set_source(fs, argv[1]);
1031 mnt_fs_set_target(fs, argv[2]);
1032 mnt_fs_append_comment(fs, "# this is new filesystem\n");
26d0c0ae 1033
d22f2822 1034 mnt_table_add_fs(tb, fs);
26d0c0ae 1035 mnt_unref_fs(fs);
d22f2822
OO
1036
1037 rc = mnt_table_replace_file(tb, mnt_get_fstab_path());
c9f1585e 1038 mnt_unref_table(tb);
d22f2822
OO
1039 return rc;
1040}
1041
6c40a53d
KZ
1042int main(int argc, char *argv[])
1043{
68164f6c 1044 struct libmnt_test tss[] = {
d58b3157 1045 { "--add", test_add, "<src> <target> <type> <options> add a line to mtab" },
6c40a53d
KZ
1046 { "--remove", test_remove, "<target> MS_REMOUNT mtab change" },
1047 { "--move", test_move, "<old_target> <target> MS_MOVE mtab change" },
1048 { "--remount",test_remount, "<target> <options> MS_REMOUNT mtab change" },
d22f2822 1049 { "--replace",test_replace, "<src> <target> Add a line to LIBMOUNT_FSTAB and replace the original file" },
6c40a53d
KZ
1050 { NULL }
1051 };
1052
1053 return mnt_run_test(tss, argc, argv);
1054}
1055
1056#endif /* TEST_PROGRAM */