From: Darrick J. Wong <darrick.wong@xxxxxxxxxx> Move the fs_table code into libfrog since it's not really a command. Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx> --- libfrog/Makefile | 10 + libfrog/paths.c | 586 ++++++++++++++++++++++++++++++++++++++++++++++++++++ libfrog/projects.c | 201 ++++++++++++++++++ libxcmd/Makefile | 10 - libxcmd/paths.c | 586 ---------------------------------------------------- libxcmd/projects.c | 201 ------------------ quota/Makefile | 4 spaceman/Makefile | 4 8 files changed, 802 insertions(+), 800 deletions(-) create mode 100644 libfrog/paths.c create mode 100644 libfrog/projects.c delete mode 100644 libxcmd/paths.c delete mode 100644 libxcmd/projects.c diff --git a/libfrog/Makefile b/libfrog/Makefile index 467362c..4c15605 100644 --- a/libfrog/Makefile +++ b/libfrog/Makefile @@ -14,11 +14,21 @@ CFILES = \ avl64.c \ convert.c \ list_sort.c \ +paths.c \ +projects.c \ radix-tree.c \ topology.c \ util.c \ workqueue.c +ifeq ($(HAVE_GETMNTENT),yes) +LCFLAGS += -DHAVE_GETMNTENT +endif + +ifeq ($(HAVE_GETMNTINFO),yes) +LCFLAGS += -DHAVE_GETMNTINFO +endif + default: ltdepend $(LTLIBRARY) include $(BUILDRULES) diff --git a/libfrog/paths.c b/libfrog/paths.c new file mode 100644 index 0000000..b767e9d --- /dev/null +++ b/libfrog/paths.c @@ -0,0 +1,586 @@ +/* + * Copyright (c) 2005-2006 Silicon Graphics, Inc. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <paths.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "path.h" +#include "input.h" +#include "project.h" +#include <limits.h> + +extern char *progname; + +int fs_count; +int xfs_fs_count; +struct fs_path *fs_table; +struct fs_path *fs_path; + +char *mtab_file; +#define PROC_MOUNTS "/proc/self/mounts" + +static int +fs_device_number( + const char *name, + dev_t *devnum) +{ + struct stat sbuf; + + if (stat(name, &sbuf) < 0) + return errno; + /* + * We want to match st_rdev if the path provided is a device + * special file. Otherwise we are looking for the the + * device id for the containing filesystem, in st_dev. + */ + if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode)) + *devnum = sbuf.st_rdev; + else + *devnum = sbuf.st_dev; + + return 0; +} + +/* + * Find the FS table entry for the given path. The "flags" argument + * is a mask containing FS_MOUNT_POINT or FS_PROJECT_PATH (or both) + * to indicate the type of table entry sought. + * fs_table_lookup() finds the fs table entry for the filesystem hosting + * the file represented in the "dir" argument. To compare against actual + * mount point entries, use fs_table_lookup_mount() instead. + */ +struct fs_path * +fs_table_lookup( + const char *dir, + uint flags) +{ + uint i; + dev_t dev = 0; + + if (fs_device_number(dir, &dev)) + return NULL; + + for (i = 0; i < fs_count; i++) { + if (flags && !(flags & fs_table[i].fs_flags)) + continue; + if (fs_table[i].fs_datadev == dev) + return &fs_table[i]; + } + return NULL; +} + +/* + * Find the FS table entry describing an actual mount for the given path. + * Unlike fs_table_lookup(), fs_table_lookup_mount() compares the "dir" + * argument to actual mount point entries in the table. Accordingly, it + * will find matches only if the "dir" argument is indeed mounted. + */ +struct fs_path * +fs_table_lookup_mount( + const char *dir) +{ + uint i; + dev_t dev = 0; + char rpath[PATH_MAX]; + + if (fs_device_number(dir, &dev)) + return NULL; + + for (i = 0; i < fs_count; i++) { + if (fs_table[i].fs_flags != FS_MOUNT_POINT) + continue; + if (!realpath(fs_table[i].fs_dir, rpath)) + continue; + if (strcmp(rpath, dir) == 0) + return &fs_table[i]; + } + return NULL; +} + +static int +fs_table_insert( + char *dir, + uint prid, + uint flags, + char *fsname, + char *fslog, + char *fsrt) +{ + dev_t datadev, logdev, rtdev; + struct fs_path *tmp_fs_table; + int error; + + datadev = logdev = rtdev = 0; + error = fs_device_number(dir, &datadev); + if (error) + goto out_nodev; + if (fslog) { + error = fs_device_number(fslog, &logdev); + if (error) + goto out_nodev; + } + if (fsrt) { + error = fs_device_number(fsrt, &rtdev); + if (error) + goto out_nodev; + } + + if (!platform_test_xfs_path(dir)) + flags |= FS_FOREIGN; + + /* + * Make copies of the directory and data device path. + * The log device and real-time device, if non-null, + * are already the result of strdup() calls so we + * don't need to duplicate those. In fact, this + * function is assumed to "consume" both of those + * pointers, meaning if an error occurs they will + * both get freed. + */ + error = ENOMEM; + dir = strdup(dir); + if (!dir) + goto out_nodev; + fsname = strdup(fsname); + if (!fsname) + goto out_noname; + + tmp_fs_table = realloc(fs_table, sizeof(fs_path_t) * (fs_count + 1)); + if (!tmp_fs_table) + goto out_norealloc; + fs_table = tmp_fs_table; + + /* Put foreign filesystems at the end, xfs filesystems at the front */ + if (flags & FS_FOREIGN || fs_count == 0) { + fs_path = &fs_table[fs_count]; + } else { + /* move foreign fs entries down, insert new one just before */ + memmove(&fs_table[xfs_fs_count + 1], &fs_table[xfs_fs_count], + sizeof(fs_path_t)*(fs_count - xfs_fs_count)); + fs_path = &fs_table[xfs_fs_count]; + } + fs_path->fs_dir = dir; + fs_path->fs_prid = prid; + fs_path->fs_flags = flags; + fs_path->fs_name = fsname; + fs_path->fs_log = fslog; + fs_path->fs_rt = fsrt; + fs_path->fs_datadev = datadev; + fs_path->fs_logdev = logdev; + fs_path->fs_rtdev = rtdev; + fs_count++; + if (!(flags & FS_FOREIGN)) + xfs_fs_count++; + + return 0; + +out_norealloc: + free(fsname); +out_noname: + free(dir); +out_nodev: + /* "Consume" fslog and fsrt even if there's an error */ + free(fslog); + free(fsrt); + + return error; +} + +/* + * Table iteration (cursor-based) interfaces + */ + +/* + * Initialize an fs_table cursor. If a directory path is supplied, + * the cursor is set up to appear as though the table contains only + * a single entry which represents the directory specified. + * Otherwise it is set up to prepare for visiting all entries in the + * global table, starting with the first. "flags" can be either + * FS_MOUNT_POINT or FS_PROJECT_PATH to limit what type of entries + * will be selected by fs_cursor_next_entry(). 0 can be used as a + * wild card (selecting either type). + */ +void +fs_cursor_initialise( + char *dir, + uint flags, + fs_cursor_t *cur) +{ + fs_path_t *path; + + memset(cur, 0, sizeof(*cur)); + if (dir) { + if ((path = fs_table_lookup(dir, flags)) == NULL) + return; + cur->local = *path; + cur->count = 1; + cur->table = &cur->local; + } else { + cur->count = fs_count; + cur->table = fs_table; + } + cur->flags = flags; +} + +/* + * Use the cursor to find the next entry in the table having the + * type specified by the cursor's "flags" field. + */ +struct fs_path * +fs_cursor_next_entry( + fs_cursor_t *cur) +{ + while (cur->index < cur->count) { + fs_path_t *next = &cur->table[cur->index++]; + + if (!cur->flags || (cur->flags & next->fs_flags)) + return next; + } + return NULL; +} + + +#if defined(HAVE_GETMNTENT) +#include <mntent.h> + +/* + * Determines whether the "logdev" or "rtdev" mount options are + * present for the given mount point. If so, the value for each (a + * device path) is returned in the pointers whose addresses are + * provided. The pointers are assigned NULL for an option not + * present. Note that the path buffers returned are allocated + * dynamically and it is the caller's responsibility to free them. + */ +static int +fs_extract_mount_options( + struct mntent *mnt, + char **logp, + char **rtp) +{ + char *fslog, *fsrt; + + /* + * Extract log device and realtime device from mount options. + * + * Note: the glibc hasmntopt implementation requires that the + * character in mnt_opts immediately after the search string + * must be a NULL ('\0'), a comma (','), or an equals ('='). + * Therefore we cannot search for 'logdev=' directly. + */ + if ((fslog = hasmntopt(mnt, "logdev")) && fslog[6] == '=') + fslog += 7; + if ((fsrt = hasmntopt(mnt, "rtdev")) && fsrt[5] == '=') + fsrt += 6; + + /* Do this only after we've finished processing mount options */ + if (fslog) { + fslog = strndup(fslog, strcspn(fslog, " ,")); + if (!fslog) + goto out_nomem; + } + if (fsrt) { + fsrt = strndup(fsrt, strcspn(fsrt, " ,")); + if (!fsrt) { + free(fslog); + goto out_nomem; + } + } + *logp = fslog; + *rtp = fsrt; + + return 0; + +out_nomem: + *logp = NULL; + *rtp = NULL; + fprintf(stderr, _("%s: unable to extract mount options for \"%s\"\n"), + progname, mnt->mnt_dir); + return ENOMEM; +} + +/* + * If *path is NULL, initialize the fs table with all xfs mount points in mtab + * If *path is specified, search for that path in mtab + * + * Everything - path, devices, and mountpoints - are boiled down to realpath() + * for comparison, but fs_table is populated with what comes from getmntent. + */ +static int +fs_table_initialise_mounts( + char *path) +{ + struct mntent *mnt; + FILE *mtp; + char *fslog, *fsrt; + int error, found; + char rpath[PATH_MAX], rmnt_fsname[PATH_MAX], rmnt_dir[PATH_MAX]; + + error = found = 0; + fslog = fsrt = NULL; + + if (!mtab_file) { + mtab_file = PROC_MOUNTS; + if (access(mtab_file, R_OK) != 0) + mtab_file = MOUNTED; + } + + if ((mtp = setmntent(mtab_file, "r")) == NULL) + return ENOENT; + + /* Use realpath to resolve symlinks, relative paths, etc */ + if (path) + if (!realpath(path, rpath)) + return errno; + + while ((mnt = getmntent(mtp)) != NULL) { + if (!realpath(mnt->mnt_dir, rmnt_dir)) + continue; + if (!realpath(mnt->mnt_fsname, rmnt_fsname)) + continue; + + if (path && + ((strcmp(rpath, rmnt_dir) != 0) && + (strcmp(rpath, rmnt_fsname) != 0))) + continue; + if (fs_extract_mount_options(mnt, &fslog, &fsrt)) + continue; + (void) fs_table_insert(mnt->mnt_dir, 0, FS_MOUNT_POINT, + mnt->mnt_fsname, fslog, fsrt); + if (path) { + found = 1; + break; + } + } + endmntent(mtp); + + if (path && !found) + error = ENXIO; + + return error; +} + +#elif defined(HAVE_GETMNTINFO) +#include <sys/mount.h> + +/* + * If *path is NULL, initialize the fs table with all xfs mount points in mtab + * If *path is specified, search for that path in mtab + * + * Everything - path, devices, and mountpoints - are boiled down to realpath() + * for comparison, but fs_table is populated with what comes from getmntinfo. + */ +static int +fs_table_initialise_mounts( + char *path) +{ + struct statfs *stats; + int i, count, error, found; + char rpath[PATH_MAX], rmntfromname[PATH_MAX], rmntonname[PATH_MAX]; + + error = found = 0; + if ((count = getmntinfo(&stats, 0)) < 0) { + fprintf(stderr, _("%s: getmntinfo() failed: %s\n"), + progname, strerror(errno)); + return 0; + } + + /* Use realpath to resolve symlinks, relative paths, etc */ + if (path) + if (!realpath(path, rpath)) + return errno; + + for (i = 0; i < count; i++) { + if (!realpath(stats[i].f_mntfromname, rmntfromname)) + continue; + if (!realpath(stats[i].f_mntonname, rmntonname)) + continue; + + if (path && + ((strcmp(rpath, rmntonname) != 0) && + (strcmp(rpath, rmntfromname) != 0))) + continue; + /* TODO: external log and realtime device? */ + (void) fs_table_insert(stats[i].f_mntonname, 0, + FS_MOUNT_POINT, stats[i].f_mntfromname, + NULL, NULL); + if (path) { + found = 1; + break; + } + } + if (path && !found) + error = ENXIO; + + return error; +} + +#else +# error "How do I extract info about mounted filesystems on this platform?" +#endif + +/* + * Given a directory, match it up to a filesystem mount point. + */ +static struct fs_path * +fs_mount_point_from_path( + const char *dir) +{ + fs_cursor_t cursor; + fs_path_t *fs; + dev_t dev = 0; + + if (fs_device_number(dir, &dev)) + return NULL; + + fs_cursor_initialise(NULL, FS_MOUNT_POINT, &cursor); + while ((fs = fs_cursor_next_entry(&cursor))) { + if (fs->fs_datadev == dev) + break; + } + return fs; +} + +static void +fs_table_insert_mount( + char *mount) +{ + int error; + + error = fs_table_initialise_mounts(mount); + if (error) + fprintf(stderr, _("%s: cannot setup path for mount %s: %s\n"), + progname, mount, strerror(error)); +} + +static int +fs_table_initialise_projects( + char *project) +{ + fs_project_path_t *path; + fs_path_t *fs; + prid_t prid = 0; + int error = 0, found = 0; + + if (project) + prid = prid_from_string(project); + + setprpathent(); + while ((path = getprpathent()) != NULL) { + if (project && prid != path->pp_prid) + continue; + fs = fs_mount_point_from_path(path->pp_pathname); + if (!fs) { + fprintf(stderr, _("%s: cannot find mount point for path `%s': %s\n"), + progname, path->pp_pathname, strerror(errno)); + continue; + } + (void) fs_table_insert(path->pp_pathname, path->pp_prid, + FS_PROJECT_PATH, fs->fs_name, + NULL, NULL); + if (project) { + found = 1; + break; + } + } + endprpathent(); + + if (project && !found) + error = ENOENT; + + return error; +} + +static void +fs_table_insert_project( + char *project) +{ + int error; + + error = fs_table_initialise_projects(project); + if (error) + fprintf(stderr, _("%s: cannot setup path for project %s: %s\n"), + progname, project, strerror(error)); +} + +/* + * Initialize fs_table to contain the given set of mount points and + * projects. If mount_count is zero, mounts is ignored and the + * table is populated with mounted filesystems. If project_count is + * zero, projects is ignored and the table is populated with all + * projects defined in the projects file. + */ +void +fs_table_initialise( + int mount_count, + char *mounts[], + int project_count, + char *projects[]) +{ + int error; + int i; + + if (mount_count) { + for (i = 0; i < mount_count; i++) + fs_table_insert_mount(mounts[i]); + } else { + error = fs_table_initialise_mounts(NULL); + if (error) + goto out_error; + } + if (project_count) { + for (i = 0; i < project_count; i++) + fs_table_insert_project(projects[i]); + } else { + error = fs_table_initialise_projects(NULL); + if (error) + goto out_error; + } + + return; + +out_error: + fprintf(stderr, _("%s: cannot initialise path table: %s\n"), + progname, strerror(error)); +} + +void +fs_table_insert_project_path( + char *dir, + prid_t prid) +{ + fs_path_t *fs; + int error = 0; + + fs = fs_mount_point_from_path(dir); + if (fs) + error = fs_table_insert(dir, prid, FS_PROJECT_PATH, + fs->fs_name, NULL, NULL); + else + error = ENOENT; + + if (error) { + fprintf(stderr, _("%s: cannot setup path for project dir %s: %s\n"), + progname, dir, strerror(error)); + exit(1); + } +} diff --git a/libfrog/projects.c b/libfrog/projects.c new file mode 100644 index 0000000..c9e863d --- /dev/null +++ b/libfrog/projects.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2005 Silicon Graphics, Inc. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "project.h" + +#define PROJID "/etc/projid" +#define PROJECT_PATHS "/etc/projects" +char *projid_file; +char *projects_file; + +static FILE *projects; +static fs_project_t p; +static char projects_buffer[512]; + +static FILE *project_paths; +static fs_project_path_t pp; +static char project_paths_buffer[1024]; + +void +setprfiles(void) +{ + if (!projid_file) + projid_file = PROJID; + if (!projects_file) + projects_file = PROJECT_PATHS; +} + +void +setprent(void) +{ + setprfiles(); + projects = fopen(projid_file, "r"); +} + +void +setprpathent(void) +{ + setprfiles(); + project_paths = fopen(projects_file, "r"); +} + +void +endprent(void) +{ + if (projects) + fclose(projects); + projects = NULL; +} + +void +endprpathent(void) +{ + if (project_paths) + fclose(project_paths); + project_paths = NULL; +} + +fs_project_t * +getprent(void) +{ + char *idstart, *idend; + size_t size = sizeof(projects_buffer) - 1; + + if (!projects) + return NULL; + for (;;) { + if (!fgets(projects_buffer, size, projects)) + break; + /* + * /etc/projid file format -- "name:id\n", ignore "^#..." + */ + if (projects_buffer[0] == '#') + continue; + idstart = strchr(projects_buffer, ':'); + if (!idstart) + continue; + if ((idstart + 1) - projects_buffer >= size) + continue; + idend = strchr(idstart+1, ':'); + if (idend) + *idend = '\0'; + *idstart = '\0'; + p.pr_prid = atoi(idstart+1); + p.pr_name = &projects_buffer[0]; + return &p; + } + + return NULL; +} + +fs_project_t * +getprnam( + char *name) +{ + fs_project_t *p = NULL; + + setprent(); + while ((p = getprent()) != NULL) + if (strcmp(p->pr_name, name) == 0) + break; + endprent(); + return p; +} + +fs_project_t * +getprprid( + prid_t prid) +{ + fs_project_t *p = NULL; + + setprent(); + while ((p = getprent()) != NULL) + if (p->pr_prid == prid) + break; + endprent(); + return p; +} + +fs_project_path_t * +getprpathent(void) +{ + char *nmstart, *nmend; + size_t size = sizeof(project_paths_buffer) - 1; + + if (!project_paths) + return NULL; + for (;;) { + if (!fgets(project_paths_buffer, size, project_paths)) + break; + /* + * /etc/projects format -- "id:pathname\n", ignore "^#..." + */ + if (project_paths_buffer[0] == '#') + continue; + nmstart = strchr(project_paths_buffer, ':'); + if (!nmstart) + continue; + if ((nmstart + 1) - project_paths_buffer >= size) + continue; + nmend = strchr(nmstart + 1, '\n'); + if (nmend) + *nmend = '\0'; + *nmstart = '\0'; + pp.pp_pathname = nmstart + 1; + pp.pp_prid = atoi(&project_paths_buffer[0]); + return &pp; + } + + return NULL; +} + + +int +getprojid( + const char *name, + int fd, + prid_t *projid) +{ + struct fsxattr fsx; + + if (xfsctl(name, fd, FS_IOC_FSGETXATTR, &fsx)) { + perror("FS_IOC_FSGETXATTR"); + return -1; + } + *projid = fsx.fsx_projid; + return 0; +} + +int +setprojid( + const char *name, + int fd, + prid_t projid) +{ + struct fsxattr fsx; + int error; + + if ((error = xfsctl(name, fd, FS_IOC_FSGETXATTR, &fsx)) == 0) { + fsx.fsx_projid = projid; + error = xfsctl(name, fd, FS_IOC_FSSETXATTR, &fsx); + } + return error; +} diff --git a/libxcmd/Makefile b/libxcmd/Makefile index 7701ed9..de0e49c 100644 --- a/libxcmd/Makefile +++ b/libxcmd/Makefile @@ -10,15 +10,7 @@ LT_CURRENT = 0 LT_REVISION = 0 LT_AGE = 0 -CFILES = command.c input.c paths.c projects.c help.c quit.c - -ifeq ($(HAVE_GETMNTENT),yes) -LCFLAGS += -DHAVE_GETMNTENT -endif - -ifeq ($(HAVE_GETMNTINFO),yes) -LCFLAGS += -DHAVE_GETMNTINFO -endif +CFILES = command.c input.c help.c quit.c ifeq ($(ENABLE_READLINE),yes) LCFLAGS += -DENABLE_READLINE diff --git a/libxcmd/paths.c b/libxcmd/paths.c deleted file mode 100644 index b767e9d..0000000 --- a/libxcmd/paths.c +++ /dev/null @@ -1,586 +0,0 @@ -/* - * Copyright (c) 2005-2006 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <paths.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include "path.h" -#include "input.h" -#include "project.h" -#include <limits.h> - -extern char *progname; - -int fs_count; -int xfs_fs_count; -struct fs_path *fs_table; -struct fs_path *fs_path; - -char *mtab_file; -#define PROC_MOUNTS "/proc/self/mounts" - -static int -fs_device_number( - const char *name, - dev_t *devnum) -{ - struct stat sbuf; - - if (stat(name, &sbuf) < 0) - return errno; - /* - * We want to match st_rdev if the path provided is a device - * special file. Otherwise we are looking for the the - * device id for the containing filesystem, in st_dev. - */ - if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode)) - *devnum = sbuf.st_rdev; - else - *devnum = sbuf.st_dev; - - return 0; -} - -/* - * Find the FS table entry for the given path. The "flags" argument - * is a mask containing FS_MOUNT_POINT or FS_PROJECT_PATH (or both) - * to indicate the type of table entry sought. - * fs_table_lookup() finds the fs table entry for the filesystem hosting - * the file represented in the "dir" argument. To compare against actual - * mount point entries, use fs_table_lookup_mount() instead. - */ -struct fs_path * -fs_table_lookup( - const char *dir, - uint flags) -{ - uint i; - dev_t dev = 0; - - if (fs_device_number(dir, &dev)) - return NULL; - - for (i = 0; i < fs_count; i++) { - if (flags && !(flags & fs_table[i].fs_flags)) - continue; - if (fs_table[i].fs_datadev == dev) - return &fs_table[i]; - } - return NULL; -} - -/* - * Find the FS table entry describing an actual mount for the given path. - * Unlike fs_table_lookup(), fs_table_lookup_mount() compares the "dir" - * argument to actual mount point entries in the table. Accordingly, it - * will find matches only if the "dir" argument is indeed mounted. - */ -struct fs_path * -fs_table_lookup_mount( - const char *dir) -{ - uint i; - dev_t dev = 0; - char rpath[PATH_MAX]; - - if (fs_device_number(dir, &dev)) - return NULL; - - for (i = 0; i < fs_count; i++) { - if (fs_table[i].fs_flags != FS_MOUNT_POINT) - continue; - if (!realpath(fs_table[i].fs_dir, rpath)) - continue; - if (strcmp(rpath, dir) == 0) - return &fs_table[i]; - } - return NULL; -} - -static int -fs_table_insert( - char *dir, - uint prid, - uint flags, - char *fsname, - char *fslog, - char *fsrt) -{ - dev_t datadev, logdev, rtdev; - struct fs_path *tmp_fs_table; - int error; - - datadev = logdev = rtdev = 0; - error = fs_device_number(dir, &datadev); - if (error) - goto out_nodev; - if (fslog) { - error = fs_device_number(fslog, &logdev); - if (error) - goto out_nodev; - } - if (fsrt) { - error = fs_device_number(fsrt, &rtdev); - if (error) - goto out_nodev; - } - - if (!platform_test_xfs_path(dir)) - flags |= FS_FOREIGN; - - /* - * Make copies of the directory and data device path. - * The log device and real-time device, if non-null, - * are already the result of strdup() calls so we - * don't need to duplicate those. In fact, this - * function is assumed to "consume" both of those - * pointers, meaning if an error occurs they will - * both get freed. - */ - error = ENOMEM; - dir = strdup(dir); - if (!dir) - goto out_nodev; - fsname = strdup(fsname); - if (!fsname) - goto out_noname; - - tmp_fs_table = realloc(fs_table, sizeof(fs_path_t) * (fs_count + 1)); - if (!tmp_fs_table) - goto out_norealloc; - fs_table = tmp_fs_table; - - /* Put foreign filesystems at the end, xfs filesystems at the front */ - if (flags & FS_FOREIGN || fs_count == 0) { - fs_path = &fs_table[fs_count]; - } else { - /* move foreign fs entries down, insert new one just before */ - memmove(&fs_table[xfs_fs_count + 1], &fs_table[xfs_fs_count], - sizeof(fs_path_t)*(fs_count - xfs_fs_count)); - fs_path = &fs_table[xfs_fs_count]; - } - fs_path->fs_dir = dir; - fs_path->fs_prid = prid; - fs_path->fs_flags = flags; - fs_path->fs_name = fsname; - fs_path->fs_log = fslog; - fs_path->fs_rt = fsrt; - fs_path->fs_datadev = datadev; - fs_path->fs_logdev = logdev; - fs_path->fs_rtdev = rtdev; - fs_count++; - if (!(flags & FS_FOREIGN)) - xfs_fs_count++; - - return 0; - -out_norealloc: - free(fsname); -out_noname: - free(dir); -out_nodev: - /* "Consume" fslog and fsrt even if there's an error */ - free(fslog); - free(fsrt); - - return error; -} - -/* - * Table iteration (cursor-based) interfaces - */ - -/* - * Initialize an fs_table cursor. If a directory path is supplied, - * the cursor is set up to appear as though the table contains only - * a single entry which represents the directory specified. - * Otherwise it is set up to prepare for visiting all entries in the - * global table, starting with the first. "flags" can be either - * FS_MOUNT_POINT or FS_PROJECT_PATH to limit what type of entries - * will be selected by fs_cursor_next_entry(). 0 can be used as a - * wild card (selecting either type). - */ -void -fs_cursor_initialise( - char *dir, - uint flags, - fs_cursor_t *cur) -{ - fs_path_t *path; - - memset(cur, 0, sizeof(*cur)); - if (dir) { - if ((path = fs_table_lookup(dir, flags)) == NULL) - return; - cur->local = *path; - cur->count = 1; - cur->table = &cur->local; - } else { - cur->count = fs_count; - cur->table = fs_table; - } - cur->flags = flags; -} - -/* - * Use the cursor to find the next entry in the table having the - * type specified by the cursor's "flags" field. - */ -struct fs_path * -fs_cursor_next_entry( - fs_cursor_t *cur) -{ - while (cur->index < cur->count) { - fs_path_t *next = &cur->table[cur->index++]; - - if (!cur->flags || (cur->flags & next->fs_flags)) - return next; - } - return NULL; -} - - -#if defined(HAVE_GETMNTENT) -#include <mntent.h> - -/* - * Determines whether the "logdev" or "rtdev" mount options are - * present for the given mount point. If so, the value for each (a - * device path) is returned in the pointers whose addresses are - * provided. The pointers are assigned NULL for an option not - * present. Note that the path buffers returned are allocated - * dynamically and it is the caller's responsibility to free them. - */ -static int -fs_extract_mount_options( - struct mntent *mnt, - char **logp, - char **rtp) -{ - char *fslog, *fsrt; - - /* - * Extract log device and realtime device from mount options. - * - * Note: the glibc hasmntopt implementation requires that the - * character in mnt_opts immediately after the search string - * must be a NULL ('\0'), a comma (','), or an equals ('='). - * Therefore we cannot search for 'logdev=' directly. - */ - if ((fslog = hasmntopt(mnt, "logdev")) && fslog[6] == '=') - fslog += 7; - if ((fsrt = hasmntopt(mnt, "rtdev")) && fsrt[5] == '=') - fsrt += 6; - - /* Do this only after we've finished processing mount options */ - if (fslog) { - fslog = strndup(fslog, strcspn(fslog, " ,")); - if (!fslog) - goto out_nomem; - } - if (fsrt) { - fsrt = strndup(fsrt, strcspn(fsrt, " ,")); - if (!fsrt) { - free(fslog); - goto out_nomem; - } - } - *logp = fslog; - *rtp = fsrt; - - return 0; - -out_nomem: - *logp = NULL; - *rtp = NULL; - fprintf(stderr, _("%s: unable to extract mount options for \"%s\"\n"), - progname, mnt->mnt_dir); - return ENOMEM; -} - -/* - * If *path is NULL, initialize the fs table with all xfs mount points in mtab - * If *path is specified, search for that path in mtab - * - * Everything - path, devices, and mountpoints - are boiled down to realpath() - * for comparison, but fs_table is populated with what comes from getmntent. - */ -static int -fs_table_initialise_mounts( - char *path) -{ - struct mntent *mnt; - FILE *mtp; - char *fslog, *fsrt; - int error, found; - char rpath[PATH_MAX], rmnt_fsname[PATH_MAX], rmnt_dir[PATH_MAX]; - - error = found = 0; - fslog = fsrt = NULL; - - if (!mtab_file) { - mtab_file = PROC_MOUNTS; - if (access(mtab_file, R_OK) != 0) - mtab_file = MOUNTED; - } - - if ((mtp = setmntent(mtab_file, "r")) == NULL) - return ENOENT; - - /* Use realpath to resolve symlinks, relative paths, etc */ - if (path) - if (!realpath(path, rpath)) - return errno; - - while ((mnt = getmntent(mtp)) != NULL) { - if (!realpath(mnt->mnt_dir, rmnt_dir)) - continue; - if (!realpath(mnt->mnt_fsname, rmnt_fsname)) - continue; - - if (path && - ((strcmp(rpath, rmnt_dir) != 0) && - (strcmp(rpath, rmnt_fsname) != 0))) - continue; - if (fs_extract_mount_options(mnt, &fslog, &fsrt)) - continue; - (void) fs_table_insert(mnt->mnt_dir, 0, FS_MOUNT_POINT, - mnt->mnt_fsname, fslog, fsrt); - if (path) { - found = 1; - break; - } - } - endmntent(mtp); - - if (path && !found) - error = ENXIO; - - return error; -} - -#elif defined(HAVE_GETMNTINFO) -#include <sys/mount.h> - -/* - * If *path is NULL, initialize the fs table with all xfs mount points in mtab - * If *path is specified, search for that path in mtab - * - * Everything - path, devices, and mountpoints - are boiled down to realpath() - * for comparison, but fs_table is populated with what comes from getmntinfo. - */ -static int -fs_table_initialise_mounts( - char *path) -{ - struct statfs *stats; - int i, count, error, found; - char rpath[PATH_MAX], rmntfromname[PATH_MAX], rmntonname[PATH_MAX]; - - error = found = 0; - if ((count = getmntinfo(&stats, 0)) < 0) { - fprintf(stderr, _("%s: getmntinfo() failed: %s\n"), - progname, strerror(errno)); - return 0; - } - - /* Use realpath to resolve symlinks, relative paths, etc */ - if (path) - if (!realpath(path, rpath)) - return errno; - - for (i = 0; i < count; i++) { - if (!realpath(stats[i].f_mntfromname, rmntfromname)) - continue; - if (!realpath(stats[i].f_mntonname, rmntonname)) - continue; - - if (path && - ((strcmp(rpath, rmntonname) != 0) && - (strcmp(rpath, rmntfromname) != 0))) - continue; - /* TODO: external log and realtime device? */ - (void) fs_table_insert(stats[i].f_mntonname, 0, - FS_MOUNT_POINT, stats[i].f_mntfromname, - NULL, NULL); - if (path) { - found = 1; - break; - } - } - if (path && !found) - error = ENXIO; - - return error; -} - -#else -# error "How do I extract info about mounted filesystems on this platform?" -#endif - -/* - * Given a directory, match it up to a filesystem mount point. - */ -static struct fs_path * -fs_mount_point_from_path( - const char *dir) -{ - fs_cursor_t cursor; - fs_path_t *fs; - dev_t dev = 0; - - if (fs_device_number(dir, &dev)) - return NULL; - - fs_cursor_initialise(NULL, FS_MOUNT_POINT, &cursor); - while ((fs = fs_cursor_next_entry(&cursor))) { - if (fs->fs_datadev == dev) - break; - } - return fs; -} - -static void -fs_table_insert_mount( - char *mount) -{ - int error; - - error = fs_table_initialise_mounts(mount); - if (error) - fprintf(stderr, _("%s: cannot setup path for mount %s: %s\n"), - progname, mount, strerror(error)); -} - -static int -fs_table_initialise_projects( - char *project) -{ - fs_project_path_t *path; - fs_path_t *fs; - prid_t prid = 0; - int error = 0, found = 0; - - if (project) - prid = prid_from_string(project); - - setprpathent(); - while ((path = getprpathent()) != NULL) { - if (project && prid != path->pp_prid) - continue; - fs = fs_mount_point_from_path(path->pp_pathname); - if (!fs) { - fprintf(stderr, _("%s: cannot find mount point for path `%s': %s\n"), - progname, path->pp_pathname, strerror(errno)); - continue; - } - (void) fs_table_insert(path->pp_pathname, path->pp_prid, - FS_PROJECT_PATH, fs->fs_name, - NULL, NULL); - if (project) { - found = 1; - break; - } - } - endprpathent(); - - if (project && !found) - error = ENOENT; - - return error; -} - -static void -fs_table_insert_project( - char *project) -{ - int error; - - error = fs_table_initialise_projects(project); - if (error) - fprintf(stderr, _("%s: cannot setup path for project %s: %s\n"), - progname, project, strerror(error)); -} - -/* - * Initialize fs_table to contain the given set of mount points and - * projects. If mount_count is zero, mounts is ignored and the - * table is populated with mounted filesystems. If project_count is - * zero, projects is ignored and the table is populated with all - * projects defined in the projects file. - */ -void -fs_table_initialise( - int mount_count, - char *mounts[], - int project_count, - char *projects[]) -{ - int error; - int i; - - if (mount_count) { - for (i = 0; i < mount_count; i++) - fs_table_insert_mount(mounts[i]); - } else { - error = fs_table_initialise_mounts(NULL); - if (error) - goto out_error; - } - if (project_count) { - for (i = 0; i < project_count; i++) - fs_table_insert_project(projects[i]); - } else { - error = fs_table_initialise_projects(NULL); - if (error) - goto out_error; - } - - return; - -out_error: - fprintf(stderr, _("%s: cannot initialise path table: %s\n"), - progname, strerror(error)); -} - -void -fs_table_insert_project_path( - char *dir, - prid_t prid) -{ - fs_path_t *fs; - int error = 0; - - fs = fs_mount_point_from_path(dir); - if (fs) - error = fs_table_insert(dir, prid, FS_PROJECT_PATH, - fs->fs_name, NULL, NULL); - else - error = ENOENT; - - if (error) { - fprintf(stderr, _("%s: cannot setup path for project dir %s: %s\n"), - progname, dir, strerror(error)); - exit(1); - } -} diff --git a/libxcmd/projects.c b/libxcmd/projects.c deleted file mode 100644 index c9e863d..0000000 --- a/libxcmd/projects.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "project.h" - -#define PROJID "/etc/projid" -#define PROJECT_PATHS "/etc/projects" -char *projid_file; -char *projects_file; - -static FILE *projects; -static fs_project_t p; -static char projects_buffer[512]; - -static FILE *project_paths; -static fs_project_path_t pp; -static char project_paths_buffer[1024]; - -void -setprfiles(void) -{ - if (!projid_file) - projid_file = PROJID; - if (!projects_file) - projects_file = PROJECT_PATHS; -} - -void -setprent(void) -{ - setprfiles(); - projects = fopen(projid_file, "r"); -} - -void -setprpathent(void) -{ - setprfiles(); - project_paths = fopen(projects_file, "r"); -} - -void -endprent(void) -{ - if (projects) - fclose(projects); - projects = NULL; -} - -void -endprpathent(void) -{ - if (project_paths) - fclose(project_paths); - project_paths = NULL; -} - -fs_project_t * -getprent(void) -{ - char *idstart, *idend; - size_t size = sizeof(projects_buffer) - 1; - - if (!projects) - return NULL; - for (;;) { - if (!fgets(projects_buffer, size, projects)) - break; - /* - * /etc/projid file format -- "name:id\n", ignore "^#..." - */ - if (projects_buffer[0] == '#') - continue; - idstart = strchr(projects_buffer, ':'); - if (!idstart) - continue; - if ((idstart + 1) - projects_buffer >= size) - continue; - idend = strchr(idstart+1, ':'); - if (idend) - *idend = '\0'; - *idstart = '\0'; - p.pr_prid = atoi(idstart+1); - p.pr_name = &projects_buffer[0]; - return &p; - } - - return NULL; -} - -fs_project_t * -getprnam( - char *name) -{ - fs_project_t *p = NULL; - - setprent(); - while ((p = getprent()) != NULL) - if (strcmp(p->pr_name, name) == 0) - break; - endprent(); - return p; -} - -fs_project_t * -getprprid( - prid_t prid) -{ - fs_project_t *p = NULL; - - setprent(); - while ((p = getprent()) != NULL) - if (p->pr_prid == prid) - break; - endprent(); - return p; -} - -fs_project_path_t * -getprpathent(void) -{ - char *nmstart, *nmend; - size_t size = sizeof(project_paths_buffer) - 1; - - if (!project_paths) - return NULL; - for (;;) { - if (!fgets(project_paths_buffer, size, project_paths)) - break; - /* - * /etc/projects format -- "id:pathname\n", ignore "^#..." - */ - if (project_paths_buffer[0] == '#') - continue; - nmstart = strchr(project_paths_buffer, ':'); - if (!nmstart) - continue; - if ((nmstart + 1) - project_paths_buffer >= size) - continue; - nmend = strchr(nmstart + 1, '\n'); - if (nmend) - *nmend = '\0'; - *nmstart = '\0'; - pp.pp_pathname = nmstart + 1; - pp.pp_prid = atoi(&project_paths_buffer[0]); - return &pp; - } - - return NULL; -} - - -int -getprojid( - const char *name, - int fd, - prid_t *projid) -{ - struct fsxattr fsx; - - if (xfsctl(name, fd, FS_IOC_FSGETXATTR, &fsx)) { - perror("FS_IOC_FSGETXATTR"); - return -1; - } - *projid = fsx.fsx_projid; - return 0; -} - -int -setprojid( - const char *name, - int fd, - prid_t projid) -{ - struct fsxattr fsx; - int error; - - if ((error = xfsctl(name, fd, FS_IOC_FSGETXATTR, &fsx)) == 0) { - fsx.fsx_projid = projid; - error = xfsctl(name, fd, FS_IOC_FSSETXATTR, &fsx); - } - return error; -} diff --git a/quota/Makefile b/quota/Makefile index 9c6411e..120af2e 100644 --- a/quota/Makefile +++ b/quota/Makefile @@ -14,8 +14,8 @@ CFILES += $(PKG_PLATFORM).c PCFILES = darwin.c freebsd.c irix.c linux.c LSRCFILES = $(shell echo $(PCFILES) | sed -e "s/$(PKG_PLATFORM).c//g") -LLDLIBS = $(LIBXCMD) -LTDEPENDENCIES = $(LIBXCMD) +LLDLIBS = $(LIBXCMD) $(LIBFROG) +LTDEPENDENCIES = $(LIBXCMD) $(LIBFROG) LLDFLAGS = -static ifeq ($(ENABLE_READLINE),yes) diff --git a/spaceman/Makefile b/spaceman/Makefile index 95ec3c0..8b31030 100644 --- a/spaceman/Makefile +++ b/spaceman/Makefile @@ -9,8 +9,8 @@ LTCOMMAND = xfs_spaceman HFILES = init.h space.h CFILES = init.c file.c prealloc.c trim.c -LLDLIBS = $(LIBXCMD) -LTDEPENDENCIES = $(LIBXCMD) +LLDLIBS = $(LIBXCMD) $(LIBFROG) +LTDEPENDENCIES = $(LIBXCMD) $(LIBFROG) LLDFLAGS = -static ifeq ($(ENABLE_READLINE),yes) -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html