]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libfrog/paths.c
2 * Copyright (c) 2005-2006 Silicon Graphics, Inc.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 #include <sys/types.h>
32 extern char *progname
;
36 struct fs_path
*fs_table
;
37 struct fs_path
*fs_path
;
40 #define PROC_MOUNTS "/proc/self/mounts"
49 if (stat(name
, &sbuf
) < 0)
52 * We want to match st_rdev if the path provided is a device
53 * special file. Otherwise we are looking for the the
54 * device id for the containing filesystem, in st_dev.
56 if (S_ISBLK(sbuf
.st_mode
) || S_ISCHR(sbuf
.st_mode
))
57 *devnum
= sbuf
.st_rdev
;
59 *devnum
= sbuf
.st_dev
;
65 * Find the FS table entry for the given path. The "flags" argument
66 * is a mask containing FS_MOUNT_POINT or FS_PROJECT_PATH (or both)
67 * to indicate the type of table entry sought.
68 * fs_table_lookup() finds the fs table entry for the filesystem hosting
69 * the file represented in the "dir" argument. To compare against actual
70 * mount point entries, use fs_table_lookup_mount() instead.
80 if (fs_device_number(dir
, &dev
))
83 for (i
= 0; i
< fs_count
; i
++) {
84 if (flags
&& !(flags
& fs_table
[i
].fs_flags
))
86 if (fs_table
[i
].fs_datadev
== dev
)
93 * Find the FS table entry describing an actual mount for the given path.
94 * Unlike fs_table_lookup(), fs_table_lookup_mount() compares the "dir"
95 * argument to actual mount point entries in the table. Accordingly, it
96 * will find matches only if the "dir" argument is indeed mounted.
99 fs_table_lookup_mount(
104 char rpath
[PATH_MAX
];
106 if (fs_device_number(dir
, &dev
))
109 for (i
= 0; i
< fs_count
; i
++) {
110 if (fs_table
[i
].fs_flags
!= FS_MOUNT_POINT
)
112 if (!realpath(fs_table
[i
].fs_dir
, rpath
))
114 if (strcmp(rpath
, dir
) == 0)
129 dev_t datadev
, logdev
, rtdev
;
130 struct fs_path
*tmp_fs_table
;
133 datadev
= logdev
= rtdev
= 0;
134 error
= fs_device_number(dir
, &datadev
);
138 error
= fs_device_number(fslog
, &logdev
);
143 error
= fs_device_number(fsrt
, &rtdev
);
148 if (!platform_test_xfs_path(dir
))
152 * Make copies of the directory and data device path.
153 * The log device and real-time device, if non-null,
154 * are already the result of strdup() calls so we
155 * don't need to duplicate those. In fact, this
156 * function is assumed to "consume" both of those
157 * pointers, meaning if an error occurs they will
164 fsname
= strdup(fsname
);
168 tmp_fs_table
= realloc(fs_table
, sizeof(fs_path_t
) * (fs_count
+ 1));
171 fs_table
= tmp_fs_table
;
173 /* Put foreign filesystems at the end, xfs filesystems at the front */
174 if (flags
& FS_FOREIGN
|| fs_count
== 0) {
175 fs_path
= &fs_table
[fs_count
];
177 /* move foreign fs entries down, insert new one just before */
178 memmove(&fs_table
[xfs_fs_count
+ 1], &fs_table
[xfs_fs_count
],
179 sizeof(fs_path_t
)*(fs_count
- xfs_fs_count
));
180 fs_path
= &fs_table
[xfs_fs_count
];
182 fs_path
->fs_dir
= dir
;
183 fs_path
->fs_prid
= prid
;
184 fs_path
->fs_flags
= flags
;
185 fs_path
->fs_name
= fsname
;
186 fs_path
->fs_log
= fslog
;
187 fs_path
->fs_rt
= fsrt
;
188 fs_path
->fs_datadev
= datadev
;
189 fs_path
->fs_logdev
= logdev
;
190 fs_path
->fs_rtdev
= rtdev
;
192 if (!(flags
& FS_FOREIGN
))
202 /* "Consume" fslog and fsrt even if there's an error */
209 /* Remove all the cached entries in the fs table. */
211 fs_table_destroy(void)
216 for (i
= 0, fsp
= fs_table
; i
< fs_count
; i
++, fsp
++) {
230 * Table iteration (cursor-based) interfaces
234 * Initialize an fs_table cursor. If a directory path is supplied,
235 * the cursor is set up to appear as though the table contains only
236 * a single entry which represents the directory specified.
237 * Otherwise it is set up to prepare for visiting all entries in the
238 * global table, starting with the first. "flags" can be either
239 * FS_MOUNT_POINT or FS_PROJECT_PATH to limit what type of entries
240 * will be selected by fs_cursor_next_entry(). 0 can be used as a
241 * wild card (selecting either type).
244 fs_cursor_initialise(
251 memset(cur
, 0, sizeof(*cur
));
253 if ((path
= fs_table_lookup(dir
, flags
)) == NULL
)
257 cur
->table
= &cur
->local
;
259 cur
->count
= fs_count
;
260 cur
->table
= fs_table
;
266 * Use the cursor to find the next entry in the table having the
267 * type specified by the cursor's "flags" field.
270 fs_cursor_next_entry(
273 while (cur
->index
< cur
->count
) {
274 fs_path_t
*next
= &cur
->table
[cur
->index
++];
276 if (!cur
->flags
|| (cur
->flags
& next
->fs_flags
))
283 #if defined(HAVE_GETMNTENT)
287 * Determines whether the "logdev" or "rtdev" mount options are
288 * present for the given mount point. If so, the value for each (a
289 * device path) is returned in the pointers whose addresses are
290 * provided. The pointers are assigned NULL for an option not
291 * present. Note that the path buffers returned are allocated
292 * dynamically and it is the caller's responsibility to free them.
295 fs_extract_mount_options(
303 * Extract log device and realtime device from mount options.
305 * Note: the glibc hasmntopt implementation requires that the
306 * character in mnt_opts immediately after the search string
307 * must be a NULL ('\0'), a comma (','), or an equals ('=').
308 * Therefore we cannot search for 'logdev=' directly.
310 if ((fslog
= hasmntopt(mnt
, "logdev")) && fslog
[6] == '=')
312 if ((fsrt
= hasmntopt(mnt
, "rtdev")) && fsrt
[5] == '=')
315 /* Do this only after we've finished processing mount options */
317 fslog
= strndup(fslog
, strcspn(fslog
, " ,"));
322 fsrt
= strndup(fsrt
, strcspn(fsrt
, " ,"));
336 fprintf(stderr
, _("%s: unable to extract mount options for \"%s\"\n"),
337 progname
, mnt
->mnt_dir
);
342 * If *path is NULL, initialize the fs table with all xfs mount points in mtab
343 * If *path is specified, search for that path in mtab
345 * Everything - path, devices, and mountpoints - are boiled down to realpath()
346 * for comparison, but fs_table is populated with what comes from getmntent.
349 fs_table_initialise_mounts(
356 char rpath
[PATH_MAX
], rmnt_fsname
[PATH_MAX
], rmnt_dir
[PATH_MAX
];
362 mtab_file
= PROC_MOUNTS
;
363 if (access(mtab_file
, R_OK
) != 0)
367 if ((mtp
= setmntent(mtab_file
, "r")) == NULL
)
370 /* Use realpath to resolve symlinks, relative paths, etc */
372 if (!realpath(path
, rpath
))
375 while ((mnt
= getmntent(mtp
)) != NULL
) {
376 if (!realpath(mnt
->mnt_dir
, rmnt_dir
))
378 if (!realpath(mnt
->mnt_fsname
, rmnt_fsname
))
382 ((strcmp(rpath
, rmnt_dir
) != 0) &&
383 (strcmp(rpath
, rmnt_fsname
) != 0)))
385 if (fs_extract_mount_options(mnt
, &fslog
, &fsrt
))
387 (void) fs_table_insert(mnt
->mnt_dir
, 0, FS_MOUNT_POINT
,
388 mnt
->mnt_fsname
, fslog
, fsrt
);
402 #elif defined(HAVE_GETMNTINFO)
403 #include <sys/mount.h>
406 * If *path is NULL, initialize the fs table with all xfs mount points in mtab
407 * If *path is specified, search for that path in mtab
409 * Everything - path, devices, and mountpoints - are boiled down to realpath()
410 * for comparison, but fs_table is populated with what comes from getmntinfo.
413 fs_table_initialise_mounts(
416 struct statfs
*stats
;
417 int i
, count
, error
, found
;
418 char rpath
[PATH_MAX
], rmntfromname
[PATH_MAX
], rmntonname
[PATH_MAX
];
421 if ((count
= getmntinfo(&stats
, 0)) < 0) {
422 fprintf(stderr
, _("%s: getmntinfo() failed: %s\n"),
423 progname
, strerror(errno
));
427 /* Use realpath to resolve symlinks, relative paths, etc */
429 if (!realpath(path
, rpath
))
432 for (i
= 0; i
< count
; i
++) {
433 if (!realpath(stats
[i
].f_mntfromname
, rmntfromname
))
435 if (!realpath(stats
[i
].f_mntonname
, rmntonname
))
439 ((strcmp(rpath
, rmntonname
) != 0) &&
440 (strcmp(rpath
, rmntfromname
) != 0)))
442 /* TODO: external log and realtime device? */
443 (void) fs_table_insert(stats
[i
].f_mntonname
, 0,
444 FS_MOUNT_POINT
, stats
[i
].f_mntfromname
,
458 # error "How do I extract info about mounted filesystems on this platform?"
462 * Given a directory, match it up to a filesystem mount point.
464 static struct fs_path
*
465 fs_mount_point_from_path(
472 if (fs_device_number(dir
, &dev
))
475 fs_cursor_initialise(NULL
, FS_MOUNT_POINT
, &cursor
);
476 while ((fs
= fs_cursor_next_entry(&cursor
))) {
477 if (fs
->fs_datadev
== dev
)
484 fs_table_insert_mount(
489 error
= fs_table_initialise_mounts(mount
);
491 fprintf(stderr
, _("%s: cannot setup path for mount %s: %s\n"),
492 progname
, mount
, strerror(error
));
496 fs_table_initialise_projects(
499 fs_project_path_t
*path
;
502 int error
= 0, found
= 0;
505 prid
= prid_from_string(project
);
508 while ((path
= getprpathent()) != NULL
) {
509 if (project
&& prid
!= path
->pp_prid
)
511 fs
= fs_mount_point_from_path(path
->pp_pathname
);
513 fprintf(stderr
, _("%s: cannot find mount point for path `%s': %s\n"),
514 progname
, path
->pp_pathname
, strerror(errno
));
517 (void) fs_table_insert(path
->pp_pathname
, path
->pp_prid
,
518 FS_PROJECT_PATH
, fs
->fs_name
,
527 if (project
&& !found
)
534 fs_table_insert_project(
539 error
= fs_table_initialise_projects(project
);
541 fprintf(stderr
, _("%s: cannot setup path for project %s: %s\n"),
542 progname
, project
, strerror(error
));
546 * Initialize fs_table to contain the given set of mount points and
547 * projects. If mount_count is zero, mounts is ignored and the
548 * table is populated with mounted filesystems. If project_count is
549 * zero, projects is ignored and the table is populated with all
550 * projects defined in the projects file.
563 for (i
= 0; i
< mount_count
; i
++)
564 fs_table_insert_mount(mounts
[i
]);
566 error
= fs_table_initialise_mounts(NULL
);
571 for (i
= 0; i
< project_count
; i
++)
572 fs_table_insert_project(projects
[i
]);
574 error
= fs_table_initialise_projects(NULL
);
582 fprintf(stderr
, _("%s: cannot initialise path table: %s\n"),
583 progname
, strerror(error
));
587 fs_table_insert_project_path(
594 fs
= fs_mount_point_from_path(dir
);
596 error
= fs_table_insert(dir
, prid
, FS_PROJECT_PATH
,
597 fs
->fs_name
, NULL
, NULL
);
602 fprintf(stderr
, _("%s: cannot setup path for project dir %s: %s\n"),
603 progname
, dir
, strerror(error
));