Whamcloud - gitweb
b=12797
[fs/lustre-release.git] / lustre / utils / lfs.c
index 1e90437..50ba49e 100644 (file)
@@ -23,7 +23,6 @@
  *
  */
 
-
 #include <stdlib.h>
 #include <stdio.h>
 #include <getopt.h>
@@ -37,6 +36,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 +69,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 +80,17 @@ 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"
+         "\t              Can be specified with k, m or g (in KB, MB and GB respectively)\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"
@@ -132,8 +142,16 @@ command_t cmdlist[] = {
          "usage: setquota [ -u | -g ] <name> <block-softlimit> <block-hardlimit> <inode-softlimit> <inode-hardlimit> <filesystem>\n"
          "       setquota -t [ -u | -g ] <block-grace> <inode-grace> <filesystem>"},
         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
-         "usage: quota [ -o obd_uuid ] [ -u | -g ] [name] <filesystem>"},
+         "usage: quota [ -o obd_uuid ] [{-u|-g  <name>}|-t] <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"},
@@ -145,45 +163,132 @@ static int lfs_setstripe(int argc, char **argv)
 {
         char *fname;
         int result;
-        long st_size;
+        unsigned 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 (*end != '\0') {
-                        fprintf(stderr, "error: %s: bad stripe size '%s'\n",
-                                argv[0], argv[2]);
+
+                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 offset */
-                st_offset = strtoul(argv[3], &end, 0);
+        /* get the stripe size */
+        if (stripe_size_arg != NULL) {
+                st_size = strtoul(stripe_size_arg, &end, 0);
+                if (*end != '\0') {
+                        if ((*end == 'k' || *end == 'K') && 
+                            *(end+1) == '\0' &&
+                            (st_size & (~0UL << (32 - 10))) == 0) {
+                                st_size <<= 10;
+                        } else if ((*end == 'm' || *end == 'M') && 
+                                   *(end+1) == '\0' &&
+                                   (st_size & (~0UL << (32 - 20))) == 0) {
+                                st_size <<= 20;
+                        } else if ((*end == 'g' || *end == 'G') && 
+                                   *(end+1) == '\0' &&
+                                   (st_size & (~0UL << (32 - 30))) == 0) {
+                                st_size <<= 30;
+                        } else {
+                                fprintf(stderr, "error: %s: bad stripe size '%s'\n",
+                                        argv[0], stripe_size_arg);
+                                return CMD_HELP;
+                        }
+                }
+        }
+        /* 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;
                 }
         }
@@ -225,12 +330,8 @@ static int lfs_find(int argc, char **argv)
 {
         int new_fashion = 1;
         int c, ret;
-        int zeroend;
         time_t t;
-        unsigned int depth;
-        int quiet, verbose, recursive;
-        struct find_param param;
-        struct obd_uuid *obduuid = NULL;
+        struct find_param param = { .maxdepth = -1 };
         char timestr[1024];
         struct option long_opts[] = {
                 /* New find options. */
@@ -258,15 +359,9 @@ static int lfs_find(int argc, char **argv)
         int isoption;
 
         time(&t);
-        zeroend = 0;
-        depth = -1;
-        quiet = verbose = recursive = 0;
-
-        memset(&param, 0, sizeof(param));
 
-        while ((c = getopt_long_only(argc, argv, "-A:C:D:M:n:PpOqrv",
-                                     long_opts, NULL)) >= 0)
-        {
+        while ((c = getopt_long_only(argc, argv, "-A:C:D:M:n:PpO:qrv",
+                                     long_opts, NULL)) >= 0) {
                 xtime = NULL;
                 xsign = NULL;
                 if (neg_opt)
@@ -295,7 +390,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;
@@ -329,7 +424,7 @@ static int lfs_find(int argc, char **argv)
                                 *xsign = ret;
                         break;
                 case 'D':
-                        depth = strtol(optarg, 0, 0);
+                        param.maxdepth = strtol(optarg, 0, 0);
                         break;
                 case 'n':
                         new_fashion = 1;
@@ -340,32 +435,32 @@ static int lfs_find(int argc, char **argv)
                                 param.exclude_pattern = 0;
                         break;
                 case 'O':
-                        if (obduuid) {
+                        if (param.obduuid) {
                                 fprintf(stderr,
                                         "error: %s: only one obduuid allowed",
                                         argv[0]);
                                 return CMD_HELP;
                         }
-                        obduuid = (struct obd_uuid *)optarg;
+                        param.obduuid = (struct obd_uuid *)optarg;
                         break;
                 case 'p':
-                        zeroend = 1;
+                        param.zeroend = 1;
                         break;
                 case 'P':
                         break;
                 case 'q':
                         new_fashion = 0;
-                        quiet++;
-                        verbose = 0;
+                        param.quiet++;
+                        param.verbose = 0;
                         break;
                 case 'r':
                         new_fashion = 0;
-                        recursive = 1;
+                        param.recursive = 1;
                         break;
                 case 'v':
                         new_fashion = 0;
-                        verbose++;
-                        quiet = 0;
+                        param.verbose++;
+                        param.quiet = 0;
                         break;
                 case '?':
                         return CMD_HELP;
@@ -375,28 +470,23 @@ 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 */
                 pathend = argc;
         }
 
-        param.obduuid = obduuid;
         if (new_fashion) {
-                param.maxdepth = depth;
-                param.zeroend = zeroend;
                 param.quiet = 1;
         } else {
-                param.recursive = recursive;
-                param.verbose = verbose;
-                param.quiet = quiet;
-                param.maxdepth = recursive ? -1 : 1;
+                if (!param.recursive && param.maxdepth == -1)
+                        param.maxdepth = 1;
         }
-
+        
         do {
                 if (new_fashion)
                         ret = llapi_find(argv[pathstart], &param);
@@ -407,7 +497,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;
 }
 
@@ -421,34 +510,32 @@ static int lfs_getstripe(int argc, char **argv)
                 {0, 0, 0, 0}
         };
         char short_opts[] = "hO:qrv";
-        int quiet, verbose, recursive, c, rc;
-        struct obd_uuid *obduuid = NULL;
-        struct find_param param;
+        int c, rc;
+        struct find_param param = { 0 };
 
         optind = 0;
-        quiet = verbose = recursive = 0;
         while ((c = getopt_long(argc, argv, short_opts,
                                 long_opts, NULL)) != -1) {
                 switch (c) {
                 case 'O':
-                        if (obduuid) {
+                        if (param.obduuid) {
                                 fprintf(stderr,
                                         "error: %s: only one obduuid allowed",
                                         argv[0]);
                                 return CMD_HELP;
                         }
-                        obduuid = (struct obd_uuid *)optarg;
+                        param.obduuid = (struct obd_uuid *)optarg;
                         break;
                 case 'q':
-                        quiet++;
-                        verbose = 0;
+                        param.quiet++;
+                        param.verbose = 0;
                         break;
                 case 'r':
-                        recursive = 1;
+                        param.recursive = 1;
                         break;
                 case 'v':
-                        verbose++;
-                        quiet = 0;
+                        param.verbose++;
+                        param.quiet = 0;
                         break;
                 case '?':
                         return CMD_HELP;
@@ -462,12 +549,7 @@ static int lfs_getstripe(int argc, char **argv)
         if (optind >= argc)
                 return CMD_HELP;
 
-        memset(&param, 0, sizeof(param));
-        param.recursive = recursive;
-        param.verbose = verbose;
-        param.quiet = quiet;
-        param.obduuid = obduuid;
-        param.maxdepth = recursive ? -1 : 1;
+        param.maxdepth = param.recursive ? -1 : 1;
 
         do {
                 rc = llapi_getstripe(argv[optind], &param);
@@ -500,7 +582,7 @@ static int lfs_osts(int argc, char **argv)
                 memset(&param, 0, sizeof(param));
                 param.obduuid = obduuid;
                 while (feof(fp) == 0 && ferror(fp) ==0) {
-                        if (llapi_is_lustre_mnttype(mnt)) {
+                        if (llapi_is_lustre_mnt(mnt)) {
                                 rc = llapi_getstripe(mnt->mnt_dir, &param);
                                 if (rc)
                                         fprintf(stderr,
@@ -548,7 +630,7 @@ static int path2mnt(char *path, FILE *fp, char *mntdir, int dir_len)
         len = 0;
         mnt = getmntent(fp);
         while (feof(fp) == 0 && ferror(fp) == 0) {
-                if (llapi_is_lustre_mnttype(mnt)) {
+                if (llapi_is_lustre_mnt(mnt)) {
                         len = strlen(mnt->mnt_dir);
                         if (len > out_len &&
                             !strncmp(rpath, mnt->mnt_dir, len)) {
@@ -769,7 +851,7 @@ static int lfs_df(int argc, char **argv)
         } else {
                 mnt = getmntent(fp);
                 while (feof(fp) == 0 && ferror(fp) == 0) {
-                        if (llapi_is_lustre_mnttype(mnt)) {
+                        if (llapi_is_lustre_mnt(mnt)) {
                                 rc = mntdf(mnt->mnt_dir, ishow, cooked);
                                 if (rc)
                                         break;
@@ -820,7 +902,7 @@ static int lfs_check(int argc, char **argv)
         } else {
                 mnt = getmntent(fp);
                 while (feof(fp) == 0 && ferror(fp) ==0) {
-                        if (llapi_is_lustre_mnttype(mnt))
+                        if (llapi_is_lustre_mnt(mnt))
                                 break;
                         mnt = getmntent(fp);
                 }
@@ -861,7 +943,7 @@ static int lfs_catinfo(int argc, char **argv)
         } else {
                 mnt = getmntent(fp);
                 while (feof(fp) == 0 && ferror(fp) == 0) {
-                        if (llapi_is_lustre_mnttype(mnt))
+                        if (llapi_is_lustre_mnt(mnt))
                                 break;
                         mnt = getmntent(fp);
                 }
@@ -1311,7 +1393,7 @@ static void print_quota_title(char *name, struct if_quotactl *qctl)
                *type2name(qctl->qc_type), qctl->qc_id);
         printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
                "Filesystem",
-               "blocks", "quota", "limit", "grace",
+               "kbytes", "quota", "limit", "grace",
                "files", "quota", "limit", "grace");
 }
 
@@ -1454,22 +1536,20 @@ static int lfs_quota(int argc, char **argv)
 {
         int c;
         char *name = NULL, *mnt;
-        struct if_quotactl qctl;
+        struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
+                                    .qc_type = 0x01 };
         char *obd_type = qctl.obd_type;
         char *obd_uuid = qctl.obd_uuid.uuid;
         int rc;
 
-        memset(&qctl, 0, sizeof(qctl));
-        qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
-
         optind = 0;
         while ((c = getopt(argc, argv, "ugto:")) != -1) {
                 switch (c) {
                 case 'u':
-                        qctl.qc_type |= 0x01;
+                        qctl.qc_type = 0x01;
                         break;
                 case 'g':
-                        qctl.qc_type |= 0x02;
+                        qctl.qc_type = 0x02;
                         break;
                 case 't':
                         qctl.qc_cmd = LUSTRE_Q_GETINFO;
@@ -1487,25 +1567,23 @@ static int lfs_quota(int argc, char **argv)
         if (qctl.qc_type)
                 qctl.qc_type--;
 
-        if (qctl.qc_type == UGQUOTA) {
-                fprintf(stderr, "error: user or group can't be specified"
-                                "both\n");
-                return CMD_HELP;
-        }
 
         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
-                if (optind + 2 != argc)
+                if (optind + 2 != argc) {
+                        fprintf(stderr, "error: missing quota argument(s)\n");
                         return CMD_HELP;
+                }
 
                 name = argv[optind++];
                 rc = name2id(&qctl.qc_id, name, qctl.qc_type);
                 if (rc) {
-                        fprintf(stderr, "error: find id for name %s failed: %s\n",
+                        fprintf(stderr,"error: can't find id for name %s: %s\n",
                                 name, strerror(errno));
                         return CMD_HELP;
                 }
                 print_quota_title(name, &qctl);
         } else if (optind + 1 != argc) {
+                fprintf(stderr, "error: missing quota info argument(s)\n");
                 return CMD_HELP;
         }
 
@@ -1538,6 +1616,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;