Whamcloud - gitweb
b=13201
[fs/lustre-release.git] / lustre / utils / lfs.c
index abda085..44905a0 100644 (file)
@@ -37,6 +37,9 @@
 #include <fcntl.h>
 #include <dirent.h>
 #include <time.h>
+#include <ctype.h>
+/* For dirname() */
+#include <libgen.h>
 
 #include <lnet/api-support.h>
 #include <lnet/lnetctl.h>
@@ -67,7 +70,10 @@ static int lfs_quotaoff(int argc, char **argv);
 static int lfs_setquota(int argc, char **argv);
 static int lfs_quota(int argc, char **argv);
 #endif
+static int lfs_flushctx(int argc, char **argv);
 static int lfs_join(int argc, char **argv);
+static int lfs_getfacl(int argc, char **argv);
+static int lfs_setfacl(int argc, char **argv);
 
 /* all avaialable commands */
 command_t cmdlist[] = {
@@ -75,12 +81,16 @@ command_t cmdlist[] = {
          "Create a new file with a specific striping pattern or\n"
          "set the default striping pattern on an existing directory or\n"
          "delete the default striping pattern from an existing directory\n"
-         "usage: setstripe <filename|dirname> <stripe size> <stripe start> <stripe count>\n"
+         "usage: setstripe <filename|dirname> <stripe_size> <stripe_index> <stripe_count>\n"
+         "       or \n"
+         "       setstripe <filename|dirname> [--size|-s stripe_size]\n"
+         "                                    [--index|-i stripe_index]\n"
+         "                                    [--count|-c stripe_count]\n"
          "       or \n"
          "       setstripe -d <dirname>   (to delete default striping)\n"
-         "\tstripe size:  Number of bytes on each OST (0 filesystem default)\n"
-         "\tstripe start: OST index of first stripe (-1 filesystem default)\n"
-         "\tstripe count: Number of OSTs to stripe over (0 default, -1 all)"},
+         "\tstripe_size:  Number of bytes on each OST (0 filesystem default)\n"
+         "\tstripe_index: OST index of first stripe (-1 filesystem default)\n"
+         "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)"},
         {"getstripe", lfs_getstripe, 0,
          "To list the striping info for a given filename or files in a\n"
          "directory or recursively for all files in a directory tree.\n"
@@ -134,6 +144,14 @@ command_t cmdlist[] = {
         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
          "usage: quota [ -o obd_uuid ] [ -u | -g ] [name] <filesystem>"},
 #endif
+        {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
+         "usage: flushctx [-k] [mountpoint...]"},
+        {"getfacl", lfs_getfacl, 0,
+         "Get file access control list in remote client.\n"
+         "usage: getfacl [-dRLPvh] file"},
+        {"setfacl", lfs_setfacl, 0,
+         "Set file access control list in remote client.\n"
+         "usage: setfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file"},
         {"help", Parser_help, 0, "help"},
         {"exit", Parser_quit, 0, "quit"},
         {"quit", Parser_quit, 0, "quit"},
@@ -148,42 +166,116 @@ static int lfs_setstripe(int argc, char **argv)
         long st_size;
         int  st_offset, st_count;
         char *end;
+        int c;
+        int delete = 0;
+        char *stripe_size_arg = NULL;
+        char *stripe_off_arg = NULL;
+        char *stripe_count_arg = NULL;
 
-        if (argc != 5 && argc != 3)
-                return CMD_HELP;
-
-
-        if (argc == 3) {
-                if (strcmp(argv[1], "-d") != 0)
-                        return CMD_HELP;
+        struct option long_opts[] = {
+                {"size",        required_argument, 0, 's'},
+                {"count",       required_argument, 0, 'c'},
+                {"index",       required_argument, 0, 'i'},
+                {"delete",      no_argument,       0, 'd'},
+                {0, 0, 0, 0}
+        };
 
+        st_size = 0;
+        st_offset = -1;
+        st_count = 0;
+        if (argc == 3 && strcmp(argv[1], "-d") == 0) {
+                /* for compatibility with the existing positional parameter
+                 * usage */
                 fname = argv[2];
-                st_size = 0;
-                st_offset = -1;
-                st_count = 0;
-        } else {
+                optind = 2;
+        } else if (argc == 5  && 
+                   (argv[2][0] != '-' || isdigit(argv[2][1])) &&
+                   (argv[3][0] != '-' || isdigit(argv[3][1])) &&
+                   (argv[4][0] != '-' || isdigit(argv[4][1])) ) {
+                /* for compatibility with the existing positional parameter
+                 * usage */
                 fname = argv[1];
+                stripe_size_arg = argv[2];
+                stripe_off_arg = argv[3];
+                stripe_count_arg = argv[4];
+                optind = 4;
+        } else {
+                while ((c = getopt_long(argc, argv, "c:di:s:",
+                                                long_opts, NULL)) >= 0) 
+                {
+                        switch (c) {
+                        case 0:
+                                /* Long options. */
+                                break;
+                        case 'c':
+                                stripe_count_arg = optarg;
+                                break;
+                        case 'd':
+                                /* delete the default striping pattern */
+                                delete = 1;
+                                break;
+                        case 'i':
+                                stripe_off_arg = optarg;
+                                break;
+                        case 's':
+                                stripe_size_arg = optarg;
+                                break;
+                        case '?':
+                                return CMD_HELP;
+                        default:
+                                fprintf(stderr, "error: %s: option '%s' "
+                                                "unrecognized\n",
+                                                argv[0], argv[optind - 1]);
+                                return CMD_HELP;
+                        }
+                }
+                if (optind < argc)
+                        fname = argv[optind];
+                else
+                        return CMD_HELP;
 
-                /* get the stripe size */
-                st_size = strtoul(argv[2], &end, 0);
+
+                if (delete && 
+                    (stripe_size_arg != NULL || stripe_off_arg != NULL || 
+                     stripe_count_arg != NULL)) {
+                        fprintf(stderr, "error: %s: cannot specify -d with "
+                                        "-s, -c or -i options\n",
+                                        argv[0]);
+                        return CMD_HELP;
+                }
+        }
+        if (optind != argc - 1) {
+                fprintf(stderr, "error: %s: only 1 filename|dirname can be "
+                                "specified: '%s'\n",
+                                argv[0], argv[argc - 1]);
+                return CMD_HELP;
+        }
+
+        /* get the stripe size */
+        if (stripe_size_arg != NULL) {
+                st_size = strtoul(stripe_size_arg, &end, 0);
                 if (*end != '\0') {
                         fprintf(stderr, "error: %s: bad stripe size '%s'\n",
-                                argv[0], argv[2]);
+                                argv[0], stripe_size_arg);
                         return CMD_HELP;
                 }
 
-                /* get the stripe offset */
-                st_offset = strtoul(argv[3], &end, 0);
+        }
+        /* get the stripe offset */
+        if (stripe_off_arg != NULL) {
+                st_offset = strtoul(stripe_off_arg, &end, 0);
                 if (*end != '\0') {
                         fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
-                                argv[0], argv[3]);
+                                argv[0], stripe_off_arg);
                         return CMD_HELP;
                 }
-                /* get the stripe count */
-                st_count = strtoul(argv[4], &end, 0);
+        }
+        /* get the stripe count */
+        if (stripe_count_arg != NULL) {
+                st_count = strtoul(stripe_count_arg, &end, 0);
                 if (*end != '\0') {
                         fprintf(stderr, "error: %s: bad stripe count '%s'\n",
-                                argv[0], argv[4]);
+                                argv[0], stripe_count_arg);
                         return CMD_HELP;
                 }
         }
@@ -295,7 +387,7 @@ static int lfs_find(int argc, char **argv)
                 case 1:
                         if (strcmp(optarg, "!") == 0)
                                 neg_opt = 2;
-                      break;
+                        break;
                 case 'A':
                         xtime = &param.atime;
                         xsign = &param.asign;
@@ -375,10 +467,10 @@ static int lfs_find(int argc, char **argv)
                         return CMD_HELP;
                 };
         }
-
+        
         if (pathstart == -1) {
                 fprintf(stderr, "error: %s: no filename|pathname\n",
-                                argv[0]);
+                        argv[0]);
                 return CMD_HELP;
         } else if (pathend == -1) {
                 /* no options */
@@ -396,7 +488,7 @@ static int lfs_find(int argc, char **argv)
                 param.quiet = quiet;
                 param.maxdepth = recursive ? -1 : 1;
         }
-
+        
         do {
                 if (new_fashion)
                         ret = llapi_find(argv[pathstart], &param);
@@ -407,7 +499,6 @@ static int lfs_find(int argc, char **argv)
         if (ret)
                 fprintf(stderr, "error: %s failed for %s.\n",
                         argv[0], argv[optind - 1]);
-
         return ret;
 }
 
@@ -1538,6 +1629,205 @@ static int lfs_quota(int argc, char **argv)
 }
 #endif /* HAVE_QUOTA_SUPPORT */
 
+static int flushctx_ioctl(char *mp)
+{
+        int fd, rc;
+
+        fd = open(mp, O_RDONLY);
+        if (fd == -1) {
+                fprintf(stderr, "flushctx: error open %s: %s\n",
+                        mp, strerror(errno));
+                return -1;
+        }
+
+        rc = ioctl(fd, LL_IOC_FLUSHCTX);
+        if (rc == -1)
+                fprintf(stderr, "flushctx: error ioctl %s: %s\n",
+                        mp, strerror(errno));
+
+        close(fd);
+        return rc;
+}
+
+static int lfs_flushctx(int argc, char **argv)
+{
+        int     kdestroy = 0, c;
+        FILE   *proc;
+        char    procline[PATH_MAX], *line;
+        int     rc = 0;
+
+        optind = 0;
+        while ((c = getopt(argc, argv, "k")) != -1) {
+                switch (c) {
+                case 'k':
+                        kdestroy = 1;
+                        break;
+                default:
+                        fprintf(stderr, "error: %s: option '-%c' "
+                                        "unrecognized\n", argv[0], c);
+                        return CMD_HELP;
+                }
+        }
+
+        if (kdestroy)
+                system("kdestroy > /dev/null");
+
+        if (optind >= argc) {
+                /* flush for all mounted lustre fs. */
+                proc = fopen("/proc/mounts", "r");
+                if (!proc) {
+                        fprintf(stderr, "error: %s: can't open /proc/mounts\n",
+                                argv[0]);
+                        return -1;
+                }
+
+                while ((line = fgets(procline, PATH_MAX, proc)) != NULL) {
+                        char dev[PATH_MAX];
+                        char mp[PATH_MAX];
+                        char fs[PATH_MAX];
+
+                        if (sscanf(line, "%s %s %s", dev, mp, fs) != 3) {
+                                fprintf(stderr, "%s: unexpected format in "
+                                                "/proc/mounts\n",
+                                        argv[0]);
+                                return -1;
+                        }
+
+                        if (strcmp(fs, "lustre") != 0)
+                                continue;
+                        /* we use '@' to determine it's a client. are there
+                         * any other better way?
+                         */
+                        if (strchr(dev, '@') == NULL)
+                                continue;
+
+                        if (flushctx_ioctl(mp))
+                                rc = -1;
+                }
+        } else {
+                /* flush fs as specified */
+                while (optind < argc) {
+                        if (flushctx_ioctl(argv[optind++]))
+                                rc = -1;
+                }
+        }
+
+        return rc;
+}
+
+/*
+ * We assume one and only one filename is supplied as the
+ * last parameter.
+ */
+static int acl_cmd_parse(int argc, char **argv, char *fname, char *cmd)
+{
+        char *dname, *rpath = NULL;
+        char path[PATH_MAX], cwd[PATH_MAX];
+        FILE *fp;
+        struct mntent *mnt;
+        int i;
+
+        if (argc < 2)
+                return -1;
+
+        /* FIXME the premise is there is no sub-mounted filesystems under this
+         * mounted lustre tree. */
+        strncpy(fname, argv[argc - 1], PATH_MAX);
+
+        /* get path prefix */
+        dname = dirname(fname);
+
+        /* try to resolve the pathname into relative to the root of the mounted
+         * lustre filesystem.
+         */
+        if (getcwd(cwd, sizeof(cwd)) == NULL) {
+                fprintf(stderr, "getcwd %s failed: %s\n", cwd, strerror(errno));
+                return -1;
+        }
+
+        if (chdir(dname) == -1) {
+                fprintf(stderr, "chdir to %s failed: %s\n",
+                        dname, strerror(errno));
+                return -1;
+        }
+
+        if (getcwd(path, sizeof(path)) == NULL) {
+                fprintf(stderr, "getcwd %s: %s\n", path, strerror(errno));
+                return -1;
+        }
+
+        if (chdir(cwd) == -1) {
+                fprintf(stderr, "chdir back to %s: %s\n",
+                        cwd, strerror(errno));
+                return -1;
+        }
+
+        strncat(path, "/", PATH_MAX);
+        strncpy(fname, argv[argc - 1], PATH_MAX);
+        strncat(path, basename(fname), PATH_MAX);
+
+        fp = setmntent(MOUNTED, "r");
+        if (fp == NULL) {
+                fprintf(stderr, "setmntent %s failed: %s\n",
+                        MOUNTED, strerror(errno));
+                return -1;
+        }
+
+        while (1) {
+                mnt = getmntent(fp);
+                if (!mnt)
+                        break;
+
+                if (!llapi_is_lustre_mnttype(mnt->mnt_type))
+                        continue;
+
+                if (!strncmp(mnt->mnt_dir, path, strlen(mnt->mnt_dir))) {
+                        rpath = path + strlen(mnt->mnt_dir);
+                        break;
+                }
+        }
+        endmntent(fp);
+
+        /* remove char '/' from rpath to be a relative path */
+        while (rpath && *rpath == '/') rpath++;
+
+        if (!rpath) {
+                fprintf(stderr,
+                        "%s: file %s doesn't belong to a lustre file system!\n",
+                        argv[0], argv[argc - 1]);
+                return -1;
+        }
+
+        for (i = 0; i < argc - 1; i++) {
+                strncat(cmd, argv[i], PATH_MAX);
+                strncat(cmd, " ", PATH_MAX);
+        }
+        strncat(cmd, *rpath ? rpath : ".", PATH_MAX);
+        strncpy(fname, argv[argc - 1], sizeof(fname));
+
+        return 0;
+}
+
+static int lfs_getfacl(int argc, char **argv)
+{
+        char fname[PATH_MAX] = "", cmd[PATH_MAX] = "";
+
+        if (acl_cmd_parse(argc, argv, fname, cmd))
+                return CMD_HELP;
+
+        return llapi_getfacl(fname, cmd);
+}
+
+static int lfs_setfacl(int argc, char **argv)
+{
+        char fname[PATH_MAX] = "", cmd[PATH_MAX] = "";
+
+        if (acl_cmd_parse(argc, argv, fname, cmd))
+                return CMD_HELP;
+
+        return llapi_setfacl(fname, cmd);
+}
+
 int main(int argc, char **argv)
 {
         int rc;