]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libxcmd/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 */
210 * Table iteration (cursor-based) interfaces
214 * Initialize an fs_table cursor. If a directory path is supplied,
215 * the cursor is set up to appear as though the table contains only
216 * a single entry which represents the directory specified.
217 * Otherwise it is set up to prepare for visiting all entries in the
218 * global table, starting with the first. "flags" can be either
219 * FS_MOUNT_POINT or FS_PROJECT_PATH to limit what type of entries
220 * will be selected by fs_cursor_next_entry(). 0 can be used as a
221 * wild card (selecting either type).
224 fs_cursor_initialise(
231 memset(cur
, 0, sizeof(*cur
));
233 if ((path
= fs_table_lookup(dir
, flags
)) == NULL
)
237 cur
->table
= &cur
->local
;
239 cur
->count
= fs_count
;
240 cur
->table
= fs_table
;
246 * Use the cursor to find the next entry in the table having the
247 * type specified by the cursor's "flags" field.
250 fs_cursor_next_entry(
253 while (cur
->index
< cur
->count
) {
254 fs_path_t
*next
= &cur
->table
[cur
->index
++];
256 if (!cur
->flags
|| (cur
->flags
& next
->fs_flags
))
263 #if defined(HAVE_GETMNTENT)
267 * Determines whether the "logdev" or "rtdev" mount options are
268 * present for the given mount point. If so, the value for each (a
269 * device path) is returned in the pointers whose addresses are
270 * provided. The pointers are assigned NULL for an option not
271 * present. Note that the path buffers returned are allocated
272 * dynamically and it is the caller's responsibility to free them.
275 fs_extract_mount_options(
283 * Extract log device and realtime device from mount options.
285 * Note: the glibc hasmntopt implementation requires that the
286 * character in mnt_opts immediately after the search string
287 * must be a NULL ('\0'), a comma (','), or an equals ('=').
288 * Therefore we cannot search for 'logdev=' directly.
290 if ((fslog
= hasmntopt(mnt
, "logdev")) && fslog
[6] == '=')
292 if ((fsrt
= hasmntopt(mnt
, "rtdev")) && fsrt
[5] == '=')
295 /* Do this only after we've finished processing mount options */
297 fslog
= strndup(fslog
, strcspn(fslog
, " ,"));
302 fsrt
= strndup(fsrt
, strcspn(fsrt
, " ,"));
316 fprintf(stderr
, _("%s: unable to extract mount options for \"%s\"\n"),
317 progname
, mnt
->mnt_dir
);
322 * If *path is NULL, initialize the fs table with all xfs mount points in mtab
323 * If *path is specified, search for that path in mtab
325 * Everything - path, devices, and mountpoints - are boiled down to realpath()
326 * for comparison, but fs_table is populated with what comes from getmntent.
329 fs_table_initialise_mounts(
336 char rpath
[PATH_MAX
], rmnt_fsname
[PATH_MAX
], rmnt_dir
[PATH_MAX
];
342 mtab_file
= PROC_MOUNTS
;
343 if (access(mtab_file
, R_OK
) != 0)
347 if ((mtp
= setmntent(mtab_file
, "r")) == NULL
)
350 /* Use realpath to resolve symlinks, relative paths, etc */
352 if (!realpath(path
, rpath
))
355 while ((mnt
= getmntent(mtp
)) != NULL
) {
356 if (!realpath(mnt
->mnt_dir
, rmnt_dir
))
358 if (!realpath(mnt
->mnt_fsname
, rmnt_fsname
))
362 ((strcmp(rpath
, rmnt_dir
) != 0) &&
363 (strcmp(rpath
, rmnt_fsname
) != 0)))
365 if (fs_extract_mount_options(mnt
, &fslog
, &fsrt
))
367 (void) fs_table_insert(mnt
->mnt_dir
, 0, FS_MOUNT_POINT
,
368 mnt
->mnt_fsname
, fslog
, fsrt
);
382 #elif defined(HAVE_GETMNTINFO)
383 #include <sys/mount.h>
386 * If *path is NULL, initialize the fs table with all xfs mount points in mtab
387 * If *path is specified, search for that path in mtab
389 * Everything - path, devices, and mountpoints - are boiled down to realpath()
390 * for comparison, but fs_table is populated with what comes from getmntinfo.
393 fs_table_initialise_mounts(
396 struct statfs
*stats
;
397 int i
, count
, error
, found
;
398 char rpath
[PATH_MAX
], rmntfromname
[PATH_MAX
], rmntonname
[PATH_MAX
];
401 if ((count
= getmntinfo(&stats
, 0)) < 0) {
402 fprintf(stderr
, _("%s: getmntinfo() failed: %s\n"),
403 progname
, strerror(errno
));
407 /* Use realpath to resolve symlinks, relative paths, etc */
409 if (!realpath(path
, rpath
))
412 for (i
= 0; i
< count
; i
++) {
413 if (!realpath(stats
[i
].f_mntfromname
, rmntfromname
))
415 if (!realpath(stats
[i
].f_mntonname
, rmntonname
))
419 ((strcmp(rpath
, rmntonname
) != 0) &&
420 (strcmp(rpath
, rmntfromname
) != 0)))
422 /* TODO: external log and realtime device? */
423 (void) fs_table_insert(stats
[i
].f_mntonname
, 0,
424 FS_MOUNT_POINT
, stats
[i
].f_mntfromname
,
438 # error "How do I extract info about mounted filesystems on this platform?"
442 * Given a directory, match it up to a filesystem mount point.
444 static struct fs_path
*
445 fs_mount_point_from_path(
452 if (fs_device_number(dir
, &dev
))
455 fs_cursor_initialise(NULL
, FS_MOUNT_POINT
, &cursor
);
456 while ((fs
= fs_cursor_next_entry(&cursor
))) {
457 if (fs
->fs_datadev
== dev
)
464 fs_table_insert_mount(
469 error
= fs_table_initialise_mounts(mount
);
471 fprintf(stderr
, _("%s: cannot setup path for mount %s: %s\n"),
472 progname
, mount
, strerror(error
));
476 fs_table_initialise_projects(
479 fs_project_path_t
*path
;
482 int error
= 0, found
= 0;
485 prid
= prid_from_string(project
);
488 while ((path
= getprpathent()) != NULL
) {
489 if (project
&& prid
!= path
->pp_prid
)
491 fs
= fs_mount_point_from_path(path
->pp_pathname
);
493 fprintf(stderr
, _("%s: cannot find mount point for path `%s': %s\n"),
494 progname
, path
->pp_pathname
, strerror(errno
));
497 (void) fs_table_insert(path
->pp_pathname
, path
->pp_prid
,
498 FS_PROJECT_PATH
, fs
->fs_name
,
507 if (project
&& !found
)
514 fs_table_insert_project(
519 error
= fs_table_initialise_projects(project
);
521 fprintf(stderr
, _("%s: cannot setup path for project %s: %s\n"),
522 progname
, project
, strerror(error
));
526 * Initialize fs_table to contain the given set of mount points and
527 * projects. If mount_count is zero, mounts is ignored and the
528 * table is populated with mounted filesystems. If project_count is
529 * zero, projects is ignored and the table is populated with all
530 * projects defined in the projects file.
543 for (i
= 0; i
< mount_count
; i
++)
544 fs_table_insert_mount(mounts
[i
]);
546 error
= fs_table_initialise_mounts(NULL
);
551 for (i
= 0; i
< project_count
; i
++)
552 fs_table_insert_project(projects
[i
]);
554 error
= fs_table_initialise_projects(NULL
);
562 fprintf(stderr
, _("%s: cannot initialise path table: %s\n"),
563 progname
, strerror(error
));
567 fs_table_insert_project_path(
574 fs
= fs_mount_point_from_path(dir
);
576 error
= fs_table_insert(dir
, prid
, FS_PROJECT_PATH
,
577 fs
->fs_name
, NULL
, NULL
);
582 fprintf(stderr
, _("%s: cannot setup path for project dir %s: %s\n"),
583 progname
, dir
, strerror(error
));