sload.f2fs: update build for android
authorJaegeuk Kim <jaegeuk@kernel.org>
Thu, 30 Nov 2017 01:21:12 +0000 (17:21 -0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Fri, 1 Dec 2017 06:36:35 +0000 (22:36 -0800)
This patch updates sload.f2fs for android build.

- do fsck() after sload() to update quota information.
- return success, if there's no source directory

  -C fs_config

  -f source directory [path of the source directory]

  -p product out directory
    : path on fs_config file for uid/gid/mode

  -s file_contexts
    : selabel file

  -t mount point [prefix of target fs path, default:/]
     : path stored in selabel/fs_config files

  -T timestamp

Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fsck/dir.c
fsck/fsck.h
fsck/main.c
fsck/mount.c
fsck/segment.c
fsck/sload.c
fsck/xattr.c
include/android_config.h
include/f2fs_fs.h
lib/libf2fs.c

index 273e762..b2ea18f 100644 (file)
@@ -620,9 +620,12 @@ int f2fs_create(struct f2fs_sb_info *sbi, struct dentry *de)
        ASSERT(ret >= 0);
 
        update_free_segments(sbi);
-       MSG(1, "Info: Create \"%s\" type=%x, ino=%x / %x into \"%s\"\n",
-                       de->full_path, de->file_type,
-                       de->ino, de->pino, de->path);
+       MSG(1, "Info: Create %s -> %s\n"
+               "  -- ino=%x, type=%x, mode=%x, uid=%x, "
+               "gid=%x, cap=%"PRIx64", size=%lu, pino=%x\n",
+               de->full_path, de->path,
+               de->ino, de->file_type, de->mode,
+               de->uid, de->gid, de->capabilities, de->size, de->pino);
 free_child_dir:
        free(child);
 free_parent_dir:
index 15ac848..0343fbd 100644 (file)
@@ -216,8 +216,7 @@ int f2fs_defragment(struct f2fs_sb_info *, u64, u64, u64, int);
 int f2fs_resize(struct f2fs_sb_info *);
 
 /* sload.c */
-int f2fs_sload(struct f2fs_sb_info *, const char *, const char *,
-               const char *, struct selabel_handle *);
+int f2fs_sload(struct f2fs_sb_info *);
 
 /* segment.c */
 void reserve_new_block(struct f2fs_sb_info *, block_t *,
index ba247d4..a09ca76 100644 (file)
 
 struct f2fs_fsck gfsck;
 
+static char *absolute_path(const char *file)
+{
+       char *ret;
+       char cwd[PATH_MAX];
+
+       if (file[0] != '/') {
+               if (getcwd(cwd, PATH_MAX) == NULL) {
+                       fprintf(stderr, "Failed to getcwd\n");
+                       exit(EXIT_FAILURE);
+               }
+               ret = malloc(strlen(cwd) + 1 + strlen(file) + 1);
+               if (ret)
+                       sprintf(ret, "%s/%s", cwd, file);
+       } else
+               ret = strdup(file);
+       return ret;
+}
+
 void fsck_usage()
 {
        MSG(0, "\nUsage: fsck.f2fs [options] device\n");
@@ -76,8 +94,12 @@ void sload_usage()
 {
        MSG(0, "\nUsage: sload.f2fs [options] device\n");
        MSG(0, "[options]:\n");
+       MSG(0, "  -C fs_config\n");
        MSG(0, "  -f source directory [path of the source directory]\n");
+       MSG(0, "  -p product out directory\n");
+       MSG(0, "  -s file_contexts\n");
        MSG(0, "  -t mount point [prefix of target fs path, default:/]\n");
+       MSG(0, "  -T timestamp\n");
        MSG(0, "  -d debug level [default:0]\n");
        exit(1);
 }
@@ -367,11 +389,20 @@ void f2fs_parse_options(int argc, char *argv[])
                                break;
                }
        } else if (!strcmp("sload.f2fs", prog)) {
-               const char *option_string = "d:f:t:";
+               const char *option_string = "C:d:f:p:s:t:T:";
+#ifdef HAVE_LIBSELINUX
+               int max_nr_opt = (int)sizeof(c.seopt_file) /
+                       sizeof(c.seopt_file[0]);
+               char *token;
+#endif
+               char *p;
 
                c.func = SLOAD;
                while ((option = getopt(argc, argv, option_string)) != EOF) {
                        switch (option) {
+                       case 'C':
+                               c.fs_config_file = absolute_path(optarg);
+                               break;
                        case 'd':
                                if (!is_digits(optarg)) {
                                        err = EWRONG_OPT;
@@ -382,11 +413,37 @@ void f2fs_parse_options(int argc, char *argv[])
                                                c.dbg_lv);
                                break;
                        case 'f':
-                               c.from_dir = (char *)optarg;
+                               c.from_dir = absolute_path(optarg);
+                               break;
+                       case 'p':
+                               c.target_out_dir = absolute_path(optarg);
+                               break;
+                       case 's':
+#ifdef HAVE_LIBSELINUX
+                               token = strtok(optarg, ",");
+                               while (token) {
+                                       if (c.nr_opt == max_nr_opt) {
+                                               MSG(0, "\tError: Expected at most %d selinux opts\n",
+                                                                               max_nr_opt);
+                                               error_out(prog);
+                                       }
+                                       c.seopt_file[c.nr_opt].type =
+                                                               SELABEL_OPT_PATH;
+                                       c.seopt_file[c.nr_opt].value =
+                                                               absolute_path(token);
+                                       c.nr_opt++;
+                                       token = strtok(NULL, ",");
+                               }
+#else
+                               MSG(0, "Info: Not support selinux opts\n");
+#endif
                                break;
                        case 't':
                                c.mount_point = (char *)optarg;
                                break;
+                       case 'T':
+                               c.fixed_time = strtoul(optarg, &p, 0);
+                               break;
                        default:
                                err = EUNKNOWN_OPT;
                                break;
@@ -591,14 +648,13 @@ static int do_resize(struct f2fs_sb_info *sbi)
 static int do_sload(struct f2fs_sb_info *sbi)
 {
        if (!c.from_dir) {
-               MSG(0, "\tError: Need source directory\n");
-               sload_usage();
-               return -1;
+               MSG(0, "Info: No source directory, but it's okay.\n");
+               return 0;
        }
        if (!c.mount_point)
                c.mount_point = "/";
 
-       return f2fs_sload(sbi, c.from_dir, c.mount_point, NULL, NULL);
+       return f2fs_sload(sbi);
 }
 
 int main(int argc, char **argv)
@@ -665,8 +721,15 @@ fsck_again:
 #endif
 #ifdef WITH_SLOAD
        case SLOAD:
-               do_sload(sbi);
-               break;
+               if (do_sload(sbi))
+                       goto out_err;
+
+               f2fs_do_umount(sbi);
+
+               /* fsck to fix missing quota */
+               c.func = FSCK;
+               c.fix_on = 1;
+               goto fsck_again;
 #endif
        default:
                ERR_MSG("Wrong program name\n");
index 3efa298..f16f046 100644 (file)
@@ -47,6 +47,9 @@ void update_free_segments(struct f2fs_sb_info *sbi)
        char *progress = "-*|*-";
        static int i = 0;
 
+       if (c.dbg_lv)
+               return;
+
        MSG(0, "\r [ %c ] Free segments: 0x%x", progress[i % 5], get_free_segments(sbi));
        fflush(stdout);
        i++;
index 695fc6a..4f8bdb4 100644 (file)
@@ -328,6 +328,11 @@ int f2fs_build_file(struct f2fs_sb_info *sbi, struct dentry *de)
 
        update_free_segments(sbi);
 
-       MSG(1, "Info: built a file %s, size=%lu\n", de->full_path, de->size);
+       MSG(1, "Info: Create %s -> %s\n"
+               "  -- ino=%x, type=%x, mode=%x, uid=%x, "
+               "gid=%x, cap=%"PRIx64", size=%lu, pino=%x\n",
+               de->full_path, de->path,
+               de->ino, de->file_type, de->mode,
+               de->uid, de->gid, de->capabilities, de->size, de->pino);
        return 0;
 }
index bfc79f2..2842f2c 100644 (file)
 #endif
 
 #ifdef HAVE_LIBSELINUX
-#include <selinux/selinux.h>
-#include <selinux/label.h>
+static struct selabel_handle *sehnd = NULL;
 #endif
 
+typedef void (*fs_config_f)(const char *path, int dir,
+                           const char *target_out_path,
+                           unsigned *uid, unsigned *gid,
+                           unsigned *mode, uint64_t *capabilities);
+
+static fs_config_f fs_config_func = NULL;
+
 #ifdef WITH_ANDROID
-#include <selinux/label.h>
+#include <selinux/android.h>
 #include <private/android_filesystem_config.h>
-
-static void handle_selabel(struct dentry *de, int dir, char *target_out)
-{
-       uint64_t capabilities;
-       unsigned int mode = 0;
-       unsigned int uid = 0;
-       unsigned int gid = 0;
-
-       fs_config(de->path, dir, target_out, &uid,
-                       &gid, &mode, &capabilities);
-       de->mode = mode;
-       de->uid = uid;
-       de->gid = gid;
-       de->capabilities = capabilities;
-}
-#else
-#define handle_selabel(...)
+#include <private/canned_fs_config.h>
 #endif
 
 static int filter_dot(const struct dirent *d)
@@ -66,14 +56,123 @@ static void f2fs_make_directory(struct f2fs_sb_info *sbi,
        }
 }
 
+#ifdef HAVE_LIBSELINUX
+static int set_selinux_xattr(struct f2fs_sb_info *sbi, const char *path,
+                                                       nid_t ino, int mode)
+{
+       char *secontext = NULL;
+       char *mnt_path = NULL;
+
+       if (!sehnd)
+               return 0;
+
+       if (asprintf(&mnt_path, "%s%s", c.mount_point, path) <= 0) {
+               ERR_MSG("cannot allocate security path for %s%s\n",
+                                               c.mount_point, path);
+               return -ENOMEM;
+       }
+
+       /* set root inode selinux context */
+       if (selabel_lookup(sehnd, &secontext, mnt_path, mode) < 0) {
+               ERR_MSG("cannot lookup security context for %s\n", mnt_path);
+               free(mnt_path);
+               return -EINVAL;
+       }
+
+       if (secontext) {
+               MSG(2, "%s (%d) -> SELinux context = %s\n",
+                                               mnt_path, ino, secontext);
+               inode_set_selinux(sbi, ino, secontext);
+       }
+       freecon(secontext);
+       free(mnt_path);
+       return 0;
+}
+#else
+#define set_selinux_xattr(...) 0
+#endif
+
+static int set_perms_and_caps(struct dentry *de)
+{
+       uint64_t capabilities = 0;
+       unsigned int uid = 0, gid = 0, imode = 0;
+       char *mnt_path = NULL;
+
+       if (asprintf(&mnt_path, "%s%s", c.mount_point, de->path) <= 0) {
+               ERR_MSG("cannot allocate mount path for %s%s\n",
+                               c.mount_point, de->path);
+               return -ENOMEM;
+       }
+
+       /* Permissions */
+       if (fs_config_func != NULL) {
+               fs_config_func(mnt_path, S_ISDIR(de->mode),
+                               c.target_out_dir, &uid, &gid, &imode,
+                               &capabilities);
+               de->uid = uid & 0xffff;
+               de->gid = gid & 0xffff;
+               de->mode = (de->mode & S_IFMT) | (imode & 0xffff);
+               de->capabilities = capabilities;
+       }
+       MSG(2, "%s -> mode = 0x%x, uid = 0x%x, gid = 0x%x, "
+                       "capabilities = 0x%"PRIx64"\n",
+               mnt_path, de->mode, de->uid, de->gid, de->capabilities);
+       free(mnt_path);
+       return 0;
+}
+
+static void set_inode_metadata(struct dentry *de)
+{
+       struct stat stat;
+       int ret;
+
+       ret = lstat(de->full_path, &stat);
+       if (ret < 0) {
+               ERR_MSG("lstat failure\n");
+               ASSERT(0);
+       }
+
+       if (S_ISREG(stat.st_mode)) {
+               de->file_type = F2FS_FT_REG_FILE;
+       } else if (S_ISDIR(stat.st_mode)) {
+               de->file_type = F2FS_FT_DIR;
+       } else if (S_ISCHR(stat.st_mode)) {
+               de->file_type = F2FS_FT_CHRDEV;
+       } else if (S_ISBLK(stat.st_mode)) {
+               de->file_type = F2FS_FT_BLKDEV;
+       } else if (S_ISFIFO(stat.st_mode)) {
+               de->file_type = F2FS_FT_FIFO;
+       } else if (S_ISSOCK(stat.st_mode)) {
+               de->file_type = F2FS_FT_SOCK;
+       } else if (S_ISLNK(stat.st_mode)) {
+               de->file_type = F2FS_FT_SYMLINK;
+               de->link = calloc(F2FS_BLKSIZE, 1);
+               ASSERT(de->link);
+               ret = readlink(de->full_path, de->link, F2FS_BLKSIZE - 1);
+               ASSERT(ret >= 0);
+       } else {
+               ERR_MSG("unknown file type on %s", de->path);
+               ASSERT(0);
+       }
+
+       de->size = stat.st_size;
+       de->mode = stat.st_mode &
+                       (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
+       if (c.fixed_time == -1 && c.from_dir)
+               de->mtime = stat.st_mtime;
+       else
+               de->mtime = c.fixed_time;
+
+       set_perms_and_caps(de);
+}
+
 static int build_directory(struct f2fs_sb_info *sbi, const char *full_path,
                        const char *dir_path, const char *target_out_dir,
-                       nid_t dir_ino, struct selabel_handle *sehnd)
+                       nid_t dir_ino)
 {
        int entries = 0;
        struct dentry *dentries;
        struct dirent **namelist = NULL;
-       struct stat stat;
        int i, ret = 0;
 
        entries = scandir(full_path, &namelist, filter_dot, (void *)alphasort);
@@ -94,7 +193,7 @@ static int build_directory(struct f2fs_sb_info *sbi, const char *full_path,
                }
                dentries[i].len = strlen((char *)dentries[i].name);
 
-               ret = asprintf(&dentries[i].path, "%s/%s",
+               ret = asprintf(&dentries[i].path, "%s%s",
                                        dir_path, namelist[i]->d_name);
                ASSERT(ret > 0);
                ret = asprintf(&dentries[i].full_path, "%s/%s",
@@ -102,52 +201,9 @@ static int build_directory(struct f2fs_sb_info *sbi, const char *full_path,
                ASSERT(ret > 0);
                free(namelist[i]);
 
-               ret = lstat(dentries[i].full_path, &stat);
-               if (ret < 0) {
-                       ERR_MSG("Skip: lstat failure\n");
-                       continue;
-               }
-               dentries[i].size = stat.st_size;
-               dentries[i].mode = stat.st_mode &
-                       (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
-               dentries[i].mtime = stat.st_mtime;
-
-               handle_selabel(dentries + i, S_ISDIR(stat.st_mode),
-                                                       target_out_dir);
-
-#ifdef HAVE_LIBSELINUX
-               if (sehnd && selabel_lookup(sehnd, &dentries[i].secon,
-                                       dentries[i].path, stat.st_mode) < 0)
-                       ERR_MSG("Cannot lookup security context for %s\n",
-                                               dentries[i].path);
-#endif
+               set_inode_metadata(dentries + i);
 
                dentries[i].pino = dir_ino;
-
-               if (S_ISREG(stat.st_mode)) {
-                       dentries[i].file_type = F2FS_FT_REG_FILE;
-               } else if (S_ISDIR(stat.st_mode)) {
-                       dentries[i].file_type = F2FS_FT_DIR;
-               } else if (S_ISCHR(stat.st_mode)) {
-                       dentries[i].file_type = F2FS_FT_CHRDEV;
-               } else if (S_ISBLK(stat.st_mode)) {
-                       dentries[i].file_type = F2FS_FT_BLKDEV;
-               } else if (S_ISFIFO(stat.st_mode)) {
-                       dentries[i].file_type = F2FS_FT_FIFO;
-               } else if (S_ISSOCK(stat.st_mode)) {
-                       dentries[i].file_type = F2FS_FT_SOCK;
-               } else if (S_ISLNK(stat.st_mode)) {
-                       dentries[i].file_type = F2FS_FT_SYMLINK;
-                       dentries[i].link = calloc(F2FS_BLKSIZE, 1);
-                       ASSERT(dentries[i].link);
-                       ret = readlink(dentries[i].full_path,
-                                       dentries[i].link, F2FS_BLKSIZE - 1);
-                       ASSERT(ret >= 0);
-               } else {
-                       MSG(1, "unknown file type on %s", dentries[i].path);
-                       i--;
-                       entries--;
-               }
        }
 
        free(namelist);
@@ -159,9 +215,9 @@ static int build_directory(struct f2fs_sb_info *sbi, const char *full_path,
                        f2fs_build_file(sbi, dentries + i);
                } else if (dentries[i].file_type == F2FS_FT_DIR) {
                        char *subdir_full_path = NULL;
-                       char *subdir_dir_path;
+                       char *subdir_dir_path = NULL;
 
-                       ret = asprintf(&subdir_full_path, "%s/",
+                       ret = asprintf(&subdir_full_path, "%s",
                                                        dentries[i].full_path);
                        ASSERT(ret > 0);
                        ret = asprintf(&subdir_dir_path, "%s/",
@@ -169,7 +225,7 @@ static int build_directory(struct f2fs_sb_info *sbi, const char *full_path,
                        ASSERT(ret > 0);
 
                        build_directory(sbi, subdir_full_path, subdir_dir_path,
-                                       target_out_dir, dentries[i].ino, sehnd);
+                                       target_out_dir, dentries[i].ino);
                        free(subdir_full_path);
                        free(subdir_dir_path);
                } else if (dentries[i].file_type == F2FS_FT_SYMLINK) {
@@ -181,19 +237,10 @@ static int build_directory(struct f2fs_sb_info *sbi, const char *full_path,
                        MSG(1, "Error unknown file type\n");
                }
 
-#ifdef HAVE_LIBSELINUX
-               if (dentries[i].secon) {
-                       inode_set_selinux(sbi, dentries[i].ino, dentries[i].secon);
-                       MSG(1, "File = %s \n----->SELinux context = %s\n",
-                                       dentries[i].path, dentries[i].secon);
-                       MSG(1, "----->mode = 0x%x, uid = 0x%x, gid = 0x%x, "
-                                       "capabilities = 0x%lx \n",
-                                       dentries[i].mode, dentries[i].uid,
-                                       dentries[i].gid, dentries[i].capabilities);
-               }
-
-               free(dentries[i].secon);
-#endif
+               ret = set_selinux_xattr(sbi, dentries[i].path,
+                                       dentries[i].ino, dentries[i].mode);
+               if (ret)
+                       return ret;
 
                free(dentries[i].path);
                free(dentries[i].full_path);
@@ -204,47 +251,71 @@ static int build_directory(struct f2fs_sb_info *sbi, const char *full_path,
        return 0;
 }
 
-int f2fs_sload(struct f2fs_sb_info *sbi, const char *from_dir,
-                               const char *mount_point,
-                               const char *target_out_dir,
-                               struct selabel_handle *sehnd)
+static int configure_files(void)
 {
-       int ret = 0;
-       nid_t mnt_ino = F2FS_ROOT_INO(sbi);
+#ifdef HAVE_LIBSELINUX
+       if (!c.nr_opt)
+               goto skip;
+#if !defined(__ANDROID__)
+       sehnd = selabel_open(SELABEL_CTX_FILE, c.seopt_file, c.nr_opt);
+       if (!sehnd) {
+               ERR_MSG("Failed to open file contexts \"%s\"",
+                                       c.seopt_file[0].value);
+                       return -EINVAL;
+       }
+#else
+       sehnd = selinux_android_file_context_handle();
+       if (!sehnd) {
+               ERR_MSG("Failed to get android file_contexts\n", c.mount_point);
+               return -EINVAL;
+       }
+#endif
+skip:
+#endif
+#ifdef WITH_ANDROID
+       /* Load the FS config */
+       if (c.fs_config_file) {
+               int ret = load_canned_fs_config(c.fs_config_file);
 
-       /* flush NAT/SIT journal entries */
-       flush_journal_entries(sbi);
+               if (ret < 0) {
+                       ERR_MSG("Failed to load fs_config \"%s\"",
+                                               c.fs_config_file);
+                       return ret;
+               }
+               fs_config_func = canned_fs_config;
+       } else {
+               fs_config_func = fs_config;
+       }
+#endif
+       return 0;
+}
 
-       ret = f2fs_find_path(sbi, (char *)mount_point, &mnt_ino);
+int f2fs_sload(struct f2fs_sb_info *sbi)
+{
+       int ret = 0;
+
+       ret = configure_files();
        if (ret) {
-               ERR_MSG("Failed to get mount point %s\n", mount_point);
+               ERR_MSG("Failed to configure files\n");
                return ret;
        }
 
-       ret = build_directory(sbi, from_dir, mount_point, target_out_dir,
-                                               mnt_ino, sehnd);
+       /* flush NAT/SIT journal entries */
+       flush_journal_entries(sbi);
+
+       ret = build_directory(sbi, c.from_dir, "/",
+                                       c.target_out_dir, F2FS_ROOT_INO(sbi));
        if (ret) {
                ERR_MSG("Failed to build due to %d\n", ret);
                return ret;
        }
 
-#ifdef HAVE_LIBSELINUX
-       if (sehnd) {
-               char *secontext = NULL;
-
-               /* set root inode selinux context */
-               if (selabel_lookup(sehnd, &secontext, mount_point, S_IFDIR) < 0)
-                       ERR_MSG("cannot lookup security context for %s\n",
-                                                               mount_point);
-               if (secontext) {
-                       MSG(1, "Labeling %s as %s, root_ino = %d\n",
-                                       mount_point, secontext, F2FS_ROOT_INO(sbi));
-                       /* xattr_add for root inode */
-                       inode_set_selinux(sbi, F2FS_ROOT_INO(sbi), secontext);
-               }
-               free(secontext);
+       ret = set_selinux_xattr(sbi, c.mount_point,
+                                       F2FS_ROOT_INO(sbi), S_IFDIR);
+       if (ret) {
+               ERR_MSG("Failed to set selinux for root: %d\n", ret);
+               return ret;
        }
-#endif
 
        /* update curseg info; can update sit->types */
        move_curseg_info(sbi, SM_I(sbi)->main_blkaddr);
index f2576cd..1d15d1b 100644 (file)
@@ -77,7 +77,6 @@ static void write_all_xattrs(struct f2fs_sb_info *sbi,
        u64 inline_size = inline_xattr_size(&inode->i);
        int ret;
 
-       ASSERT(inode->i.i_inline & F2FS_INLINE_XATTR);
        memcpy(inline_xattr_addr(&inode->i), txattr_addr, inline_size);
 
        if (hsize <= inline_size)
index bfc4105..59ba1ee 100644 (file)
 #define HAVE_LSEEK64 1
 #define HAVE_MEMSET 1
 #define HAVE_SETMNTENT 1
+
+#ifdef WITH_SLOAD
+#define HAVE_LIBSELINUX 1
+#endif
 #endif
 
 #if defined(__APPLE__)
@@ -51,4 +55,8 @@
 #define HAVE_KEYCTL 1
 #define HAVE_LLSEEK 1
 #define HAVE_MEMSET 1
+
+#ifdef WITH_SLOAD
+#define HAVE_LIBSELINUX 1
+#endif
 #endif
index 7e766a8..3084cce 100644 (file)
 #include <linux/blkzoned.h>
 #endif
 
+#ifdef HAVE_LIBSELINUX
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#endif
+
 #ifdef UNUSED
 #elif defined(__GNUC__)
 # define UNUSED(x) UNUSED_ ## x __attribute__((unused))
@@ -359,6 +364,13 @@ struct f2fs_configuration {
        /* sload parameters */
        char *from_dir;
        char *mount_point;
+       char *target_out_dir;
+       char *fs_config_file;
+       time_t fixed_time;
+#ifdef HAVE_LIBSELINUX
+       struct selinux_opt seopt_file[8];
+       int nr_opt;
+#endif
 
        /* precomputed fs UUID checksum for seeding other checksums */
        u_int32_t chksum_seed;
index 1e63843..bbe3a8b 100644 (file)
@@ -614,6 +614,7 @@ void f2fs_init_configuration(void)
        c.ro = 0;
        c.kd = -1;
        c.dry_run = 0;
+       c.fixed_time = -1;
 }
 
 #ifdef HAVE_SETMNTENT