]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libfrog/paths.c
abb29a237e80684ea9541abc9f73c405dedf6858
1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2005-2006 Silicon Graphics, Inc.
13 #include <sys/types.h>
20 extern char *progname
;
24 struct fs_path
*fs_table
;
25 struct fs_path
*fs_path
;
28 #define PROC_MOUNTS "/proc/self/mounts"
37 if (stat(name
, &sbuf
) < 0)
40 * We want to match st_rdev if the path provided is a device
41 * special file. Otherwise we are looking for the the
42 * device id for the containing filesystem, in st_dev.
44 if (S_ISBLK(sbuf
.st_mode
) || S_ISCHR(sbuf
.st_mode
))
45 *devnum
= sbuf
.st_rdev
;
47 *devnum
= sbuf
.st_dev
;
53 * Find the FS table entry for the given path. The "flags" argument
54 * is a mask containing FS_MOUNT_POINT or FS_PROJECT_PATH (or both)
55 * to indicate the type of table entry sought.
56 * fs_table_lookup() finds the fs table entry for the filesystem hosting
57 * the file represented in the "dir" argument. To compare against actual
58 * mount point entries, use fs_table_lookup_mount() instead.
68 if (fs_device_number(dir
, &dev
))
71 for (i
= 0; i
< fs_count
; i
++) {
72 if (flags
&& !(flags
& fs_table
[i
].fs_flags
))
74 if (fs_table
[i
].fs_datadev
== dev
)
80 static struct fs_path
*
81 __fs_table_lookup_mount(
92 if (dir
&& !realpath(dir
, dpath
))
94 if (blkdev
&& !realpath(blkdev
, dpath
))
97 for (i
= 0; i
< fs_count
; i
++) {
98 if (fs_table
[i
].fs_flags
!= FS_MOUNT_POINT
)
100 if (dir
&& !realpath(fs_table
[i
].fs_dir
, rpath
))
102 if (blkdev
&& !realpath(fs_table
[i
].fs_name
, rpath
))
104 if (strcmp(rpath
, dpath
) == 0)
111 * Find the FS table entry describing an actual mount for the given path.
112 * Unlike fs_table_lookup(), fs_table_lookup_mount() compares the "dir"
113 * argument to actual mount point entries in the table. Accordingly, it
114 * will find matches only if the "dir" argument is indeed mounted.
117 fs_table_lookup_mount(
120 return __fs_table_lookup_mount(dir
, NULL
);
124 * Find the FS table entry describing an actual mount for the block device.
125 * Unlike fs_table_lookup(), fs_table_lookup_blkdev() compares the "bdev"
126 * argument to actual mount point names in the table. Accordingly, it
127 * will find matches only if the "bdev" argument is indeed mounted.
130 fs_table_lookup_blkdev(
133 return __fs_table_lookup_mount(NULL
, bdev
);
145 dev_t datadev
, logdev
, rtdev
;
146 struct fs_path
*tmp_fs_table
;
149 datadev
= logdev
= rtdev
= 0;
150 error
= fs_device_number(dir
, &datadev
);
154 error
= fs_device_number(fslog
, &logdev
);
159 error
= fs_device_number(fsrt
, &rtdev
);
164 if (!platform_test_xfs_path(dir
))
168 * Make copies of the directory and data device path.
169 * The log device and real-time device, if non-null,
170 * are already the result of strdup() calls so we
171 * don't need to duplicate those. In fact, this
172 * function is assumed to "consume" both of those
173 * pointers, meaning if an error occurs they will
180 fsname
= strdup(fsname
);
184 tmp_fs_table
= realloc(fs_table
, sizeof(fs_path_t
) * (fs_count
+ 1));
187 fs_table
= tmp_fs_table
;
189 /* Put foreign filesystems at the end, xfs filesystems at the front */
190 if (flags
& FS_FOREIGN
|| fs_count
== 0) {
191 fs_path
= &fs_table
[fs_count
];
193 /* move foreign fs entries down, insert new one just before */
194 memmove(&fs_table
[xfs_fs_count
+ 1], &fs_table
[xfs_fs_count
],
195 sizeof(fs_path_t
)*(fs_count
- xfs_fs_count
));
196 fs_path
= &fs_table
[xfs_fs_count
];
198 fs_path
->fs_dir
= dir
;
199 fs_path
->fs_prid
= prid
;
200 fs_path
->fs_flags
= flags
;
201 fs_path
->fs_name
= fsname
;
202 fs_path
->fs_log
= fslog
;
203 fs_path
->fs_rt
= fsrt
;
204 fs_path
->fs_datadev
= datadev
;
205 fs_path
->fs_logdev
= logdev
;
206 fs_path
->fs_rtdev
= rtdev
;
208 if (!(flags
& FS_FOREIGN
))
218 /* "Consume" fslog and fsrt even if there's an error */
225 /* Remove all the cached entries in the fs table. */
227 fs_table_destroy(void)
232 for (i
= 0, fsp
= fs_table
; i
< fs_count
; i
++, fsp
++) {
246 * Table iteration (cursor-based) interfaces
250 * Initialize an fs_table cursor. If a directory path is supplied,
251 * the cursor is set up to appear as though the table contains only
252 * a single entry which represents the directory specified.
253 * Otherwise it is set up to prepare for visiting all entries in the
254 * global table, starting with the first. "flags" can be either
255 * FS_MOUNT_POINT or FS_PROJECT_PATH to limit what type of entries
256 * will be selected by fs_cursor_next_entry(). 0 can be used as a
257 * wild card (selecting either type).
260 fs_cursor_initialise(
267 memset(cur
, 0, sizeof(*cur
));
269 if ((path
= fs_table_lookup(dir
, flags
)) == NULL
)
273 cur
->table
= &cur
->local
;
275 cur
->count
= fs_count
;
276 cur
->table
= fs_table
;
282 * Use the cursor to find the next entry in the table having the
283 * type specified by the cursor's "flags" field.
286 fs_cursor_next_entry(
289 while (cur
->index
< cur
->count
) {
290 fs_path_t
*next
= &cur
->table
[cur
->index
++];
292 if (!cur
->flags
|| (cur
->flags
& next
->fs_flags
))
299 #if defined(HAVE_GETMNTENT)
303 * Determines whether the "logdev" or "rtdev" mount options are
304 * present for the given mount point. If so, the value for each (a
305 * device path) is returned in the pointers whose addresses are
306 * provided. The pointers are assigned NULL for an option not
307 * present. Note that the path buffers returned are allocated
308 * dynamically and it is the caller's responsibility to free them.
311 fs_extract_mount_options(
319 * Extract log device and realtime device from mount options.
321 * Note: the glibc hasmntopt implementation requires that the
322 * character in mnt_opts immediately after the search string
323 * must be a NULL ('\0'), a comma (','), or an equals ('=').
324 * Therefore we cannot search for 'logdev=' directly.
326 if ((fslog
= hasmntopt(mnt
, "logdev")) && fslog
[6] == '=')
328 if ((fsrt
= hasmntopt(mnt
, "rtdev")) && fsrt
[5] == '=')
331 /* Do this only after we've finished processing mount options */
333 fslog
= strndup(fslog
, strcspn(fslog
, " ,"));
338 fsrt
= strndup(fsrt
, strcspn(fsrt
, " ,"));
352 fprintf(stderr
, _("%s: unable to extract mount options for \"%s\"\n"),
353 progname
, mnt
->mnt_dir
);
358 * If *path is NULL, initialize the fs table with all xfs mount points in mtab
359 * If *path is specified, search for that path in mtab
361 * Everything - path, devices, and mountpoints - are boiled down to realpath()
362 * for comparison, but fs_table is populated with what comes from getmntent.
365 fs_table_initialise_mounts(
372 char rpath
[PATH_MAX
], rmnt_fsname
[PATH_MAX
], rmnt_dir
[PATH_MAX
];
378 mtab_file
= PROC_MOUNTS
;
379 if (access(mtab_file
, R_OK
) != 0)
383 if ((mtp
= setmntent(mtab_file
, "r")) == NULL
)
386 /* Use realpath to resolve symlinks, relative paths, etc */
388 if (!realpath(path
, rpath
))
391 while ((mnt
= getmntent(mtp
)) != NULL
) {
392 if (!strcmp(mnt
->mnt_type
, "autofs"))
394 if (!realpath(mnt
->mnt_dir
, rmnt_dir
))
396 if (!realpath(mnt
->mnt_fsname
, rmnt_fsname
))
400 ((strcmp(rpath
, rmnt_dir
) != 0) &&
401 (strcmp(rpath
, rmnt_fsname
) != 0)))
403 if (fs_extract_mount_options(mnt
, &fslog
, &fsrt
))
405 (void) fs_table_insert(mnt
->mnt_dir
, 0, FS_MOUNT_POINT
,
406 mnt
->mnt_fsname
, fslog
, fsrt
);
421 # error "How do I extract info about mounted filesystems on this platform?"
425 * Given a directory, match it up to a filesystem mount point.
427 static struct fs_path
*
428 fs_mount_point_from_path(
435 if (fs_device_number(dir
, &dev
))
438 fs_cursor_initialise(NULL
, FS_MOUNT_POINT
, &cursor
);
439 while ((fs
= fs_cursor_next_entry(&cursor
))) {
440 if (fs
->fs_datadev
== dev
)
447 fs_table_insert_mount(
452 error
= fs_table_initialise_mounts(mount
);
454 fprintf(stderr
, _("%s: cannot setup path for mount %s: %s\n"),
455 progname
, mount
, strerror(error
));
459 fs_table_initialise_projects(
462 fs_project_path_t
*path
;
465 int error
= 0, found
= 0;
468 prid
= prid_from_string(project
);
471 while ((path
= getprpathent()) != NULL
) {
472 if (project
&& prid
!= path
->pp_prid
)
474 fs
= fs_mount_point_from_path(path
->pp_pathname
);
476 fprintf(stderr
, _("%s: cannot find mount point for path `%s': %s\n"),
477 progname
, path
->pp_pathname
, strerror(errno
));
480 (void) fs_table_insert(path
->pp_pathname
, path
->pp_prid
,
481 FS_PROJECT_PATH
, fs
->fs_name
,
490 if (project
&& !found
)
497 fs_table_insert_project(
502 error
= fs_table_initialise_projects(project
);
504 fprintf(stderr
, _("%s: cannot setup path for project %s: %s\n"),
505 progname
, project
, strerror(error
));
509 * Initialize fs_table to contain the given set of mount points and
510 * projects. If mount_count is zero, mounts is ignored and the
511 * table is populated with mounted filesystems. If project_count is
512 * zero, projects is ignored and the table is populated with all
513 * projects defined in the projects file.
526 for (i
= 0; i
< mount_count
; i
++)
527 fs_table_insert_mount(mounts
[i
]);
529 error
= fs_table_initialise_mounts(NULL
);
534 for (i
= 0; i
< project_count
; i
++)
535 fs_table_insert_project(projects
[i
]);
537 error
= fs_table_initialise_projects(NULL
);
545 fprintf(stderr
, _("%s: cannot initialise path table: %s\n"),
546 progname
, strerror(error
));
550 fs_table_insert_project_path(
557 fs
= fs_mount_point_from_path(dir
);
559 error
= fs_table_insert(dir
, prid
, FS_PROJECT_PATH
,
560 fs
->fs_name
, NULL
, NULL
);