~ubuntu-branches/ubuntu/trusty/util-linux/trusty-proposed

« back to all changes in this revision

Viewing changes to libmount/src/utils.c

  • Committer: Package Import Robot
  • Author(s): LaMont Jones
  • Date: 2011-11-03 15:38:23 UTC
  • mto: (4.5.5 sid) (1.6.4)
  • mto: This revision was merged to the branch mainline in revision 85.
  • Revision ID: package-import@ubuntu.com-20111103153823-10sx16jprzxlhkqf
ImportĀ upstreamĀ versionĀ 2.20.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2008-2009 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
/**
 
9
 * SECTION: utils
 
10
 * @title: Utils
 
11
 * @short_description: misc utils.
 
12
 */
 
13
#include <ctype.h>
 
14
#include <fcntl.h>
 
15
#include <pwd.h>
 
16
#include <grp.h>
 
17
 
 
18
#include "strutils.h"
 
19
#include "pathnames.h"
 
20
#include "mountP.h"
 
21
#include "mangle.h"
 
22
#include "canonicalize.h"
 
23
#include "env.h"
 
24
 
 
25
int endswith(const char *s, const char *sx)
 
26
{
 
27
        ssize_t off;
 
28
 
 
29
        assert(s);
 
30
        assert(sx);
 
31
 
 
32
        off = strlen(s);
 
33
        if (!off)
 
34
                return 0;
 
35
        off -= strlen(sx);
 
36
        if (off < 0)
 
37
                return 0;
 
38
 
 
39
        return !strcmp(s + off, sx);
 
40
}
 
41
 
 
42
int startswith(const char *s, const char *sx)
 
43
{
 
44
        size_t off;
 
45
 
 
46
        assert(s);
 
47
        assert(sx);
 
48
 
 
49
        off = strlen(sx);
 
50
        if (!off)
 
51
                return 0;
 
52
 
 
53
        return !strncmp(s, sx, off);
 
54
}
 
55
 
 
56
/* returns basename and keeps dirname in the @path, if @path is "/" (root)
 
57
 * then returns empty string */
 
58
static char *stripoff_last_component(char *path)
 
59
{
 
60
        char *p = path ? strrchr(path, '/') : NULL;
 
61
 
 
62
        if (!p)
 
63
                return NULL;
 
64
        *p = '\0';
 
65
        return ++p;
 
66
}
 
67
 
 
68
/* Note that the @target has to be absolute path (so at least "/")
 
69
 */
 
70
int mnt_chdir_to_parent(const char *target, char **filename)
 
71
{
 
72
        char *path, *last = NULL;
 
73
        char cwd[PATH_MAX];
 
74
        int rc = -EINVAL;
 
75
 
 
76
        if (!target || *target != '/')
 
77
                return -EINVAL;
 
78
 
 
79
        path = strdup(target);
 
80
        if (!path)
 
81
                return -ENOMEM;
 
82
 
 
83
        if (*(path + 1) != '\0') {
 
84
                last = stripoff_last_component(path);
 
85
                if (!last)
 
86
                        goto err;
 
87
        }
 
88
        if (!*path)
 
89
                *path = '/';    /* root */
 
90
 
 
91
        if (chdir(path) == -1) {
 
92
                DBG(UTILS, mnt_debug("failed to chdir to %s: %m", path));
 
93
                rc = -errno;
 
94
                goto err;
 
95
        }
 
96
        if (!getcwd(cwd, sizeof(cwd))) {
 
97
                DBG(UTILS, mnt_debug("failed to obtain current directory: %m"));
 
98
                rc = -errno;
 
99
                goto err;
 
100
        }
 
101
        if (strcmp(cwd, path) != 0) {
 
102
                DBG(UTILS, mnt_debug("path moved (%s -> %s)", path, cwd));
 
103
                goto err;
 
104
        }
 
105
 
 
106
        DBG(CXT, mnt_debug("current directory moved to %s", path));
 
107
 
 
108
        *filename = path;
 
109
 
 
110
        if (!last || !*last)
 
111
                memcpy(*filename, ".", 2);
 
112
        else
 
113
                memcpy(*filename, last, strlen(last) + 1);
 
114
        return 0;
 
115
err:
 
116
        free(path);
 
117
        return rc;
 
118
}
 
119
 
 
120
/**
 
121
 * mnt_mangle:
 
122
 * @str: string
 
123
 *
 
124
 * Encode @str to be compatible with fstab/mtab
 
125
 *
 
126
 * Returns: new allocated string or NULL in case of error.
 
127
 */
 
128
char *mnt_mangle(const char *str)
 
129
{
 
130
        return mangle(str);
 
131
}
 
132
 
 
133
/**
 
134
 * mnt_unmangle:
 
135
 * @str: string
 
136
 *
 
137
 * Decode @str from fstab/mtab
 
138
 *
 
139
 * Returns: new allocated string or NULL in case of error.
 
140
 */
 
141
char *mnt_unmangle(const char *str)
 
142
{
 
143
        return unmangle(str, NULL);
 
144
}
 
145
 
 
146
/**
 
147
 * mnt_fstype_is_pseudofs:
 
148
 * @type: filesystem name
 
149
 *
 
150
 * Returns: 1 for filesystems like proc, sysfs, ... or 0.
 
151
 */
 
152
int mnt_fstype_is_pseudofs(const char *type)
 
153
{
 
154
        if (!type)
 
155
                return 0;
 
156
        if (strcmp(type, "none")  == 0 ||
 
157
            strcmp(type, "proc")  == 0 ||
 
158
            strcmp(type, "tmpfs") == 0 ||
 
159
            strcmp(type, "sysfs") == 0 ||
 
160
            strcmp(type, "autofs") == 0 ||
 
161
            strcmp(type, "devpts") == 0||
 
162
            strcmp(type, "cgroup") == 0 ||
 
163
            strcmp(type, "devtmpfs") == 0 ||
 
164
            strcmp(type, "devfs") == 0 ||
 
165
            strcmp(type, "dlmfs") == 0 ||
 
166
            strcmp(type, "cpuset") == 0 ||
 
167
            strcmp(type, "securityfs") == 0 ||
 
168
            strcmp(type, "hugetlbfs") == 0 ||
 
169
            strcmp(type, "rpc_pipefs") == 0 ||
 
170
            strcmp(type, "fusectl") == 0 ||
 
171
            strcmp(type, "mqueue") == 0 ||
 
172
            strcmp(type, "binfmt_misc") == 0 ||
 
173
            strcmp(type, "fuse.gvfs-fuse-daemon") == 0 ||
 
174
            strcmp(type, "debugfs") == 0 ||
 
175
            strcmp(type, "spufs") == 0)
 
176
                return 1;
 
177
        return 0;
 
178
}
 
179
 
 
180
/**
 
181
 * mnt_fstype_is_netfs:
 
182
 * @type: filesystem name
 
183
 *
 
184
 * Returns: 1 for filesystems like cifs, nfs, ... or 0.
 
185
 */
 
186
int mnt_fstype_is_netfs(const char *type)
 
187
{
 
188
        if (!type)
 
189
                return 0;
 
190
        if (strcmp(type, "cifs")   == 0 ||
 
191
            strcmp(type, "smbfs")  == 0 ||
 
192
            strncmp(type,"nfs", 3) == 0 ||
 
193
            strcmp(type, "afs")    == 0 ||
 
194
            strcmp(type, "ncpfs")  == 0 ||
 
195
            strncmp(type,"9p", 2)  == 0)
 
196
                return 1;
 
197
        return 0;
 
198
}
 
199
 
 
200
/**
 
201
 * mnt_match_fstype:
 
202
 * @type: filesystem type
 
203
 * @pattern: filesystem name or comma delimited list of names
 
204
 *
 
205
 * The @pattern list of filesystem can be prefixed with a global
 
206
 * "no" prefix to invert matching of the whole list. The "no" could
 
207
 * also be used for individual items in the @pattern list. So,
 
208
 * "nofoo,bar" has the same meaning as "nofoo,nobar".
 
209
 *
 
210
 * "bar"  : "nofoo,bar"         -> False   (global "no" prefix)
 
211
 *
 
212
 * "bar"  : "foo,bar"           -> True
 
213
 *
 
214
 * "bar" : "foo,nobar"          -> False
 
215
 *
 
216
 * Returns: 1 if type is matching, else 0. This function also returns
 
217
 *          0 if @pattern is NULL and @type is non-NULL.
 
218
 */
 
219
int mnt_match_fstype(const char *type, const char *pattern)
 
220
{
 
221
        int no = 0;             /* negated types list */
 
222
        int len;
 
223
        const char *p;
 
224
 
 
225
        if (!pattern && !type)
 
226
                return 1;
 
227
        if (!pattern)
 
228
                return 0;
 
229
 
 
230
        if (!strncmp(pattern, "no", 2)) {
 
231
                no = 1;
 
232
                pattern += 2;
 
233
        }
 
234
 
 
235
        /* Does type occur in types, separated by commas? */
 
236
        len = strlen(type);
 
237
        p = pattern;
 
238
        while(1) {
 
239
                if (!strncmp(p, "no", 2) && !strncmp(p+2, type, len) &&
 
240
                    (p[len+2] == 0 || p[len+2] == ','))
 
241
                        return 0;
 
242
                if (strncmp(p, type, len) == 0 && (p[len] == 0 || p[len] == ','))
 
243
                        return !no;
 
244
                p = strchr(p,',');
 
245
                if (!p)
 
246
                        break;
 
247
                p++;
 
248
        }
 
249
        return no;
 
250
}
 
251
 
 
252
 
 
253
/* Returns 1 if needle found or noneedle not found in haystack
 
254
 * Otherwise returns 0
 
255
 */
 
256
static int check_option(const char *haystack, size_t len,
 
257
                        const char *needle, size_t needle_len)
 
258
{
 
259
        const char *p;
 
260
        int no = 0;
 
261
 
 
262
        if (needle_len >= 2 && !strncmp(needle, "no", 2)) {
 
263
                no = 1;
 
264
                needle += 2;
 
265
                needle_len -= 2;
 
266
        }
 
267
 
 
268
        for (p = haystack; p && p < haystack + len; p++) {
 
269
                char *sep = strchr(p, ',');
 
270
                size_t plen = sep ? (size_t) (sep - p) :
 
271
                                    len - (p - haystack);
 
272
 
 
273
                if (plen == needle_len) {
 
274
                        if (!strncmp(p, needle, plen))
 
275
                                return !no;     /* foo or nofoo was found */
 
276
                }
 
277
                p += plen;
 
278
        }
 
279
 
 
280
        return no;  /* foo or nofoo was not found */
 
281
}
 
282
 
 
283
/**
 
284
 * mnt_match_options:
 
285
 * @optstr: options string
 
286
 * @pattern: comma delimited list of options
 
287
 *
 
288
 * The "no" could used for individual items in the @options list. The "no"
 
289
 * prefix does not have a global meaning.
 
290
 *
 
291
 * Unlike fs type matching, nonetdev,user and nonetdev,nouser have
 
292
 * DIFFERENT meanings; each option is matched explicitly as specified.
 
293
 *
 
294
 * "xxx,yyy,zzz" : "nozzz"      -> False
 
295
 *
 
296
 * "xxx,yyy,zzz" : "xxx,noeee"  -> True
 
297
 *
 
298
 * Returns: 1 if pattern is matching, else 0. This function also returns 0
 
299
 *          if @pattern is NULL and @optstr is non-NULL.
 
300
 */
 
301
int mnt_match_options(const char *optstr, const char *pattern)
 
302
{
 
303
        const char *p;
 
304
        size_t len, optstr_len = 0;
 
305
 
 
306
        if (!pattern && !optstr)
 
307
                return 1;
 
308
        if (!pattern)
 
309
                return 0;
 
310
 
 
311
        len = strlen(pattern);
 
312
        if (optstr)
 
313
                optstr_len = strlen(optstr);
 
314
 
 
315
        for (p = pattern; p < pattern + len; p++) {
 
316
                char *sep = strchr(p, ',');
 
317
                size_t plen = sep ? (size_t) (sep - p) :
 
318
                                    len - (p - pattern);
 
319
 
 
320
                if (!plen)
 
321
                        continue; /* if two ',' appear in a row */
 
322
 
 
323
                if (!check_option(optstr, optstr_len, p, plen))
 
324
                        return 0; /* any match failure means failure */
 
325
 
 
326
                p += plen;
 
327
        }
 
328
 
 
329
        /* no match failures in list means success */
 
330
        return 1;
 
331
}
 
332
 
 
333
void mnt_free_filesystems(char **filesystems)
 
334
{
 
335
        char **p;
 
336
 
 
337
        if (!filesystems)
 
338
                return;
 
339
        for (p = filesystems; *p; p++)
 
340
                free(*p);
 
341
        free(filesystems);
 
342
}
 
343
 
 
344
static int add_filesystem(char ***filesystems, char *name)
 
345
{
 
346
        int n = 0;
 
347
 
 
348
        assert(filesystems);
 
349
        assert(name);
 
350
 
 
351
        if (*filesystems) {
 
352
                char **p;
 
353
                for (n = 0, p = *filesystems; *p; p++, n++) {
 
354
                        if (strcmp(*p, name) == 0)
 
355
                                return 0;
 
356
                }
 
357
        }
 
358
 
 
359
        #define MYCHUNK 16
 
360
 
 
361
        if (n == 0 || !((n + 1) % MYCHUNK)) {
 
362
                size_t items = ((n + 1 + MYCHUNK) / MYCHUNK) * MYCHUNK;
 
363
                char **x = realloc(*filesystems, items * sizeof(char *));
 
364
 
 
365
                if (!x)
 
366
                        goto err;
 
367
                *filesystems = x;
 
368
        }
 
369
        name = strdup(name);
 
370
        if (!name)
 
371
                goto err;
 
372
        (*filesystems)[n] = name;
 
373
        (*filesystems)[n + 1] = NULL;
 
374
        return 0;
 
375
err:
 
376
        mnt_free_filesystems(*filesystems);
 
377
        return -ENOMEM;
 
378
}
 
379
 
 
380
static int get_filesystems(const char *filename, char ***filesystems, const char *pattern)
 
381
{
 
382
        FILE *f;
 
383
        char line[128];
 
384
 
 
385
        f = fopen(filename, "r");
 
386
        if (!f)
 
387
                return 0;
 
388
 
 
389
        while (fgets(line, sizeof(line), f)) {
 
390
                char name[sizeof(line)];
 
391
                int rc;
 
392
 
 
393
                if (*line == '#' || strncmp(line, "nodev", 5) == 0)
 
394
                        continue;
 
395
                if (sscanf(line, " %128[^\n ]\n", name) != 1)
 
396
                        continue;
 
397
                if (pattern && !mnt_match_fstype(name, pattern))
 
398
                        continue;
 
399
                rc = add_filesystem(filesystems, name);
 
400
                if (rc)
 
401
                        return rc;
 
402
        }
 
403
        return 0;
 
404
}
 
405
 
 
406
int mnt_get_filesystems(char ***filesystems, const char *pattern)
 
407
{
 
408
        int rc;
 
409
 
 
410
        if (!filesystems)
 
411
                return -EINVAL;
 
412
        *filesystems = NULL;
 
413
 
 
414
        rc = get_filesystems(_PATH_FILESYSTEMS, filesystems, pattern);
 
415
        if (rc)
 
416
                return rc;
 
417
        return get_filesystems(_PATH_PROC_FILESYSTEMS, filesystems, pattern);
 
418
}
 
419
 
 
420
/*
 
421
 * Returns allocated string with username or NULL.
 
422
 */
 
423
char *mnt_get_username(const uid_t uid)
 
424
{
 
425
        struct passwd pwd;
 
426
        struct passwd *res;
 
427
#ifdef _SC_GETPW_R_SIZE_MAX
 
428
        size_t sz = sysconf(_SC_GETPW_R_SIZE_MAX);
 
429
#else
 
430
        size_t sz = 0;
 
431
#endif
 
432
        char *buf, *username = NULL;
 
433
 
 
434
        if (sz <= 0)
 
435
                sz = 16384;        /* Should be more than enough */
 
436
 
 
437
        buf = malloc(sz);
 
438
        if (!buf)
 
439
                return NULL;
 
440
 
 
441
        if (!getpwuid_r(uid, &pwd, buf, sz, &res) && res)
 
442
                username = strdup(pwd.pw_name);
 
443
 
 
444
        free(buf);
 
445
        return username;
 
446
}
 
447
 
 
448
int mnt_get_uid(const char *username, uid_t *uid)
 
449
{
 
450
        int rc = -1;
 
451
        struct passwd pwd;
 
452
        struct passwd *pw;
 
453
        size_t sz = sysconf(_SC_GETPW_R_SIZE_MAX);
 
454
        char *buf;
 
455
 
 
456
        if (!username || !uid)
 
457
                return -EINVAL;
 
458
        if (sz <= 0)
 
459
                sz = 16384;        /* Should be more than enough */
 
460
 
 
461
        buf = malloc(sz);
 
462
        if (!buf)
 
463
                return -ENOMEM;
 
464
 
 
465
        if (!getpwnam_r(username, &pwd, buf, sz, &pw) && pw) {
 
466
                *uid= pw->pw_uid;
 
467
                rc = 0;
 
468
        } else {
 
469
                DBG(UTILS, mnt_debug(
 
470
                        "cannot convert '%s' username to UID", username));
 
471
        }
 
472
 
 
473
        free(buf);
 
474
        return rc;
 
475
}
 
476
 
 
477
int mnt_get_gid(const char *groupname, gid_t *gid)
 
478
{
 
479
        int rc = -1;
 
480
        struct group grp;
 
481
        struct group *gr;
 
482
        size_t sz = sysconf(_SC_GETGR_R_SIZE_MAX);
 
483
        char *buf;
 
484
 
 
485
        if (!groupname || !gid)
 
486
                return -EINVAL;
 
487
        if (sz <= 0)
 
488
                sz = 16384;        /* Should be more than enough */
 
489
 
 
490
        buf = malloc(sz);
 
491
        if (!buf)
 
492
                return -ENOMEM;
 
493
 
 
494
        if (!getgrnam_r(groupname, &grp, buf, sz, &gr) && gr) {
 
495
                *gid= gr->gr_gid;
 
496
                rc = 0;
 
497
        } else {
 
498
                DBG(UTILS, mnt_debug(
 
499
                        "cannot convert '%s' groupname to GID", groupname));
 
500
        }
 
501
 
 
502
        free(buf);
 
503
        return rc;
 
504
}
 
505
 
 
506
int mnt_in_group(gid_t gid)
 
507
{
 
508
        int rc = 0, n, i;
 
509
        gid_t *grps = NULL;
 
510
 
 
511
        if (getgid() == gid)
 
512
                return 1;
 
513
 
 
514
        n = getgroups(0, NULL);
 
515
        if (n <= 0)
 
516
                goto done;
 
517
 
 
518
        grps = malloc(n * sizeof(*grps));
 
519
        if (!grps)
 
520
                goto done;
 
521
 
 
522
        if (getgroups(n, grps) == n) {
 
523
                for (i = 0; i < n; i++) {
 
524
                        if (grps[i] == gid) {
 
525
                                rc = 1;
 
526
                                break;
 
527
                        }
 
528
                }
 
529
        }
 
530
done:
 
531
        free(grps);
 
532
        return rc;
 
533
}
 
534
 
 
535
static int try_write(const char *filename)
 
536
{
 
537
        int fd;
 
538
 
 
539
        if (!filename)
 
540
                return -EINVAL;
 
541
 
 
542
        fd = open(filename, O_RDWR|O_CREAT, S_IWUSR| \
 
543
                                            S_IRUSR|S_IRGRP|S_IROTH);
 
544
        if (fd >= 0) {
 
545
                close(fd);
 
546
                return 0;
 
547
        }
 
548
        return -errno;
 
549
}
 
550
 
 
551
/**
 
552
 * mnt_has_regular_mtab:
 
553
 * @mtab: returns path to mtab
 
554
 * @writable: returns 1 if the file is writable
 
555
 *
 
556
 * If the file does not exist and @writable argument is not NULL then it will
 
557
 * try to create the file
 
558
 *
 
559
 * Returns: 1 if /etc/mtab is a regular file, and 0 in case of error (check
 
560
 *          errno for more details).
 
561
 */
 
562
int mnt_has_regular_mtab(const char **mtab, int *writable)
 
563
{
 
564
        struct stat st;
 
565
        int rc;
 
566
        const char *filename = mtab && *mtab ? *mtab : mnt_get_mtab_path();
 
567
 
 
568
        if (writable)
 
569
                *writable = 0;
 
570
        if (mtab && !*mtab)
 
571
                *mtab = filename;
 
572
 
 
573
        DBG(UTILS, mnt_debug("mtab: %s", filename));
 
574
 
 
575
        rc = lstat(filename, &st);
 
576
 
 
577
        if (rc == 0) {
 
578
                /* file exist */
 
579
                if (S_ISREG(st.st_mode)) {
 
580
                        if (writable)
 
581
                                *writable = !try_write(filename);
 
582
                        return 1;
 
583
                }
 
584
                goto done;
 
585
        }
 
586
 
 
587
        /* try to create the file */
 
588
        if (writable) {
 
589
                *writable = !try_write(filename);
 
590
                if (*writable)
 
591
                        return 1;
 
592
        }
 
593
 
 
594
done:
 
595
        DBG(UTILS, mnt_debug("%s: irregular/non-writable", filename));
 
596
        return 0;
 
597
}
 
598
 
 
599
/*
 
600
 * Don't export this to libmount API -- utab is private library stuff.
 
601
 *
 
602
 * If the file does not exist and @writable argument is not NULL then it will
 
603
 * try to create the directory (e.g. /run/mount) and the file.
 
604
 *
 
605
 * Returns: 1 if utab is a regular file, and 0 in case of
 
606
 *          error (check errno for more details).
 
607
 */
 
608
int mnt_has_regular_utab(const char **utab, int *writable)
 
609
{
 
610
        struct stat st;
 
611
        int rc;
 
612
        const char *filename = utab && *utab ? *utab : mnt_get_utab_path();
 
613
 
 
614
        if (writable)
 
615
                *writable = 0;
 
616
        if (utab && !*utab)
 
617
                *utab = filename;
 
618
 
 
619
        DBG(UTILS, mnt_debug("utab: %s", filename));
 
620
 
 
621
        rc = lstat(filename, &st);
 
622
 
 
623
        if (rc == 0) {
 
624
                /* file exist */
 
625
                if (S_ISREG(st.st_mode)) {
 
626
                        if (writable)
 
627
                                *writable = !try_write(filename);
 
628
                        return 1;
 
629
                }
 
630
                goto done;      /* it's not regular file */
 
631
        }
 
632
 
 
633
        if (writable) {
 
634
                char *dirname = strdup(filename);
 
635
 
 
636
                if (!dirname)
 
637
                        goto done;
 
638
 
 
639
                stripoff_last_component(dirname);       /* remove filename */
 
640
 
 
641
                rc = mkdir(dirname, S_IWUSR|
 
642
                                    S_IRUSR|S_IRGRP|S_IROTH|
 
643
                                    S_IXUSR|S_IXGRP|S_IXOTH);
 
644
                free(dirname);
 
645
                if (rc && errno != EEXIST)
 
646
                        goto done;                      /* probably EACCES */
 
647
 
 
648
                *writable = !try_write(filename);
 
649
                if (*writable)
 
650
                        return 1;
 
651
        }
 
652
done:
 
653
        DBG(UTILS, mnt_debug("%s: irregular/non-writable file", filename));
 
654
        return 0;
 
655
}
 
656
 
 
657
/**
 
658
 * mnt_get_fstab_path:
 
659
 *
 
660
 * Returns: path to /etc/fstab or $LIBMOUNT_FSTAB.
 
661
 */
 
662
const char *mnt_get_fstab_path(void)
 
663
{
 
664
        const char *p = safe_getenv("LIBMOUNT_FSTAB");
 
665
        return p ? : _PATH_MNTTAB;
 
666
}
 
667
 
 
668
/**
 
669
 * mnt_get_mtab_path:
 
670
 *
 
671
 * This function returns *default* location of the mtab file. The result does
 
672
 * not have to be writable. See also mnt_has_regular_mtab().
 
673
 *
 
674
 * Returns: path to /etc/mtab or $LIBMOUNT_MTAB.
 
675
 */
 
676
const char *mnt_get_mtab_path(void)
 
677
{
 
678
        const char *p = safe_getenv("LIBMOUNT_MTAB");
 
679
        return p ? : _PATH_MOUNTED;
 
680
}
 
681
 
 
682
/*
 
683
 * Don't export this to libmount API -- utab is private library stuff.
 
684
 *
 
685
 * Returns: path to /run/mount/utab (or /dev/.mount/utab) or $LIBMOUNT_UTAB.
 
686
 */
 
687
const char *mnt_get_utab_path(void)
 
688
{
 
689
        struct stat st;
 
690
        const char *p = safe_getenv("LIBMOUNT_UTAB");
 
691
 
 
692
        if (p)
 
693
                return p;
 
694
 
 
695
        if (stat(MNT_RUNTIME_TOPDIR, &st) == 0)
 
696
                return MNT_PATH_UTAB;
 
697
 
 
698
        return MNT_PATH_UTAB_OLD;
 
699
}
 
700
 
 
701
 
 
702
/* returns file descriptor or -errno, @name returns uniques filename
 
703
 */
 
704
int mnt_open_uniq_filename(const char *filename, char **name)
 
705
{
 
706
        int rc, fd;
 
707
        char *n;
 
708
 
 
709
        assert(filename);
 
710
 
 
711
        if (name)
 
712
                *name = NULL;
 
713
 
 
714
        rc = asprintf(&n, "%s.XXXXXX", filename);
 
715
        if (rc <= 0)
 
716
                return -errno;
 
717
 
 
718
        fd = mkstemp(n);
 
719
        if (fd >= 0 && name)
 
720
                *name = n;
 
721
        else
 
722
                free(n);
 
723
 
 
724
        return fd < 0 ? -errno : fd;
 
725
}
 
726
 
 
727
char *mnt_get_mountpoint(const char *path)
 
728
{
 
729
        char *mnt = strdup(path);
 
730
        struct stat st;
 
731
        dev_t dir, base;
 
732
 
 
733
        if (!mnt)
 
734
                return NULL;
 
735
        if (*mnt == '/' && *(mnt + 1) == '\0')
 
736
                goto done;
 
737
 
 
738
        if (stat(mnt, &st))
 
739
                goto err;
 
740
        base = st.st_dev;
 
741
 
 
742
        do {
 
743
                char *p = stripoff_last_component(mnt);
 
744
 
 
745
                if (!p)
 
746
                        break;
 
747
                if (stat(*mnt ? mnt : "/", &st))
 
748
                        goto err;
 
749
                dir = st.st_dev;
 
750
                if (dir != base) {
 
751
                        *(p - 1) = '/';
 
752
                        goto done;
 
753
                }
 
754
                base = dir;
 
755
        } while (mnt && *(mnt + 1) != '\0');
 
756
 
 
757
        memcpy(mnt, "/", 2);
 
758
done:
 
759
        DBG(UTILS, mnt_debug("%s mountpoint is %s", path, mnt));
 
760
        return mnt;
 
761
err:
 
762
        free(mnt);
 
763
        return NULL;
 
764
}
 
765
 
 
766
char *mnt_get_fs_root(const char *path, const char *mnt)
 
767
{
 
768
        char *m = (char *) mnt, *res;
 
769
        const char *p;
 
770
        size_t sz;
 
771
 
 
772
        if (!m)
 
773
                m = mnt_get_mountpoint(path);
 
774
        if (!m)
 
775
                return NULL;
 
776
 
 
777
        sz = strlen(m);
 
778
        p = sz > 1 ? path + sz : path;
 
779
 
 
780
        if (m != mnt)
 
781
                free(m);
 
782
 
 
783
        res = *p ? strdup(p) : strdup("/");
 
784
        DBG(UTILS, mnt_debug("%s fs-root is %s", path, res));
 
785
        return res;
 
786
}
 
787
 
 
788
#ifdef TEST_PROGRAM
 
789
int test_match_fstype(struct libmnt_test *ts, int argc, char *argv[])
 
790
{
 
791
        char *type = argv[1];
 
792
        char *pattern = argv[2];
 
793
 
 
794
        printf("%s\n", mnt_match_fstype(type, pattern) ? "MATCH" : "NOT-MATCH");
 
795
        return 0;
 
796
}
 
797
 
 
798
int test_match_options(struct libmnt_test *ts, int argc, char *argv[])
 
799
{
 
800
        char *optstr = argv[1];
 
801
        char *pattern = argv[2];
 
802
 
 
803
        printf("%s\n", mnt_match_options(optstr, pattern) ? "MATCH" : "NOT-MATCH");
 
804
        return 0;
 
805
}
 
806
 
 
807
int test_startswith(struct libmnt_test *ts, int argc, char *argv[])
 
808
{
 
809
        char *optstr = argv[1];
 
810
        char *pattern = argv[2];
 
811
 
 
812
        printf("%s\n", startswith(optstr, pattern) ? "YES" : "NOT");
 
813
        return 0;
 
814
}
 
815
 
 
816
int test_endswith(struct libmnt_test *ts, int argc, char *argv[])
 
817
{
 
818
        char *optstr = argv[1];
 
819
        char *pattern = argv[2];
 
820
 
 
821
        printf("%s\n", endswith(optstr, pattern) ? "YES" : "NOT");
 
822
        return 0;
 
823
}
 
824
 
 
825
int test_mountpoint(struct libmnt_test *ts, int argc, char *argv[])
 
826
{
 
827
        char *path = canonicalize_path(argv[1]),
 
828
             *mnt = path ? mnt_get_mountpoint(path) :  NULL;
 
829
 
 
830
        printf("%s: %s\n", argv[1], mnt ? : "unknown");
 
831
        free(mnt);
 
832
        free(path);
 
833
        return 0;
 
834
}
 
835
 
 
836
int test_fsroot(struct libmnt_test *ts, int argc, char *argv[])
 
837
{
 
838
        char *path = canonicalize_path(argv[1]),
 
839
             *mnt = path ? mnt_get_fs_root(path, NULL) : NULL;
 
840
 
 
841
        printf("%s: %s\n", argv[1], mnt ? : "unknown");
 
842
        free(mnt);
 
843
        free(path);
 
844
        return 0;
 
845
}
 
846
 
 
847
int test_filesystems(struct libmnt_test *ts, int argc, char *argv[])
 
848
{
 
849
        char **filesystems = NULL;
 
850
        int rc;
 
851
 
 
852
        rc = mnt_get_filesystems(&filesystems, argc ? argv[1] : NULL);
 
853
        if (!rc) {
 
854
                char **p;
 
855
                for (p = filesystems; *p; p++)
 
856
                        printf("%s\n", *p);
 
857
                mnt_free_filesystems(filesystems);
 
858
        }
 
859
        return rc;
 
860
}
 
861
 
 
862
int test_chdir(struct libmnt_test *ts, int argc, char *argv[])
 
863
{
 
864
        int rc;
 
865
        char *path = canonicalize_path(argv[1]),
 
866
             *last = NULL;
 
867
 
 
868
        if (!path)
 
869
                return -errno;
 
870
 
 
871
        rc = mnt_chdir_to_parent(path, &last);
 
872
        if (!rc) {
 
873
                printf("path='%s', abs='%s', last='%s'\n",
 
874
                                argv[1], path, last);
 
875
        }
 
876
        free(path);
 
877
        free(last);
 
878
        return rc;
 
879
}
 
880
 
 
881
 
 
882
int main(int argc, char *argv[])
 
883
{
 
884
        struct libmnt_test tss[] = {
 
885
        { "--match-fstype",  test_match_fstype,    "<type> <pattern>     FS types matching" },
 
886
        { "--match-options", test_match_options,   "<options> <pattern>  options matching" },
 
887
        { "--filesystems",   test_filesystems,     "[<pattern>] list /{etc,proc}/filesystems" },
 
888
        { "--starts-with",   test_startswith,      "<string> <prefix>" },
 
889
        { "--ends-with",     test_endswith,        "<string> <prefix>" },
 
890
        { "--mountpoint",    test_mountpoint,      "<path>" },
 
891
        { "--fs-root",       test_fsroot,          "<path>" },
 
892
        { "--cd-parent",     test_chdir,           "<path>" },
 
893
        { NULL }
 
894
        };
 
895
 
 
896
        return mnt_run_test(tss, argc, argv);
 
897
}
 
898
 
 
899
#endif /* TEST_PROGRAM */