]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libmount/src/tab_update.c
taskset: Accept 0 pid for current process
[thirdparty/util-linux.git] / libmount / src / tab_update.c
CommitLineData
2c37ca7c 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
6c40a53d 2/*
2c37ca7c 3 * This file is part of libmount from util-linux project.
6c40a53d 4 *
2c37ca7c
KZ
5 * Copyright (C) 2011-2018 Karel Zak <kzak@redhat.com>
6 *
7 * libmount is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
6c40a53d
KZ
11 */
12
13/**
30493710 14 * SECTION: update
63de90d4
KZ
15 * @title: Tables update
16 * @short_description: userspace mount information management
0f32f1e2 17 *
d58b3157 18 * The struct libmnt_update provides an abstraction to manage mount options in
e9d52e6e
KZ
19 * userspace independently of system configuration. The userspace mount options
20 * (e.g. user=) are stored in the /run/mount/utab file.
0f32f1e2 21 *
68164f6c 22 * It's recommended to use high-level struct libmnt_context API.
6c40a53d 23 */
1d0cd73f
KZ
24#include <sys/file.h>
25#include <fcntl.h>
8f60ea34 26#include <signal.h>
6c40a53d 27
6c40a53d
KZ
28#include "mountP.h"
29#include "mangle.h"
30#include "pathnames.h"
a04149fb 31#include "strutils.h"
6c40a53d 32
68164f6c 33struct libmnt_update {
1d0cd73f 34 char *target;
68164f6c 35 struct libmnt_fs *fs;
77417bc0 36 char *filename;
1d0cd73f 37 unsigned long mountflags;
477401f0 38
9218c967
KZ
39 int act_fd;
40 char *act_filename;
41
477401f0
KZ
42 unsigned int ready : 1,
43 missing_options : 1;
c4c66355
KZ
44
45 struct libmnt_table *mountinfo;
b94b5929 46 struct libmnt_lock *lock;
6c40a53d
KZ
47};
48
c4c66355
KZ
49static int set_fs_root(struct libmnt_update *upd, struct libmnt_fs *fs, unsigned long mountflags);
50static int utab_new_entry(struct libmnt_update *upd, struct libmnt_fs *fs, unsigned long mountflags);
1d0cd73f 51
6c40a53d 52/**
30493710 53 * mnt_new_update:
6c40a53d 54 *
1d0cd73f 55 * Returns: newly allocated update handler
6c40a53d 56 */
68164f6c 57struct libmnt_update *mnt_new_update(void)
6c40a53d 58{
68164f6c 59 struct libmnt_update *upd;
6c40a53d 60
68164f6c 61 upd = calloc(1, sizeof(*upd));
30493710 62 if (!upd)
6c40a53d
KZ
63 return NULL;
64
9218c967 65 upd->act_fd = -1;
83a78332 66 DBG(UPDATE, ul_debugobj(upd, "allocate"));
30493710 67 return upd;
6c40a53d
KZ
68}
69
70/**
30493710
KZ
71 * mnt_free_update:
72 * @upd: update
6c40a53d 73 *
68164f6c 74 * Deallocates struct libmnt_update handler.
6c40a53d 75 */
68164f6c 76void mnt_free_update(struct libmnt_update *upd)
6c40a53d 77{
30493710 78 if (!upd)
6c40a53d
KZ
79 return;
80
83a78332 81 DBG(UPDATE, ul_debugobj(upd, "free"));
6c40a53d 82
b94b5929 83 mnt_unref_lock(upd->lock);
26d0c0ae 84 mnt_unref_fs(upd->fs);
c9f1585e 85 mnt_unref_table(upd->mountinfo);
9218c967
KZ
86 if (upd->act_fd >= 0)
87 close(upd->act_fd);
1d0cd73f 88 free(upd->target);
77417bc0 89 free(upd->filename);
9218c967 90 free(upd->act_filename);
30493710 91 free(upd);
6c40a53d
KZ
92}
93
77417bc0 94/*
6f5788c5 95 * Returns 0 on success, <0 in case of error.
77417bc0 96 */
e9d52e6e 97int mnt_update_set_filename(struct libmnt_update *upd, const char *filename)
77417bc0
KZ
98{
99 const char *path = NULL;
100 int rw = 0;
101
ba2bdf41
KZ
102 if (!upd)
103 return -EINVAL;
77417bc0
KZ
104
105 /* filename explicitly defined */
106 if (filename) {
107 char *p = strdup(filename);
108 if (!p)
109 return -ENOMEM;
110
77417bc0
KZ
111 free(upd->filename);
112 upd->filename = p;
113 }
114
115 if (upd->filename)
116 return 0;
117
e9d52e6e 118 /* detect tab filename -- /run/mount/utab
77417bc0 119 */
7f56e412
KZ
120 path = NULL;
121 mnt_has_regular_utab(&path, &rw);
122 if (!rw)
123 return -EACCES;
77417bc0
KZ
124 upd->filename = strdup(path);
125 if (!upd->filename)
126 return -ENOMEM;
127
128 return 0;
129}
130
36bda5cb
KZ
131/**
132 * mnt_update_get_filename:
133 * @upd: update
134 *
e9d52e6e 135 * This function returns the file name of the up-dated file.
36bda5cb
KZ
136 *
137 * Returns: pointer to filename that will be updated or NULL in case of error.
138 */
68164f6c 139const char *mnt_update_get_filename(struct libmnt_update *upd)
36bda5cb 140{
86cd5870 141 return upd ? upd->filename : NULL;
36bda5cb
KZ
142}
143
6c40a53d 144/**
1d0cd73f
KZ
145 * mnt_update_is_ready:
146 * @upd: update handler
d300992d 147 *
1d0cd73f 148 * Returns: 1 if entry described by @upd is successfully prepared and will be
e9d52e6e 149 * written to the utab file.
d300992d 150 */
68164f6c 151int mnt_update_is_ready(struct libmnt_update *upd)
d300992d 152{
1d0cd73f 153 return upd ? upd->ready : FALSE;
6c40a53d
KZ
154}
155
6c40a53d 156/**
30493710 157 * mnt_update_set_fs:
1d0cd73f
KZ
158 * @upd: update handler
159 * @mountflags: MS_* flags
f12aac6e 160 * @target: umount target, must be NULL for mount
2915bdc0 161 * @fs: mount filesystem description, must be NULL for umount
d300992d 162 *
6f5788c5 163 * Returns: <0 in case on error, 0 on success, 1 if update is unnecessary.
6c40a53d 164 */
68164f6c
KZ
165int mnt_update_set_fs(struct libmnt_update *upd, unsigned long mountflags,
166 const char *target, struct libmnt_fs *fs)
6c40a53d 167{
77417bc0
KZ
168 int rc;
169
30493710 170 if (!upd)
3a5b1b1d 171 return -EINVAL;
2915bdc0
KZ
172 if ((mountflags & MS_MOVE) && (!fs || !mnt_fs_get_srcpath(fs)))
173 return -EINVAL;
174 if (target && fs)
175 return -EINVAL;
6c40a53d 176
83a78332 177 DBG(UPDATE, ul_debugobj(upd,
63c9c05d
KZ
178 "resetting FS [target=%s, flags=0x%08lx]",
179 target, mountflags));
87a07a4c 180 if (fs) {
83a78332 181 DBG(UPDATE, ul_debugobj(upd, "FS template:"));
87a07a4c
KZ
182 DBG(UPDATE, mnt_fs_print_debug(fs, stderr));
183 }
6c40a53d 184
26d0c0ae 185 mnt_unref_fs(upd->fs);
1d0cd73f 186 free(upd->target);
477401f0 187 upd->ready = 0;
1d0cd73f
KZ
188 upd->fs = NULL;
189 upd->target = NULL;
36bda5cb
KZ
190 upd->mountflags = 0;
191
192 if (mountflags & MS_PROPAGATION)
193 return 1;
194
1d0cd73f 195 upd->mountflags = mountflags;
6c40a53d 196
e9d52e6e 197 rc = mnt_update_set_filename(upd, NULL);
6f5788c5 198 if (rc) {
83a78332 199 DBG(UPDATE, ul_debugobj(upd, "no writable file available [rc=%d]", rc));
77417bc0 200 return rc; /* error or no file available (rc = 1) */
6f5788c5 201 }
2915bdc0
KZ
202 if (target) {
203 upd->target = strdup(target);
204 if (!upd->target)
205 return -ENOMEM;
206
207 } else if (fs) {
e9d52e6e 208 if (!(mountflags & MS_MOVE)) {
8228372b 209 rc = utab_new_entry(upd, fs, mountflags);
1d0cd73f 210 if (rc)
e9d52e6e 211 return rc;
1d0cd73f 212 } else {
f84fa6f7 213 upd->fs = mnt_copy_mtab_fs(fs);
1d0cd73f
KZ
214 if (!upd->fs)
215 return -ENOMEM;
216 }
217 }
6c40a53d 218
83a78332 219 DBG(UPDATE, ul_debugobj(upd, "ready"));
477401f0 220 upd->ready = 1;
7714c689 221 return 0;
6c40a53d
KZ
222}
223
36bda5cb 224/**
f84fa6f7
KZ
225 * mnt_update_get_fs:
226 * @upd: update
227 *
228 * Returns: update filesystem entry or NULL
97e23b5e 229 */
68164f6c 230struct libmnt_fs *mnt_update_get_fs(struct libmnt_update *upd)
97e23b5e
KZ
231{
232 return upd ? upd->fs : NULL;
233}
1d0cd73f 234
36bda5cb 235/**
68164f6c 236 * mnt_update_get_mflags:
36bda5cb
KZ
237 * @upd: update
238 *
239 * Returns: mount flags as was set by mnt_update_set_fs()
240 */
68164f6c 241unsigned long mnt_update_get_mflags(struct libmnt_update *upd)
36bda5cb
KZ
242{
243 return upd ? upd->mountflags : 0;
244}
245
246/**
247 * mnt_update_force_rdonly:
248 * @upd: update
249 * @rdonly: is read-only?
250 *
251 * Returns: 0 on success and negative number in case of error.
252 */
68164f6c 253int mnt_update_force_rdonly(struct libmnt_update *upd, int rdonly)
36bda5cb
KZ
254{
255 int rc = 0;
256
257 if (!upd || !upd->fs)
258 return -EINVAL;
259
260 if (rdonly && (upd->mountflags & MS_RDONLY))
261 return 0;
262 if (!rdonly && !(upd->mountflags & MS_RDONLY))
263 return 0;
264
36bda5cb
KZ
265 if (rdonly)
266 upd->mountflags &= ~MS_RDONLY;
267 else
268 upd->mountflags |= MS_RDONLY;
269
270 return rc;
271}
272
7e0c0619 273
6c40a53d 274/*
d58b3157 275 * Allocates an utab entry (upd->fs) for mount/remount. This function should be
c4c66355 276 * called *before* mount(2) syscall. The @fs is used as a read-only template.
1d0cd73f 277 *
d58b3157 278 * Returns: 0 on success, negative number on error, 1 if utab's update is
1d0cd73f 279 * unnecessary.
6c40a53d 280 */
c4c66355
KZ
281static int utab_new_entry(struct libmnt_update *upd, struct libmnt_fs *fs,
282 unsigned long mountflags)
6c40a53d 283{
1d0cd73f 284 int rc = 0;
1b504263 285 const char *o, *a;
f84fa6f7 286 char *u = NULL;
6c40a53d
KZ
287
288 assert(fs);
c4c66355
KZ
289 assert(upd);
290 assert(upd->fs == NULL);
1d0cd73f 291 assert(!(mountflags & MS_MOVE));
6c40a53d 292
83a78332 293 DBG(UPDATE, ul_debug("prepare utab entry"));
6c40a53d 294
68164f6c 295 o = mnt_fs_get_user_options(fs);
76a06ca4 296 a = mnt_fs_get_attributes(fs);
c4c66355 297 upd->fs = NULL;
76a06ca4 298
f84fa6f7
KZ
299 if (o) {
300 /* remove non-mtab options */
301 rc = mnt_optstr_get_options(o, &u,
302 mnt_get_builtin_optmap(MNT_USERSPACE_MAP),
303 MNT_NOMTAB);
304 if (rc)
305 goto err;
306 }
307
308 if (!u && !a) {
83a78332 309 DBG(UPDATE, ul_debug("utab entry unnecessary (no options)"));
f84fa6f7
KZ
310 return 1;
311 }
1d0cd73f
KZ
312
313 /* allocate the entry */
c4c66355
KZ
314 upd->fs = mnt_copy_fs(NULL, fs);
315 if (!upd->fs) {
1d0cd73f
KZ
316 rc = -ENOMEM;
317 goto err;
6c40a53d
KZ
318 }
319
c4c66355 320 rc = mnt_fs_set_options(upd->fs, u);
76a06ca4
KZ
321 if (rc)
322 goto err;
c4c66355 323 rc = mnt_fs_set_attributes(upd->fs, a);
1d0cd73f
KZ
324 if (rc)
325 goto err;
6c40a53d 326
1d0cd73f 327 if (!(mountflags & MS_REMOUNT)) {
c4c66355 328 rc = set_fs_root(upd, fs, mountflags);
1d0cd73f
KZ
329 if (rc)
330 goto err;
331 }
6c40a53d 332
f84fa6f7 333 free(u);
83a78332 334 DBG(UPDATE, ul_debug("utab entry OK"));
6c40a53d 335 return 0;
1d0cd73f 336err:
f84fa6f7 337 free(u);
26d0c0ae 338 mnt_unref_fs(upd->fs);
c4c66355 339 upd->fs = NULL;
1d0cd73f 340 return rc;
6c40a53d
KZ
341}
342
c4c66355
KZ
343/*
344 * Sets fs-root and fs-type to @upd->fs according to the @fs template and
d58b3157 345 * @mountfalgs. For MS_BIND mountflag it reads information about the source
c4c66355
KZ
346 * filesystem from /proc/self/mountinfo.
347 */
348static int set_fs_root(struct libmnt_update *upd, struct libmnt_fs *fs,
349 unsigned long mountflags)
6c40a53d 350{
c4c66355
KZ
351 struct libmnt_fs *src_fs;
352 char *fsroot = NULL;
e9cd2e2b 353 const char *src, *fstype;
c4c66355 354 int rc = 0;
1d0cd73f 355
83a78332 356 DBG(UPDATE, ul_debug("setting FS root"));
6c40a53d 357
c4c66355
KZ
358 assert(upd);
359 assert(upd->fs);
360 assert(fs);
6c40a53d 361
e9cd2e2b
KZ
362 fstype = mnt_fs_get_fstype(fs);
363
1d0cd73f 364 if (mountflags & MS_BIND) {
c4c66355
KZ
365 if (!upd->mountinfo)
366 upd->mountinfo = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO);
6c40a53d 367 src = mnt_fs_get_srcpath(fs);
dd369652 368 if (src) {
c4c66355
KZ
369 rc = mnt_fs_set_bindsrc(upd->fs, src);
370 if (rc)
371 goto err;
f84fa6f7 372 }
e9cd2e2b
KZ
373
374 } else if (fstype && (strcmp(fstype, "btrfs") == 0 || strcmp(fstype, "auto") == 0)) {
375 if (!upd->mountinfo)
376 upd->mountinfo = mnt_new_table_from_file(_PATH_PROC_MOUNTINFO);
c4c66355 377 }
6c40a53d 378
c4c66355
KZ
379 src_fs = mnt_table_get_fs_root(upd->mountinfo, fs,
380 mountflags, &fsroot);
381 if (src_fs) {
6c40a53d 382 src = mnt_fs_get_srcpath(src_fs);
c4c66355 383 rc = mnt_fs_set_source(upd->fs, src);
dd369652
KZ
384 if (rc)
385 goto err;
6c40a53d 386
c4c66355 387 mnt_fs_set_fstype(upd->fs, mnt_fs_get_fstype(src_fs));
6c40a53d
KZ
388 }
389
c4c66355 390 upd->fs->root = fsroot;
6c40a53d
KZ
391 return 0;
392err:
c4c66355 393 free(fsroot);
1d0cd73f 394 return rc;
d300992d
KZ
395}
396
68af0bcc
KZ
397/* mtab and fstab update -- returns zero on success
398 */
68164f6c 399static int fprintf_mtab_fs(FILE *f, struct libmnt_fs *fs)
6c40a53d 400{
cb90e24e 401 const char *o, *src, *fstype, *comm;
1d0cd73f
KZ
402 char *m1, *m2, *m3, *m4;
403 int rc;
6c40a53d 404
1d0cd73f
KZ
405 assert(fs);
406 assert(f);
1b56aae8 407
cb90e24e 408 comm = mnt_fs_get_comment(fs);
b5962110
KZ
409 src = mnt_fs_get_source(fs);
410 fstype = mnt_fs_get_fstype(fs);
411 o = mnt_fs_get_options(fs);
76a06ca4 412
b5962110 413 m1 = src ? mangle(src) : "none";
1d0cd73f 414 m2 = mangle(mnt_fs_get_target(fs));
b5962110
KZ
415 m3 = fstype ? mangle(fstype) : "none";
416 m4 = o ? mangle(o) : "rw";
1b56aae8 417
68af0bcc 418 if (m1 && m2 && m3 && m4) {
cb90e24e
OO
419 if (comm)
420 fputs(comm, f);
68af0bcc 421 rc = fprintf(f, "%s %s %s %s %d %d\n",
1d0cd73f
KZ
422 m1, m2, m3, m4,
423 mnt_fs_get_freq(fs),
424 mnt_fs_get_passno(fs));
68af0bcc
KZ
425 if (rc > 0)
426 rc = 0;
427 } else
1d0cd73f 428 rc = -ENOMEM;
6c40a53d 429
b5962110
KZ
430 if (src)
431 free(m1);
1d0cd73f 432 free(m2);
b5962110
KZ
433 if (fstype)
434 free(m3);
435 if (o)
436 free(m4);
3a5b1b1d 437
1d0cd73f
KZ
438 return rc;
439}
6c40a53d 440
68164f6c 441static int fprintf_utab_fs(FILE *f, struct libmnt_fs *fs)
1d0cd73f 442{
dd369652 443 char *p;
68af0bcc 444 int rc = 0;
4e92d2b0 445
1d0cd73f
KZ
446 if (!fs || !f)
447 return -EINVAL;
dd369652 448
4b1348c7 449 if (mnt_fs_get_id(fs) > 0)
8cf6c507 450 rc = fprintf(f, "ID=%d ", mnt_fs_get_id(fs));
4b1348c7
KZ
451 if (mnt_fs_get_uniq_id(fs) > 0)
452 rc = fprintf(f, "UNIQID=%" PRIu64, mnt_fs_get_uniq_id(fs));
453
8cf6c507
KZ
454 if (rc >= 0) {
455 p = mangle(mnt_fs_get_source(fs));
456 if (p) {
457 rc = fprintf(f, "SRC=%s ", p);
458 free(p);
459 }
dd369652 460 }
68af0bcc
KZ
461 if (rc >= 0) {
462 p = mangle(mnt_fs_get_target(fs));
463 if (p) {
464 rc = fprintf(f, "TARGET=%s ", p);
465 free(p);
466 }
dd369652 467 }
68af0bcc
KZ
468 if (rc >= 0) {
469 p = mangle(mnt_fs_get_root(fs));
470 if (p) {
471 rc = fprintf(f, "ROOT=%s ", p);
472 free(p);
473 }
dd369652 474 }
68af0bcc
KZ
475 if (rc >= 0) {
476 p = mangle(mnt_fs_get_bindsrc(fs));
477 if (p) {
478 rc = fprintf(f, "BINDSRC=%s ", p);
479 free(p);
480 }
dd369652 481 }
68af0bcc
KZ
482 if (rc >= 0) {
483 p = mangle(mnt_fs_get_attributes(fs));
484 if (p) {
485 rc = fprintf(f, "ATTRS=%s ", p);
486 free(p);
487 }
76a06ca4 488 }
68af0bcc
KZ
489 if (rc >= 0) {
490 p = mangle(mnt_fs_get_user_options(fs));
491 if (p) {
492 rc = fprintf(f, "OPTS=%s", p);
493 free(p);
494 }
dd369652 495 }
68af0bcc
KZ
496 if (rc >= 0)
497 rc = fprintf(f, "\n");
dd369652 498
68af0bcc
KZ
499 if (rc > 0)
500 rc = 0; /* success */
501 return rc;
6c40a53d
KZ
502}
503
68164f6c 504static int update_table(struct libmnt_update *upd, struct libmnt_table *tb)
6c40a53d
KZ
505{
506 FILE *f;
1d0cd73f
KZ
507 int rc, fd;
508 char *uq = NULL;
6c40a53d 509
77417bc0 510 if (!tb || !upd->filename)
1d0cd73f 511 return -EINVAL;
6c40a53d 512
83a78332 513 DBG(UPDATE, ul_debugobj(upd, "%s: updating", upd->filename));
3f31a959 514
4b6cf485 515 fd = mnt_open_uniq_filename(upd->filename, &uq);
1d0cd73f
KZ
516 if (fd < 0)
517 return fd; /* error */
518
1eb8539d 519 f = fdopen(fd, "w" UL_CLOEXECSTR);
6c40a53d 520 if (f) {
1d0cd73f 521 struct stat st;
68164f6c
KZ
522 struct libmnt_iter itr;
523 struct libmnt_fs *fs;
1d0cd73f
KZ
524
525 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
cb90e24e
OO
526
527 if (tb->comms && mnt_table_get_intro_comment(tb))
528 fputs(mnt_table_get_intro_comment(tb), f);
529
68164f6c 530 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
e9d52e6e 531 rc = fprintf_utab_fs(f, fs);
68af0bcc 532 if (rc) {
83a78332 533 DBG(UPDATE, ul_debugobj(upd,
68af0bcc
KZ
534 "%s: write entry failed: %m", uq));
535 goto leave;
536 }
537 }
3035ba93
OO
538 if (tb->comms && mnt_table_get_trailing_comment(tb))
539 fputs(mnt_table_get_trailing_comment(tb), f);
68af0bcc
KZ
540
541 if (fflush(f) != 0) {
542 rc = -errno;
83a78332 543 DBG(UPDATE, ul_debugobj(upd, "%s: fflush failed: %m", uq));
68af0bcc 544 goto leave;
1d0cd73f 545 }
68af0bcc 546
1d0cd73f
KZ
547 rc = fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) ? -errno : 0;
548
77417bc0 549 if (!rc && stat(upd->filename, &st) == 0)
1d0cd73f
KZ
550 /* Copy uid/gid from the present file before renaming. */
551 rc = fchown(fd, st.st_uid, st.st_gid) ? -errno : 0;
552
6c40a53d 553 fclose(f);
80140144 554 f = NULL;
a9ddf316
KZ
555
556 if (!rc)
557 rc = rename(uq, upd->filename) ? -errno : 0;
1d0cd73f
KZ
558 } else {
559 rc = -errno;
560 close(fd);
6c40a53d 561 }
1d0cd73f 562
68af0bcc 563leave:
80140144
KZ
564 if (f)
565 fclose(f);
566
1d0cd73f
KZ
567 unlink(uq); /* be paranoid */
568 free(uq);
06ff935e 569 DBG(UPDATE, ul_debugobj(upd, "%s: done [rc=%d]", upd->filename, rc));
6c40a53d
KZ
570 return rc;
571}
572
d22f2822
OO
573/**
574 * mnt_table_write_file
575 * @tb: parsed file (e.g. fstab)
576 * @file: target
577 *
578 * This function writes @tb to @file.
579 *
580 * Returns: 0 on success, negative number on error.
581 */
582int mnt_table_write_file(struct libmnt_table *tb, FILE *file)
583{
584 int rc = 0;
585 struct libmnt_iter itr;
586 struct libmnt_fs *fs;
587
588 if (tb->comms && mnt_table_get_intro_comment(tb))
589 fputs(mnt_table_get_intro_comment(tb), file);
590
591 mnt_reset_iter(&itr, MNT_ITER_FORWARD);
592 while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
593 rc = fprintf_mtab_fs(file, fs);
594 if (rc)
595 return rc;
596 }
3035ba93
OO
597 if (tb->comms && mnt_table_get_trailing_comment(tb))
598 fputs(mnt_table_get_trailing_comment(tb), file);
d22f2822
OO
599
600 if (fflush(file) != 0)
601 rc = -errno;
602
83a78332 603 DBG(TAB, ul_debugobj(tb, "write file done [rc=%d]", rc));
d22f2822
OO
604 return rc;
605}
606
607/**
608 * mnt_table_replace_file
609 * @tb: parsed file (e.g. fstab)
610 * @filename: target
611 *
d58b3157 612 * This function replaces @file by the new content from @tb.
d22f2822
OO
613 *
614 * Returns: 0 on success, negative number on error.
615 */
616int mnt_table_replace_file(struct libmnt_table *tb, const char *filename)
617{
618 int fd, rc = 0;
619 FILE *f;
620 char *uq = NULL;
621
83a78332 622 DBG(TAB, ul_debugobj(tb, "%s: replacing", filename));
d22f2822
OO
623
624 fd = mnt_open_uniq_filename(filename, &uq);
625 if (fd < 0)
626 return fd; /* error */
627
628 f = fdopen(fd, "w" UL_CLOEXECSTR);
629 if (f) {
630 struct stat st;
631
632 mnt_table_write_file(tb, f);
633
a84ec176
KZ
634 if (fflush(f) != 0) {
635 rc = -errno;
83a78332 636 DBG(UPDATE, ul_debug("%s: fflush failed: %m", uq));
a84ec176
KZ
637 goto leave;
638 }
639
d22f2822
OO
640 rc = fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) ? -errno : 0;
641
642 if (!rc && stat(filename, &st) == 0)
643 /* Copy uid/gid from the present file before renaming. */
644 rc = fchown(fd, st.st_uid, st.st_gid) ? -errno : 0;
645
646 fclose(f);
a84ec176
KZ
647 f = NULL;
648
d22f2822 649 if (!rc)
a84ec176 650 rc = rename(uq, filename) ? -errno : 0;
d22f2822
OO
651 } else {
652 rc = -errno;
653 close(fd);
654 }
655
a84ec176
KZ
656leave:
657 if (f)
658 fclose(f);
d22f2822
OO
659 unlink(uq);
660 free(uq);
661
83a78332 662 DBG(TAB, ul_debugobj(tb, "replace done [rc=%d]", rc));
d22f2822
OO
663 return rc;
664}
a84ec176 665
c3085df6
KZ
666static int add_file_entry(struct libmnt_table *tb, struct libmnt_update *upd)
667{
4569bbea
KZ
668 struct libmnt_fs *fs;
669
670 assert(upd);
c3085df6 671
4569bbea 672 fs = mnt_copy_fs(NULL, upd->fs);
c3085df6
KZ
673 if (!fs)
674 return -ENOMEM;
675
676 mnt_table_add_fs(tb, fs);
26d0c0ae
KZ
677 mnt_unref_fs(fs);
678
c3085df6
KZ
679 return update_table(upd, tb);
680}
681
b94b5929 682static int update_add_entry(struct libmnt_update *upd)
6c40a53d 683{
68af0bcc 684 struct libmnt_table *tb;
8f60ea34 685 int rc = 0;
6c40a53d 686
30493710 687 assert(upd);
1d0cd73f 688 assert(upd->fs);
b94b5929 689 assert(upd->lock);
6c40a53d 690
83a78332 691 DBG(UPDATE, ul_debugobj(upd, "%s: add entry", upd->filename));
6c40a53d 692
b94b5929 693 rc = mnt_lock_file(upd->lock);
8f60ea34 694 if (rc)
d369dc42 695 return -MNT_ERR_LOCK;
6c40a53d 696
e9d52e6e 697 tb = __mnt_new_table_from_file(upd->filename, MNT_FMT_UTAB, 1);
c3085df6
KZ
698 if (tb)
699 rc = add_file_entry(tb, upd);
68af0bcc 700
b94b5929 701 mnt_unlock_file(upd->lock);
c9f1585e 702 mnt_unref_table(tb);
1d0cd73f
KZ
703 return rc;
704}
6c40a53d 705
b94b5929 706static int update_remove_entry(struct libmnt_update *upd)
1d0cd73f 707{
68164f6c 708 struct libmnt_table *tb;
8f60ea34 709 int rc = 0;
6c40a53d 710
1d0cd73f
KZ
711 assert(upd);
712 assert(upd->target);
b94b5929 713 assert(upd->lock);
1d0cd73f 714
83a78332 715 DBG(UPDATE, ul_debugobj(upd, "%s: remove entry", upd->filename));
1d0cd73f 716
b94b5929 717 rc = mnt_lock_file(upd->lock);
8f60ea34 718 if (rc)
d369dc42 719 return -MNT_ERR_LOCK;
1d0cd73f 720
e9d52e6e 721 tb = __mnt_new_table_from_file(upd->filename, MNT_FMT_UTAB, 1);
1d0cd73f 722 if (tb) {
68164f6c 723 struct libmnt_fs *rem = mnt_table_find_target(tb, upd->target, MNT_ITER_BACKWARD);
1d0cd73f 724 if (rem) {
68164f6c
KZ
725 mnt_table_remove_fs(tb, rem);
726 rc = update_table(upd, tb);
1d0cd73f 727 }
1d0cd73f 728 }
6f5788c5 729
b94b5929 730 mnt_unlock_file(upd->lock);
c9f1585e 731 mnt_unref_table(tb);
6c40a53d
KZ
732 return rc;
733}
734
b94b5929 735static int update_modify_target(struct libmnt_update *upd)
6c40a53d 736{
68164f6c 737 struct libmnt_table *tb = NULL;
8f60ea34 738 int rc = 0;
1d0cd73f 739
4569bbea 740 assert(upd);
b94b5929 741 assert(upd->lock);
83a78332 742 DBG(UPDATE, ul_debugobj(upd, "%s: modify target", upd->filename));
1d0cd73f 743
b94b5929 744 rc = mnt_lock_file(upd->lock);
8f60ea34 745 if (rc)
d369dc42 746 return -MNT_ERR_LOCK;
1d0cd73f 747
e9d52e6e 748 tb = __mnt_new_table_from_file(upd->filename, MNT_FMT_UTAB, 1);
1d0cd73f 749 if (tb) {
a04149fb
FB
750 const char *upd_source = mnt_fs_get_srcpath(upd->fs);
751 const char *upd_target = mnt_fs_get_target(upd->fs);
752 struct libmnt_iter itr;
753 struct libmnt_fs *fs;
1ec32f42
KZ
754 char *cn_target = mnt_resolve_path(upd_target, NULL);
755
756 if (!cn_target) {
757 rc = -ENOMEM;
758 goto done;
759 }
a04149fb
FB
760
761 mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
1ec32f42
KZ
762 while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
763 char *p;
764 const char *e;
a04149fb 765
aa07db0a 766 e = ul_startswith(mnt_fs_get_target(fs), upd_source);
1ec32f42 767 if (!e || (*e && *e != '/'))
a04149fb 768 continue;
1ec32f42
KZ
769 if (*e == '/')
770 e++; /* remove extra '/' */
a04149fb 771
1ec32f42
KZ
772 /* no subdirectory, replace entire path */
773 if (!*e)
774 rc = mnt_fs_set_target(fs, cn_target);
a04149fb 775
1ec32f42
KZ
776 /* update start of the path, keep subdirectory */
777 else if (asprintf(&p, "%s/%s", cn_target, e) > 0) {
778 rc = mnt_fs_set_target(fs, p);
a04149fb 779 free(p);
1ec32f42
KZ
780 } else
781 rc = -ENOMEM;
a04149fb
FB
782
783 if (rc < 0)
784 break;
1d0cd73f 785 }
a04149fb
FB
786
787 if (!rc)
788 rc = update_table(upd, tb);
1ec32f42 789 free(cn_target);
1d0cd73f 790 }
8f60ea34 791
1ec32f42 792done:
b94b5929 793 mnt_unlock_file(upd->lock);
c9f1585e 794 mnt_unref_table(tb);
1d0cd73f
KZ
795 return rc;
796}
6c40a53d 797
477401f0 798/* replaces option in the table entry by new options from @udp */
b94b5929 799static int update_modify_options(struct libmnt_update *upd)
1d0cd73f 800{
68164f6c 801 struct libmnt_table *tb = NULL;
8f60ea34 802 int rc = 0;
68164f6c 803 struct libmnt_fs *fs;
6c40a53d 804
1d0cd73f
KZ
805 assert(upd);
806 assert(upd->fs);
b94b5929 807 assert(upd->lock);
6c40a53d 808
83a78332 809 DBG(UPDATE, ul_debugobj(upd, "%s: modify options", upd->filename));
1d0cd73f 810
76a06ca4
KZ
811 fs = upd->fs;
812
b94b5929 813 rc = mnt_lock_file(upd->lock);
8f60ea34 814 if (rc)
d369dc42 815 return -MNT_ERR_LOCK;
1d0cd73f 816
e9d52e6e 817 tb = __mnt_new_table_from_file(upd->filename, MNT_FMT_UTAB, 1);
1d0cd73f 818 if (tb) {
68164f6c 819 struct libmnt_fs *cur = mnt_table_find_target(tb,
76a06ca4 820 mnt_fs_get_target(fs),
1d0cd73f
KZ
821 MNT_ITER_BACKWARD);
822 if (cur) {
e9d52e6e 823 rc = mnt_fs_set_attributes(cur, mnt_fs_get_attributes(fs));
76a06ca4 824 if (!rc)
f2b3a3a3 825 rc = mnt_fs_set_options(cur, mnt_fs_get_options(fs));
1d0cd73f 826 if (!rc)
68164f6c 827 rc = update_table(upd, tb);
c3085df6
KZ
828 } else
829 rc = add_file_entry(tb, upd); /* not found, add new */
6c40a53d 830 }
76a06ca4 831
b94b5929 832 mnt_unlock_file(upd->lock);
c9f1585e 833 mnt_unref_table(tb);
6c40a53d
KZ
834 return rc;
835}
836
477401f0 837/* add user options missing in the table entry by new options from @udp */
b94b5929 838static int update_add_options(struct libmnt_update *upd)
477401f0
KZ
839{
840 struct libmnt_table *tb = NULL;
841 int rc = 0;
842 struct libmnt_fs *fs;
843
844 assert(upd);
845 assert(upd->fs);
b94b5929 846 assert(upd->lock);
477401f0
KZ
847
848 if (!upd->fs->user_optstr)
849 return 0;
850
851 DBG(UPDATE, ul_debugobj(upd, "%s: add options", upd->filename));
852
853 fs = upd->fs;
854
b94b5929 855 rc = mnt_lock_file(upd->lock);
477401f0
KZ
856 if (rc)
857 return -MNT_ERR_LOCK;
858
859 tb = __mnt_new_table_from_file(upd->filename, MNT_FMT_UTAB, 1);
860 if (tb) {
861 struct libmnt_fs *cur = mnt_table_find_target(tb,
862 mnt_fs_get_target(fs),
863 MNT_ITER_BACKWARD);
864 if (cur) {
865 char *u = NULL;
866
867 rc = mnt_optstr_get_missing(cur->user_optstr, upd->fs->user_optstr, &u);
868 if (!rc && u) {
869 DBG(UPDATE, ul_debugobj(upd, " add missing: %s", u));
870 rc = mnt_optstr_append_option(&cur->user_optstr, u, NULL);
871 }
872 if (!rc && u)
873 rc = update_table(upd, tb);
874
875 if (rc == 1) /* nothing is missing */
876 rc = 0;
877 } else
878 rc = add_file_entry(tb, upd); /* not found, add new */
879 }
880
b94b5929 881 mnt_unlock_file(upd->lock);
477401f0
KZ
882 mnt_unref_table(tb);
883 return rc;
884
885}
886
b94b5929
KZ
887static int update_init_lock(struct libmnt_update *upd, struct libmnt_lock *lc)
888{
889 assert(upd);
890
891 if (lc) {
892 mnt_unref_lock(upd->lock);
893 mnt_ref_lock(lc);
894 upd->lock = lc;
895 } else if (!upd->lock) {
896 upd->lock = mnt_new_lock(upd->filename, 0);
897 if (!upd->lock)
898 return -ENOMEM;
ed4d3e26 899 mnt_lock_block_signals(upd->lock, TRUE);
b94b5929
KZ
900 }
901
902 return 0;
903}
904
6c40a53d 905/**
68164f6c 906 * mnt_update_table:
0f32f1e2 907 * @upd: update
5976114f 908 * @lc: lock or NULL
6c40a53d 909 *
a362ae60 910 * High-level API to update /etc/mtab (or private /run/mount/utab file).
6c40a53d 911 *
5976114f 912 * The @lc lock is optional and will be created if necessary. Note that
d58b3157 913 * an automatically created lock blocks all signals.
5976114f
KZ
914 *
915 * See also mnt_lock_block_signals() and mnt_context_get_lock().
916 *
1d0cd73f 917 * Returns: 0 on success, negative number on error.
6c40a53d 918 */
68164f6c 919int mnt_update_table(struct libmnt_update *upd, struct libmnt_lock *lc)
6c40a53d 920{
1d0cd73f
KZ
921 int rc = -EINVAL;
922
8726371f 923 if (!upd || !upd->filename)
1d0cd73f
KZ
924 return -EINVAL;
925 if (!upd->ready)
d300992d 926 return 0;
6c40a53d 927
83a78332 928 DBG(UPDATE, ul_debugobj(upd, "%s: update tab", upd->filename));
f84fa6f7
KZ
929 if (upd->fs) {
930 DBG(UPDATE, mnt_fs_print_debug(upd->fs, stderr));
931 }
b94b5929
KZ
932
933 rc = update_init_lock(upd, lc);
934 if (rc)
935 goto done;
c570f567 936
1d0cd73f 937 if (!upd->fs && upd->target)
b94b5929 938 rc = update_remove_entry(upd); /* umount */
1d0cd73f 939 else if (upd->mountflags & MS_MOVE)
b94b5929 940 rc = update_modify_target(upd); /* move */
1d0cd73f 941 else if (upd->mountflags & MS_REMOUNT)
b94b5929 942 rc = update_modify_options(upd); /* remount */
477401f0 943 else if (upd->fs && upd->missing_options)
1a02c7a7 944 rc = update_add_options(upd); /* mount by external helper */
1d0cd73f 945 else if (upd->fs)
b94b5929 946 rc = update_add_entry(upd); /* mount */
1d0cd73f 947
477401f0 948 upd->ready = 1;
b94b5929 949done:
83a78332 950 DBG(UPDATE, ul_debugobj(upd, "%s: update tab: done [rc=%d]",
77417bc0 951 upd->filename, rc));
1d0cd73f 952 return rc;
6c40a53d
KZ
953}
954
b94b5929 955int mnt_update_already_done(struct libmnt_update *upd)
7e0c0619
KZ
956{
957 struct libmnt_table *tb = NULL;
7e0c0619
KZ
958 int rc = 0;
959
960 if (!upd || !upd->filename || (!upd->fs && !upd->target))
961 return -EINVAL;
962
83a78332 963 DBG(UPDATE, ul_debugobj(upd, "%s: checking for previous update", upd->filename));
7e0c0619 964
e9d52e6e 965 tb = __mnt_new_table_from_file(upd->filename, MNT_FMT_UTAB, 1);
7e0c0619
KZ
966 if (!tb)
967 goto done;
968
969 if (upd->fs) {
970 /* mount */
477401f0 971 struct libmnt_fs *fs;
7e0c0619
KZ
972 const char *tgt = mnt_fs_get_target(upd->fs);
973 const char *src = mnt_fs_get_bindsrc(upd->fs) ?
974 mnt_fs_get_bindsrc(upd->fs) :
975 mnt_fs_get_source(upd->fs);
976
477401f0
KZ
977 fs = mnt_table_find_pair(tb, src, tgt, MNT_ITER_BACKWARD);
978 if (fs) {
83a78332 979 DBG(UPDATE, ul_debugobj(upd, "%s: found %s %s",
7e0c0619 980 upd->filename, src, tgt));
477401f0 981
1a02c7a7 982 /* Check if utab entry (probably written by /sbin/mount.<type>
477401f0
KZ
983 * helper) contains all options expected by this update */
984 if (mnt_optstr_get_missing(fs->user_optstr, upd->fs->user_optstr, NULL) == 0) {
985 upd->missing_options = 1;
986 DBG(UPDATE, ul_debugobj(upd, " missing options detected"));
6b316e0c
GL
987 } else
988 rc = 1;
989 }
477401f0 990
7e0c0619
KZ
991 } else if (upd->target) {
992 /* umount */
993 if (!mnt_table_find_target(tb, upd->target, MNT_ITER_BACKWARD)) {
83a78332 994 DBG(UPDATE, ul_debugobj(upd, "%s: not-found (umounted) %s",
7e0c0619
KZ
995 upd->filename, upd->target));
996 rc = 1;
997 }
998 }
999
1000 mnt_unref_table(tb);
1001done:
83a78332 1002 DBG(UPDATE, ul_debugobj(upd, "%s: previous update check done [rc=%d]",
7e0c0619
KZ
1003 upd->filename, rc));
1004 return rc;
1005}
1006
54482492
KZ
1007int mnt_update_emit_event(struct libmnt_update *upd)
1008{
1009 char *filename;
1010 int fd;
1011
1012 if (!upd || !upd->filename)
1013 return -EINVAL;
1014
1015 if (asprintf(&filename, "%s.event", upd->filename) <= 0)
a002df07 1016 return -ENOMEM;
54482492 1017
9218c967
KZ
1018 DBG(UPDATE, ul_debugobj(upd, "emitting utab event"));
1019
54482492
KZ
1020 fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC,
1021 S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH);
1022 free(filename);
1023 if (fd < 0)
1024 return -errno;
1025 close(fd);
1026 return 0;
1027}
7e0c0619 1028
9218c967
KZ
1029/*
1030 * Let's use /run/mount/utab.act file to report to libmount monitor that
1031 * libmount is working with utab. In this case, the monitor can ignore all
1032 * events from kernel until entire mount (with all steps) is done.
1033 *
1034 * For example mount NFS with x-* options, means
1035 * - create utab.act and mark it as used (by LOCK_SH)
1036 * - exec /sbin/mount.nfs
1037 * - call mount(2) (kernel event on /proc/self/mounts)
1038 * - utab update (NFS stuff)
1039 * - utab update (add x-* userspace options)
1040 * - unlink utab.act (if not use anyone else)
1041 * - release event by /run/mount/utab.event
1042 *
1043 * Note, this is used only when utab is in the game (x-* options).
1044 */
1045int mnt_update_start(struct libmnt_update *upd)
1046{
1047 int rc = 0;
1048 mode_t oldmask;
1049
1050 if (!upd || !upd->filename)
1051 return -EINVAL;
1052
1053 if (!upd->act_filename &&
1054 asprintf(&upd->act_filename, "%s.act", upd->filename) <= 0)
1055 return -ENOMEM;
1056
1a02c7a7 1057 /* Use exclusive lock to avoid some other process will remove the the
9218c967
KZ
1058 * file before it's marked as used by LOCK_SH (below) */
1059 rc = update_init_lock(upd, NULL);
1060 if (rc)
1061 return rc;
1062
1063 rc = mnt_lock_file(upd->lock);
1064 if (rc)
1065 return -MNT_ERR_LOCK;
1066
1067 DBG(UPDATE, ul_debugobj(upd, "creating act file"));
1068
1069 oldmask = umask(S_IRGRP|S_IWGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH);
1070 upd->act_fd = open(upd->act_filename, O_WRONLY|O_CREAT|O_CLOEXEC, S_IRUSR|S_IWUSR);
1071 umask(oldmask);
1072
1073 if (upd->act_fd < 0) {
1074 rc = -errno;
1075 goto fail;
1076 }
1077
1078 /* mark the file as used */
1079 rc = flock(upd->act_fd, LOCK_SH);
1080 if (rc) {
1081 rc = -errno;
1082 goto fail;
1083 }
1084
1085 mnt_unlock_file(upd->lock);
1086 return 0;
1087fail:
1088 DBG(UPDATE, ul_debugobj(upd, "act file failed [rc=%d]", rc));
1089 mnt_unlock_file(upd->lock);
1090 unlink(upd->act_filename);
630dd235
KZ
1091 if (upd->act_fd >= 0)
1092 close(upd->act_fd);
9218c967
KZ
1093 upd->act_fd = -1;
1094 return rc;
1095}
1096
1097int mnt_update_end(struct libmnt_update *upd)
1098{
1099 int rc;
1100
1101 if (!upd || upd->act_fd < 0)
1102 return -EINVAL;
1103
1104 DBG(UPDATE, ul_debugobj(upd, "removing act file"));
1105
1106 /* make sure nobody else will use the file */
1107 rc = mnt_lock_file(upd->lock);
1108 if (rc)
1109 return -MNT_ERR_LOCK;
1110
1111 /* mark the file as unused */
1112 flock(upd->act_fd, LOCK_UN);
1113 errno = 0;
1114
1115 /* check if nobody else need the file (if yes, then the file is under LOCK_SH) )*/
1116 if (flock(upd->act_fd, LOCK_EX | LOCK_NB) != 0) {
1117 if (errno == EWOULDBLOCK)
1118 DBG(UPDATE, ul_debugobj(upd, "act file used, no unlink"));
1119 } else {
1120 DBG(UPDATE, ul_debugobj(upd, "unlinking act file"));
1121 unlink(upd->act_filename);
1122 }
1123
1124 mnt_unlock_file(upd->lock);
1125 close(upd->act_fd);
1126 upd->act_fd = -1;
1127 return 0;
1128}
1129
6c40a53d
KZ
1130#ifdef TEST_PROGRAM
1131
68164f6c 1132static int update(const char *target, struct libmnt_fs *fs, unsigned long mountflags)
6c40a53d 1133{
36bda5cb 1134 int rc;
68164f6c 1135 struct libmnt_update *upd;
6c40a53d 1136
83a78332 1137 DBG(UPDATE, ul_debug("update test"));
3a5b1b1d 1138
77417bc0
KZ
1139 upd = mnt_new_update();
1140 if (!upd)
1141 return -ENOMEM;
7714c689 1142
1d0cd73f 1143 rc = mnt_update_set_fs(upd, mountflags, target, fs);
1d0cd73f 1144 if (rc == 1) {
7c118af7 1145 /* update is unnecessary */
1d0cd73f
KZ
1146 rc = 0;
1147 goto done;
1148 }
7c118af7
KZ
1149 if (rc) {
1150 fprintf(stderr, "failed to set FS\n");
1151 goto done;
1152 }
30493710 1153
d58b3157 1154 /* [... mount(2) call should be here...] */
30493710 1155
5976114f 1156 rc = mnt_update_table(upd, NULL);
1d0cd73f 1157done:
8dece036 1158 mnt_free_update(upd);
30493710
KZ
1159 return rc;
1160}
1161
2a472ae8
TW
1162static int test_add(struct libmnt_test *ts __attribute__((unused)),
1163 int argc, char *argv[])
30493710 1164{
68164f6c 1165 struct libmnt_fs *fs = mnt_new_fs();
1d0cd73f 1166 int rc;
30493710 1167
1d0cd73f 1168 if (argc < 5 || !fs)
30493710
KZ
1169 return -1;
1170 mnt_fs_set_source(fs, argv[1]);
1171 mnt_fs_set_target(fs, argv[2]);
1172 mnt_fs_set_fstype(fs, argv[3]);
76a06ca4 1173 mnt_fs_set_options(fs, argv[4]);
30493710 1174
1d0cd73f 1175 rc = update(NULL, fs, 0);
26d0c0ae 1176 mnt_unref_fs(fs);
6c40a53d
KZ
1177 return rc;
1178}
1179
2a472ae8
TW
1180static int test_remove(struct libmnt_test *ts __attribute__((unused)),
1181 int argc, char *argv[])
6c40a53d 1182{
1d0cd73f 1183 if (argc < 2)
6c40a53d 1184 return -1;
1d0cd73f 1185 return update(argv[1], NULL, 0);
6c40a53d
KZ
1186}
1187
2a472ae8
TW
1188static int test_move(struct libmnt_test *ts __attribute__((unused)),
1189 int argc, char *argv[])
6c40a53d 1190{
68164f6c 1191 struct libmnt_fs *fs = mnt_new_fs();
1d0cd73f 1192 int rc;
6c40a53d 1193
1d0cd73f 1194 if (argc < 3)
6c40a53d 1195 return -1;
25bca458 1196 mnt_fs_set_source(fs, argv[1]);
7714c689 1197 mnt_fs_set_target(fs, argv[2]);
25bca458
KZ
1198
1199 rc = update(NULL, fs, MS_MOVE);
7714c689 1200
26d0c0ae 1201 mnt_unref_fs(fs);
6c40a53d
KZ
1202 return rc;
1203}
1204
2a472ae8
TW
1205static int test_remount(struct libmnt_test *ts __attribute__((unused)),
1206 int argc, char *argv[])
6c40a53d 1207{
68164f6c 1208 struct libmnt_fs *fs = mnt_new_fs();
1d0cd73f 1209 int rc;
6c40a53d 1210
1d0cd73f 1211 if (argc < 3)
6c40a53d 1212 return -1;
7714c689 1213 mnt_fs_set_target(fs, argv[1]);
76a06ca4 1214 mnt_fs_set_options(fs, argv[2]);
7714c689 1215
1d0cd73f 1216 rc = update(NULL, fs, MS_REMOUNT);
26d0c0ae 1217 mnt_unref_fs(fs);
6c40a53d
KZ
1218 return rc;
1219}
1220
2a472ae8
TW
1221static int test_replace(struct libmnt_test *ts __attribute__((unused)),
1222 int argc, char *argv[])
d22f2822
OO
1223{
1224 struct libmnt_fs *fs = mnt_new_fs();
1225 struct libmnt_table *tb = mnt_new_table();
1226 int rc;
1227
1228 if (argc < 3)
1229 return -1;
1230
1231 mnt_table_enable_comments(tb, TRUE);
1232 mnt_table_parse_fstab(tb, NULL);
1233
1234 mnt_fs_set_source(fs, argv[1]);
1235 mnt_fs_set_target(fs, argv[2]);
1236 mnt_fs_append_comment(fs, "# this is new filesystem\n");
26d0c0ae 1237
d22f2822 1238 mnt_table_add_fs(tb, fs);
26d0c0ae 1239 mnt_unref_fs(fs);
d22f2822
OO
1240
1241 rc = mnt_table_replace_file(tb, mnt_get_fstab_path());
c9f1585e 1242 mnt_unref_table(tb);
d22f2822
OO
1243 return rc;
1244}
1245
6c40a53d
KZ
1246int main(int argc, char *argv[])
1247{
68164f6c 1248 struct libmnt_test tss[] = {
d58b3157 1249 { "--add", test_add, "<src> <target> <type> <options> add a line to mtab" },
6c40a53d
KZ
1250 { "--remove", test_remove, "<target> MS_REMOUNT mtab change" },
1251 { "--move", test_move, "<old_target> <target> MS_MOVE mtab change" },
1252 { "--remount",test_remount, "<target> <options> MS_REMOUNT mtab change" },
d22f2822 1253 { "--replace",test_replace, "<src> <target> Add a line to LIBMOUNT_FSTAB and replace the original file" },
6c40a53d
KZ
1254 { NULL }
1255 };
1256
1257 return mnt_run_test(tss, argc, argv);
1258}
1259
1260#endif /* TEST_PROGRAM */