Whamcloud - gitweb
LU-11380 llapi: add llapi_fid_parse() helper 84/36184/11
authorAndreas Dilger <adilger@whamcloud.com>
Fri, 13 Sep 2019 23:27:23 +0000 (17:27 -0600)
committerOleg Drokin <green@whamcloud.com>
Fri, 6 Dec 2019 01:03:53 +0000 (01:03 +0000)
Split the llapi_* FID handling functions to a separate file
rather than continually increasing the size of liblustrepai.c.

Add llapi_fid_parse() to parse a string to binary struct lu_fid.

Signed-off-by: Andreas Dilger <adilger@whamcloud.com>
Change-Id: I15abfaf888a5474d62feebab4e8db543ba3ebbe5
Reviewed-on: https://review.whamcloud.com/36184
Tested-by: jenkins <devops@whamcloud.com>
Reviewed-by: Olaf Faaland-LLNL <faaland1@llnl.gov>
Reviewed-by: Jian Yu <yujian@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: James Simmons <jsimmons@infradead.org>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/doc/Makefile.am
lustre/doc/llapi_fid_parse.3 [new file with mode: 0644]
lustre/doc/lustreapi.7
lustre/include/lustre/lustreapi.h
lustre/utils/LCOPYING
lustre/utils/Makefile.am
lustre/utils/lfs.c
lustre/utils/lhsmtool_posix.c
lustre/utils/liblustreapi.c
lustre/utils/liblustreapi_fid.c [new file with mode: 0644]
lustre/utils/obd.c

index 3e908f2..fbb3458 100644 (file)
@@ -71,6 +71,7 @@ MANFILES =                                    \
        lhbadm.8                                \
        llapi_create_volatile_param.3           \
        llapi_fd2parent.3                       \
+       llapi_fid_parse.3                       \
        llapi_file_create.3                     \
        llapi_file_create_foreign.3             \
        llapi_file_get_stripe.3                 \
diff --git a/lustre/doc/llapi_fid_parse.3 b/lustre/doc/llapi_fid_parse.3
new file mode 100644 (file)
index 0000000..2889ba8
--- /dev/null
@@ -0,0 +1,86 @@
+.TH lustreapi 3 "2019 Sep 13" Lustre user application interface library
+.SH NAME
+llapi_fid_parse \- parse ASCII FID string into binary lu_fid
+.SH SYNOPSIS
+.nf
+.B #include <lustre/lustreapi.h>
+.sp
+.BI "int llapi_fid_parse(const char *" fidstr ", struct lu_fid *" fid ,
+.BI "                    char **" endptr ");"
+.sp
+.fi
+.SH DESCRIPTION
+.LP
+.B llapi_fid_parse()
+converts an ASCII FID string into a binary
+.B struct lu_fid
+for use in other interfaces such as
+.BR llapi_layout_get_by_fid() .
+.I fidstr
+should contain three numbers in the form
+.IR fid_seq : fid_oid : fid_ver
+and may optionally be enclosed in square braces
+.BR [] .
+It will skip any leading whitespace before the FID.
+.LP
+If
+.I endptr
+is not NULL,
+.B llapi_fid_parse()
+stores the address of the first invalid character in
+.IR *endptr ,
+or the character immediately following the end of the parsed FID.
+.SH RETURN VALUES
+.LP
+.B llapi_fid_parse()
+returns:
+.TP
+0
+on success,
+.TP
+<0
+a negative errno on failure and sets errno.
+.SH ERRORS
+.TP 15
+.SM EINVAL
+.I fidstr
+is NULL or does not contain a valid FID format.
+.TP
+.SM ERANGE
+.I fidstr
+contains numeric values that exceed valid values for a component.
+.SH "EXAMPLE"
+.nf
+#include <lustre/lustreapi.h>
+
+int main(int argc, char *argv[])
+{
+        char fidstr = "[0x200000004:0x2:0x0] [0x200000400:0x345:0x0]";
+        struct lu_fid fid1, fid2;
+        char *end;
+        int rc;
+
+        fidstr = argv[1];
+        rc = llapi_fid_parse(fidstr, &fid1, &end);
+        if (rc < 0) {
+                fprintf(stderr, "invalid first FID '%s': %s\\n",
+                        fidstr, strerror(-rc));
+                return -1;
+        }
+
+        fidstr = end;
+        rc = llapi_fid_parse(fidstr, &fid2, &end);
+        if (rc < 0) {
+                fprintf(stderr, "invalid second FID '%s': %s\\n",
+                        fidstr, strerror(-rc));
+                return -1;
+        }
+
+        printf("fid1=" DFID " fid2="DFID"\\n", PFID(&fid1), PFID(&fid2));
+        return 0;
+}
+.fi
+.SH "SEE ALSO"
+.BR lustre (7),
+.BR llapi_path2parent (3),
+.BR lustreapi (7)
index b733832..47f06ee 100644 (file)
@@ -14,6 +14,7 @@ quotas, file layouts, etc).  See the referenced man pages for details.
 .BR llapi_create_volatile_param (3),
 .BR llapi_fd2parent (3),
 .BR llapi_fid2path (3),
+.BR llapi_fid_parse (3),
 .BR llapi_file_create (3),
 .BR llapi_file_get_stripe (3),
 .BR llapi_file_open (3),
index 237dc65..bd1f940 100644 (file)
@@ -409,6 +409,7 @@ int llapi_target_iterate(int type_num, char **obd_type, void *args,
 int llapi_get_connect_flags(const char *mnt, __u64 *flags);
 int llapi_cp(int argc, char *argv[]);
 int llapi_ls(int argc, char *argv[]);
+int llapi_fid_parse(const char *fidstr, struct lu_fid *fid, char **endptr);
 int llapi_fid2path(const char *device, const char *fidstr, char *path,
                   int pathlen, long long *recno, int *linkno);
 int llapi_path2fid(const char *path, struct lu_fid *fid);
index 5e37211..105f1fd 100644 (file)
@@ -1,4 +1,5 @@
 This licence file applies to new library files:
+lustre/utils/liblustreapi_fid.c
 lustre/utils/liblustreapi_hsm.c
 lustre/utils/liblustreapi_json.c
 lustre/utils/liblustreapi_layout.c
index 8704f5b..9cb0e6f 100644 (file)
@@ -96,7 +96,7 @@ liblustreapi_la_SOURCES = liblustreapi.c liblustreapi_hsm.c \
                          liblustreapi_json.c liblustreapi_layout.c \
                          liblustreapi_lease.c liblustreapi_util.c \
                          liblustreapi_kernelconn.c liblustreapi_param.c \
-                         liblustreapi_mirror.c \
+                         liblustreapi_mirror.c liblustreapi_fid.c \
                          liblustreapi_ladvise.c liblustreapi_chlg.c \
                          liblustreapi_heat.c liblustreapi_pcc.c
 liblustreapi_la_LDFLAGS = $(LIBREADLINE) -version-info 1:0:0 \
index c96afdf..c815e1c 100644 (file)
@@ -8195,16 +8195,10 @@ static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
        hui->hui_extent.length = -1;
 
        if (mntpath != NULL) {
-               if (*fname == '[')
-                       fname++;
-               rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
-               if (rc == 3) {
-                       rc = 0;
-               } else {
+               rc = llapi_fid_parse(fname, &hui->hui_fid, NULL);
+               if (rc)
                        fprintf(stderr, "hsm: '%s' is not a valid FID\n",
                                fname);
-                       rc = -EINVAL;
-               }
        } else {
                rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
        }
index 152dc81..5dbe904 100644 (file)
@@ -1542,10 +1542,9 @@ static int ct_import_recurse(const char *relpath)
        if (relpath == NULL)
                return -EINVAL;
 
-       /* Is relpath a FID? In which case SFID should expand to three
-        * elements. */
-       rc = sscanf(relpath, SFID, RFID(&import_fid));
-       if (rc == 3)
+       /* Is relpath a FID? */
+       rc = llapi_fid_parse(relpath, &import_fid, NULL);
+       if (!rc)
                return ct_import_fid(&import_fid);
 
        srcpath = path_concat(opt.o_hsm_root, relpath);
@@ -1692,8 +1691,9 @@ static int ct_rebind_list(const char *list)
 
        /* each line consists of 2 FID */
        while ((r = getline(&line, &line_size, filp)) != -1) {
-               struct lu_fid   old_fid;
-               struct lu_fid   new_fid;
+               struct lu_fid old_fid;
+               struct lu_fid new_fid;
+               char *next_fid;
 
                /* Ignore empty and commented out ('#...') lines. */
                if (should_ignore_line(line))
@@ -1701,12 +1701,17 @@ static int ct_rebind_list(const char *list)
 
                nl++;
 
-               rc = sscanf(line, SFID" "SFID, RFID(&old_fid), RFID(&new_fid));
-               if (rc != 6 || !fid_is_file(&old_fid) ||
-                   !fid_is_file(&new_fid)) {
-                       CT_ERROR(EINVAL,
-                                "'%s' FID expected near '%s', line %u",
-                                list, line, nl);
+               rc = llapi_fid_parse(line, &old_fid, &next_fid);
+               if (rc)
+                       goto error;
+               rc = llapi_fid_parse(next_fid, &new_fid, NULL);
+               if (rc)
+                       goto error;
+               if (!fid_is_file(&old_fid) || !fid_is_file(&new_fid))
+                       rc = -EINVAL;
+               if (rc) {
+error:                 CT_ERROR(rc, "%s:%u: two FIDs expected in '%s'",
+                                list, nl, line);
                        err_major++;
                        continue;
                }
@@ -1730,23 +1735,25 @@ static int ct_rebind_list(const char *list)
 
 static int ct_rebind(void)
 {
-       int     rc;
+       int rc;
 
        if (opt.o_dst) {
                struct lu_fid old_fid;
                struct lu_fid new_fid;
 
-               if (sscanf(opt.o_src, SFID, RFID(&old_fid)) != 3 ||
-                   !fid_is_file(&old_fid)) {
+               rc = llapi_fid_parse(opt.o_src, &old_fid, NULL);
+               if (!rc && !fid_is_file(&old_fid))
                        rc = -EINVAL;
-                       CT_ERROR(rc, "'%s' invalid FID format", opt.o_src);
+               if (rc) {
+                       CT_ERROR(rc, "invalid source FID '%s'", opt.o_src);
                        return rc;
                }
 
-               if (sscanf(opt.o_dst, SFID, RFID(&new_fid)) != 3 ||
-                   !fid_is_file(&new_fid)) {
+               rc = llapi_fid_parse(opt.o_dst, &new_fid, NULL);
+               if (!rc && !fid_is_file(&new_fid))
                        rc = -EINVAL;
-                       CT_ERROR(rc, "'%s' invalid FID format", opt.o_dst);
+               if (rc) {
+                       CT_ERROR(rc, "invalid destination FID '%s'", opt.o_dst);
                        return rc;
                }
 
index 754536f..726b520 100644 (file)
@@ -5499,248 +5499,6 @@ int llapi_quotactl(char *mnt, struct if_quotactl *qctl)
        return rc;
 }
 
-/* Print mdtname 'name' into 'buf' using 'format'.  Add -MDT0000 if needed.
- * format must have %s%s, buf must be > 16
- * Eg: if name = "lustre-MDT0000", "lustre", or "lustre-MDT0000_UUID"
- *     then buf = "lustre-MDT0000"
- */
-static int get_mdtname(char *name, char *format, char *buf)
-{
-        char suffix[]="-MDT0000";
-        int len = strlen(name);
-
-        if ((len > 5) && (strncmp(name + len - 5, "_UUID", 5) == 0)) {
-                name[len - 5] = '\0';
-                len -= 5;
-        }
-
-        if (len > 8) {
-                if ((len <= 16) && strncmp(name + len - 8, "-MDT", 4) == 0) {
-                        suffix[0] = '\0';
-                } else {
-                        /* Not enough room to add suffix */
-                        llapi_err_noerrno(LLAPI_MSG_ERROR,
-                                         "Invalid MDT name |%s|", name);
-                        return -EINVAL;
-                }
-        }
-
-        return sprintf(buf, format, name, suffix);
-}
-
-/** ioctl on filsystem root, with mdtindex sent as data
- * \param mdtname path, fsname, or mdtname (lutre-MDT0004)
- * \param mdtidxp pointer to integer within data to be filled in with the
- *    mdt index (0 if no mdt is specified).  NULL won't be filled.
- */
-int root_ioctl(const char *mdtname, int opc, void *data, int *mdtidxp,
-              int want_error)
-{
-       char fsname[20];
-       char *ptr;
-       int fd, rc;
-       long index;
-
-       /* Take path, fsname, or MDTname.  Assume MDT0000 in the former cases.
-        Open root and parse mdt index. */
-       if (mdtname[0] == '/') {
-               index = 0;
-               rc = get_root_path(WANT_FD | want_error, NULL, &fd,
-                                  (char *)mdtname, -1);
-       } else {
-               if (get_mdtname((char *)mdtname, "%s%s", fsname) < 0)
-                       return -EINVAL;
-               ptr = fsname + strlen(fsname) - 8;
-               *ptr = '\0';
-               index = strtol(ptr + 4, NULL, 16);
-               rc = get_root_path(WANT_FD | want_error, fsname, &fd, NULL, -1);
-       }
-       if (rc < 0) {
-               if (want_error)
-                       llapi_err_noerrno(LLAPI_MSG_ERROR,
-                                         "Can't open %s: %d\n", mdtname, rc);
-               return rc;
-       }
-
-       if (mdtidxp)
-               *mdtidxp = index;
-
-       rc = ioctl(fd, opc, data);
-       if (rc == -1)
-               rc = -errno;
-       else
-               rc = 0;
-       close(fd);
-       return rc;
-}
-
-int llapi_fid2path(const char *device, const char *fidstr, char *buf,
-                  int buflen, long long *recno, int *linkno)
-{
-       const char *fidstr_orig = fidstr;
-       struct lu_fid fid;
-       struct getinfo_fid2path *gf;
-       char *a;
-       char *b;
-       int rc;
-
-       while (*fidstr == '[')
-               fidstr++;
-
-       sscanf(fidstr, SFID, RFID(&fid));
-       if (!fid_is_sane(&fid)) {
-               llapi_err_noerrno(LLAPI_MSG_ERROR,
-                                 "bad FID format '%s', should be [seq:oid:ver]"
-                                 " (e.g. "DFID")\n", fidstr_orig,
-                                 (unsigned long long)FID_SEQ_NORMAL, 2, 0);
-               return -EINVAL;
-       }
-
-       gf = malloc(sizeof(*gf) + buflen);
-       if (gf == NULL)
-               return -ENOMEM;
-
-       gf->gf_fid = fid;
-       gf->gf_recno = *recno;
-       gf->gf_linkno = *linkno;
-       gf->gf_pathlen = buflen;
-
-       /* Take path or fsname */
-       rc = root_ioctl(device, OBD_IOC_FID2PATH, gf, NULL, 0);
-       if (rc)
-               goto out_free;
-
-       b = buf;
-       /* strip out instances of // */
-       for (a = gf->gf_u.gf_path; *a != '\0'; a++) {
-               if ((*a == '/') && (*(a + 1) == '/'))
-                       continue;
-               *b = *a;
-               b++;
-       }
-       *b = '\0';
-
-       if (buf[0] == '\0') { /* ROOT path */
-               buf[0] = '/';
-               buf[1] = '\0';
-       }
-
-       *recno = gf->gf_recno;
-       *linkno = gf->gf_linkno;
-
-out_free:
-       free(gf);
-       return rc;
-}
-
-static int fid_from_lma(const char *path, int fd, struct lu_fid *fid)
-{
-       char                     buf[512];
-       struct lustre_mdt_attrs *lma;
-       int                      rc;
-
-       if (path == NULL)
-               rc = fgetxattr(fd, XATTR_NAME_LMA, buf, sizeof(buf));
-       else
-               rc = lgetxattr(path, XATTR_NAME_LMA, buf, sizeof(buf));
-       if (rc < 0)
-               return -errno;
-       lma = (struct lustre_mdt_attrs *)buf;
-       fid_le_to_cpu(fid, &lma->lma_self_fid);
-       return 0;
-}
-
-int llapi_get_mdt_index_by_fid(int fd, const struct lu_fid *fid,
-                              int *mdt_index)
-{
-       int     rc;
-
-       rc = ioctl(fd, LL_IOC_FID2MDTIDX, fid);
-       if (rc < 0)
-               return -errno;
-
-       *mdt_index = rc;
-
-       return rc;
-}
-
-int llapi_fd2fid(int fd, struct lu_fid *fid)
-{
-       int rc;
-
-       memset(fid, 0, sizeof(*fid));
-
-       rc = ioctl(fd, LL_IOC_PATH2FID, fid) < 0 ? -errno : 0;
-       if (rc == -EINVAL || rc == -ENOTTY)
-               rc = fid_from_lma(NULL, fd, fid);
-
-       return rc;
-}
-
-int llapi_path2fid(const char *path, struct lu_fid *fid)
-{
-       int fd, rc;
-
-       memset(fid, 0, sizeof(*fid));
-       fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
-       if (fd < 0) {
-               if (errno == ELOOP || errno == ENXIO)
-                       return fid_from_lma(path, -1, fid);
-               return -errno;
-       }
-
-       rc = llapi_fd2fid(fd, fid);
-       if (rc == -EINVAL || rc == -ENOTTY)
-               rc = fid_from_lma(path, -1, fid);
-
-       close(fd);
-       return rc;
-}
-
-int llapi_fd2parent(int fd, unsigned int linkno, struct lu_fid *parent_fid,
-                   char *name, size_t name_size)
-{
-       struct getparent        *gp;
-       int                      rc;
-
-       gp = malloc(sizeof(*gp) + name_size);
-       if (gp == NULL)
-               return -ENOMEM;
-
-       gp->gp_linkno = linkno;
-       gp->gp_name_size = name_size;
-
-       rc = ioctl(fd, LL_IOC_GETPARENT, gp);
-       if (rc < 0) {
-               rc = -errno;
-               goto err_free;
-       }
-
-       *parent_fid = gp->gp_fid;
-
-       strncpy(name, gp->gp_name, name_size);
-       name[name_size - 1] = '\0';
-
-err_free:
-       free(gp);
-       return rc;
-}
-
-int llapi_path2parent(const char *path, unsigned int linkno,
-                     struct lu_fid *parent_fid, char *name, size_t name_size)
-{
-       int     fd;
-       int     rc;
-
-       fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
-       if (fd < 0)
-               return -errno;
-
-       rc = llapi_fd2parent(fd, linkno, parent_fid, name, name_size);
-       close(fd);
-       return rc;
-}
-
 int llapi_get_connect_flags(const char *mnt, __u64 *flags)
 {
        int root;
@@ -6068,32 +5826,6 @@ out:
 }
 
 /**
- * Attempt to open a file with Lustre file identifier \a fid
- * and return an open file descriptor.
- *
- * \param[in] lustre_dir       path within Lustre filesystem containing \a fid
- * \param[in] fid              Lustre file identifier of file to open
- * \param[in] flags            open() flags
- *
- * \retval                     non-negative file descriptor on successful open
- * \retval                     -1 if an error occurred
- */
-int llapi_open_by_fid(const char *lustre_dir, const struct lu_fid *fid,
-                     int flags)
-{
-       char mntdir[PATH_MAX];
-       char path[PATH_MAX + 64];
-       int rc;
-
-       rc = llapi_search_mounts(lustre_dir, 0, mntdir, NULL);
-       if (rc != 0)
-               return -1;
-
-       snprintf(path, sizeof(path), "%s/.lustre/fid/"DFID, mntdir, PFID(fid));
-       return open(path, flags);
-}
-
-/**
  * Take group lock.
  *
  * \param fd   File to lock.
diff --git a/lustre/utils/liblustreapi_fid.c b/lustre/utils/liblustreapi_fid.c
new file mode 100644 (file)
index 0000000..0034714
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * LGPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the GNU Lesser General Public License
+ * (LGPL) version 2.1 or (at your discretion) any later version.
+ * (LGPL) version 2.1 accompanies this distribution, and is available at
+ * http://www.gnu.org/licenses/lgpl-2.1.html
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * LGPL HEADER END
+ */
+/*
+ * lustre/utils/liblustreapi_fid.c
+ *
+ * lustreapi library for FID mapping calls for determining the pathname
+ * of Lustre files from the File IDentifier.
+ *
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Copyright (c) 2011, 2017, Intel Corporation.
+ *
+ * Copyright (c) 2018, 2019, Data Direct Networks
+ */
+
+/* for O_DIRECTORY */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/xattr.h>
+#include <unistd.h>
+
+#include <libcfs/util/ioctl.h>
+#include <lustre/lustreapi.h>
+#include <linux/lustre/lustre_fid.h>
+#include "lustreapi_internal.h"
+
+/* strip instances of // (DNE striped directory) when copying to reply buffer */
+static int copy_strip_dne_path(const char *src, char *tgt, size_t tgtlen)
+{
+       const char *a;
+       char *b;
+
+       for (a = src, b = tgt; *a != '\0' && b - tgt < tgtlen; a++) {
+               if (*a == '/' && *(a + 1) == '/')
+                       continue;
+               *b = *a;
+               b++;
+       }
+       if (b - tgt >= tgtlen) {
+               errno = ERANGE;
+               return -errno;
+       }
+
+       *b = '\0';
+
+       if (tgt[0] == '\0') { /* ROOT path */
+               tgt[0] = '/';
+               tgt[1] = '\0';
+       }
+
+       return 0;
+}
+
+/**
+ * parse a FID from a string into a binary lu_fid
+ *
+ * Only the format of the FID is checked, not whether the numeric value
+ * contains a valid FID sequence or object ID or version. Optional leading
+ * whitespace and '[' from the standard FID format are skipped.
+ *
+ * \param[in] fidstr   string to be parsed
+ * \param[out] fid     Lustre File IDentifier
+ * \param[out] endptr  pointer to first invalid/unused character in @fidstr
+ *
+ * \retval     0 on success
+ * \retval     -errno on failure
+ */
+int llapi_fid_parse(const char *fidstr, struct lu_fid *fid, char **endptr)
+{
+       unsigned long long val;
+       bool bracket = false;
+       char *end = (char *)fidstr;
+       int rc = 0;
+
+       if (!fidstr || !fid) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       while (isspace(*fidstr))
+               fidstr++;
+       while (*fidstr == '[') {
+               bracket = true;
+               fidstr++;
+       }
+
+       /* Parse the FID fields individually with strtoull() instead of a
+        * single call to sscanf() so that the character after the FID can
+        * be returned in @endptr, in case the string has more to parse.
+        * If values are present, but too large for the field, continue
+        * parsing to consume the whole FID and return -ERANGE at the end.
+        */
+       errno = 0;
+       val = strtoull(fidstr, &end, 0);
+       if ((val == 0 && errno == EINVAL) || *end != ':') {
+               rc = -EINVAL;
+               goto out;
+       }
+       if (val >= UINT64_MAX)
+               rc = -ERANGE;
+       else
+               fid->f_seq = val;
+
+       fidstr = end + 1; /* skip first ':', checked above */
+       errno = 0;
+       val = strtoull(fidstr, &end, 0);
+       if ((val == 0 && errno == EINVAL) || *end != ':') {
+               rc = -EINVAL;
+               goto out;
+       }
+       if (val > UINT32_MAX)
+               rc = -ERANGE;
+       else
+               fid->f_oid = val;
+
+       fidstr = end + 1; /* skip second ':', checked above */
+       errno = 0;
+       val = strtoull(fidstr, &end, 0);
+       if (val == 0 && errno == EINVAL) {
+               rc = -EINVAL;
+               goto out;
+       }
+       if (val > UINT32_MAX)
+               rc = -ERANGE;
+       else
+               fid->f_ver = val;
+
+       if (bracket && *end == ']')
+               end++;
+out:
+       if (endptr)
+               *endptr = end;
+
+       errno = -rc;
+       return rc;
+}
+
+/* Print mdtname 'name' into 'buf' using 'format'.  Add -MDT0000 if needed.
+ * format must have %s%s, buf must be > 16
+ * Eg: if name = "lustre-MDT0000", "lustre", or "lustre-MDT0000_UUID"
+ *     then buf = "lustre-MDT0000"
+ */
+static int get_mdtname(char *name, char *format, char *buf)
+{
+       char suffix[] = "-MDT0000";
+       int len = strlen(name);
+
+       if (len > 5 && strncmp(name + len - 5, "_UUID", 5) == 0) {
+               name[len - 5] = '\0';
+               len -= 5;
+       }
+
+       if (len > 8) {
+               if ((len <= 16) && strncmp(name + len - 8, "-MDT", 4) == 0) {
+                       suffix[0] = '\0';
+               } else {
+                       /* Not enough room to add suffix */
+                       llapi_err_noerrno(LLAPI_MSG_ERROR,
+                                         "Invalid MDT name |%s|", name);
+                       return -EINVAL;
+               }
+       }
+
+       return sprintf(buf, format, name, suffix);
+}
+
+/** ioctl on filsystem root, with mdtindex sent as data
+ * \param mdtname path, fsname, or mdtname (lutre-MDT0004)
+ * \param mdtidxp pointer to integer within data to be filled in with the
+ *    mdt index (0 if no mdt is specified).  NULL won't be filled.
+ */
+int root_ioctl(const char *mdtname, int opc, void *data, int *mdtidxp,
+              int want_error)
+{
+       char fsname[20];
+       char *ptr;
+       int fd, rc;
+       long index;
+
+       /* Take path, fsname, or MDTname.  Assume MDT0000 in former cases.
+        * Open root and parse mdt index.
+        */
+       if (mdtname[0] == '/') {
+               index = 0;
+               rc = get_root_path(WANT_FD | want_error, NULL, &fd,
+                                  (char *)mdtname, -1);
+       } else {
+               if (get_mdtname((char *)mdtname, "%s%s", fsname) < 0)
+                       return -EINVAL;
+               ptr = fsname + strlen(fsname) - 8;
+               *ptr = '\0';
+               index = strtol(ptr + 4, NULL, 16);
+               rc = get_root_path(WANT_FD | want_error, fsname, &fd, NULL, -1);
+       }
+       if (rc < 0) {
+               if (want_error)
+                       llapi_err_noerrno(LLAPI_MSG_ERROR,
+                                         "Can't open %s: %d\n", mdtname, rc);
+               return rc;
+       }
+
+       if (mdtidxp)
+               *mdtidxp = index;
+
+       rc = ioctl(fd, opc, data);
+       if (rc == -1)
+               rc = -errno;
+       else
+               rc = 0;
+       close(fd);
+       return rc;
+}
+
+int llapi_fid2path(const char *device, const char *fidstr, char *path,
+                  int pathlen, long long *recno, int *linkno)
+{
+       struct lu_fid fid;
+       struct getinfo_fid2path *gf;
+       int rc;
+
+       if (!path || pathlen <= 1) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       rc = llapi_fid_parse(fidstr, &fid, NULL);
+       if (!rc && !fid_is_sane(&fid)) {
+               rc = -EINVAL;
+               goto out;
+       }
+       if (rc) {
+               llapi_err_noerrno(LLAPI_MSG_ERROR,
+                                 "bad FID format '%s', should be [seq:oid:ver] (e.g. "DFID")\n",
+                                 fidstr,
+                                 (unsigned long long)FID_SEQ_NORMAL, 2, 0);
+               goto out;
+       }
+
+       gf = malloc(sizeof(*gf) + pathlen);
+       if (gf == NULL) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       gf->gf_fid = fid;
+       if (recno)
+               gf->gf_recno = *recno;
+       if (linkno)
+               gf->gf_linkno = *linkno;
+       gf->gf_pathlen = pathlen;
+
+       /* Take path or fsname */
+       rc = root_ioctl(device, OBD_IOC_FID2PATH, gf, NULL, 0);
+       if (rc)
+               goto out_free;
+
+       rc = copy_strip_dne_path(gf->gf_u.gf_path, path, pathlen);
+
+       if (recno)
+               *recno = gf->gf_recno;
+       if (linkno)
+               *linkno = gf->gf_linkno;
+
+out_free:
+       free(gf);
+out:
+       errno = -rc;
+       return rc;
+}
+
+static int fid_from_lma(const char *path, int fd, struct lu_fid *fid)
+{
+       char buf[512];
+       struct lustre_mdt_attrs *lma;
+       int rc = -1;
+
+       if (fd >= 0)
+               rc = fgetxattr(fd, XATTR_NAME_LMA, buf, sizeof(buf));
+       else if (path)
+               rc = lgetxattr(path, XATTR_NAME_LMA, buf, sizeof(buf));
+       else
+               errno = EINVAL;
+       if (rc < 0)
+               return -errno;
+
+       lma = (struct lustre_mdt_attrs *)buf;
+       fid_le_to_cpu(fid, &lma->lma_self_fid);
+
+       return 0;
+}
+
+int llapi_get_mdt_index_by_fid(int fd, const struct lu_fid *fid,
+                              int *mdt_index)
+{
+       int rc;
+
+       rc = ioctl(fd, LL_IOC_FID2MDTIDX, fid);
+       if (rc < 0)
+               return -errno;
+
+       if (mdt_index)
+               *mdt_index = rc;
+
+       return rc;
+}
+
+int llapi_fd2fid(int fd, struct lu_fid *fid)
+{
+       int rc;
+
+       memset(fid, 0, sizeof(*fid));
+
+       rc = ioctl(fd, LL_IOC_PATH2FID, fid) < 0 ? -errno : 0;
+       /* Allow extracting the FID from an ldiskfs-mounted filesystem */
+       if (rc < 0) {
+               if (errno == EINVAL || errno == ENOTTY)
+                       rc = fid_from_lma(NULL, fd, fid);
+               else
+                       rc = -errno;
+       }
+
+       return rc;
+}
+
+int llapi_path2fid(const char *path, struct lu_fid *fid)
+{
+       int fd, rc;
+
+       fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
+       if (fd >= 0) {
+               rc = llapi_fd2fid(fd, fid);
+               close(fd);
+       } else {
+               memset(fid, 0, sizeof(*fid));
+               rc = -errno;
+       }
+
+       if (rc == -ELOOP || rc == -ENXIO || rc == -EINVAL || rc == -ENOTTY)
+               rc = fid_from_lma(path, -1, fid);
+
+       return rc;
+}
+
+int llapi_fd2parent(int fd, unsigned int linkno, struct lu_fid *parent_fid,
+                   char *name, size_t name_size)
+{
+       struct getparent *gp;
+       int rc;
+
+       if (name && name_size <= 1) {
+               errno = EOVERFLOW;
+               return -errno;
+       }
+
+       gp = malloc(sizeof(*gp) + name_size);
+       if (gp == NULL) {
+               errno = ENOMEM;
+               return -errno;
+       }
+
+       gp->gp_linkno = linkno;
+       gp->gp_name_size = name_size;
+
+       rc = ioctl(fd, LL_IOC_GETPARENT, gp);
+       if (rc < 0) {
+               rc = -errno;
+               goto err_free;
+       }
+
+       if (parent_fid)
+               *parent_fid = gp->gp_fid;
+
+       if (name)
+               rc = copy_strip_dne_path(gp->gp_name, name, name_size);
+
+err_free:
+       free(gp);
+       return rc;
+}
+
+int llapi_path2parent(const char *path, unsigned int linkno,
+                     struct lu_fid *parent_fid, char *name, size_t name_size)
+{
+       int fd;
+       int rc;
+
+       fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
+       if (fd < 0)
+               return -errno;
+
+       rc = llapi_fd2parent(fd, linkno, parent_fid, name, name_size);
+       close(fd);
+
+       return rc;
+}
+
+/**
+ * Attempt to open a file with Lustre file identifier \a fid
+ * and return an open file descriptor.
+ *
+ * \param[in] lustre_dir       path within Lustre filesystem containing \a fid
+ * \param[in] fid              Lustre file identifier of file to open
+ * \param[in] flags            open() flags
+ *
+ * \retval                     non-negative file descriptor on successful open
+ * \retval                     negative errno if an error occurred
+ */
+int llapi_open_by_fid(const char *lustre_dir, const struct lu_fid *fid,
+                     int flags)
+{
+       char mntdir[PATH_MAX];
+       char path[PATH_MAX + 64];
+       int rc;
+
+       rc = llapi_search_mounts(lustre_dir, 0, mntdir, NULL);
+       if (rc)
+               return rc;
+
+       snprintf(path, sizeof(path), "%s/.lustre/fid/"DFID, mntdir, PFID(fid));
+       rc = open(path, flags);
+       if (rc < 0)
+               rc = -errno;
+
+       return rc;
+}
index 15ff456..1e34654 100644 (file)
@@ -5268,7 +5268,7 @@ int jt_get_obj_version(int argc, char **argv)
        }
 
        argc -= optind;
-       argv += optind;
+       fidstr = *(argv + optind);
 
        if (!(id != ULLONG_MAX && group != ULLONG_MAX && argc == 0) &&
            !(id == ULLONG_MAX && group == ULLONG_MAX && argc == 1))
@@ -5277,18 +5277,20 @@ int jt_get_obj_version(int argc, char **argv)
        memset(&data, 0, sizeof data);
        data.ioc_dev = cur_device;
        if (argc == 1) {
-               fidstr = *argv;
-               while (*fidstr == '[')
-                       fidstr++;
-               sscanf(fidstr, SFID, RFID(&fid));
+               rc = llapi_fid_parse(fidstr, &fid, NULL);
+               if (rc) {
+                       fprintf(stderr, "%s: error parsing FID '%s': %s\n",
+                               jt_cmdname(argv[0]), fidstr, strerror(-rc));
+                       return rc;
+               }
 
-               data.ioc_inlbuf1 = (char *) &fid;
-               data.ioc_inllen1 = sizeof fid;
+               data.ioc_inlbuf1 = (char *)&fid;
+               data.ioc_inllen1 = sizeof(fid);
        } else {
-               data.ioc_inlbuf3 = (char *) &id;
-               data.ioc_inllen3 = sizeof id;
-               data.ioc_inlbuf4 = (char *) &group;
-               data.ioc_inllen4 = sizeof group;
+               data.ioc_inlbuf3 = (char *)&id;
+               data.ioc_inllen3 = sizeof(id);
+               data.ioc_inlbuf4 = (char *)&group;
+               data.ioc_inllen4 = sizeof(group);
        }
        data.ioc_inlbuf2 = (char *) &version;
        data.ioc_inllen2 = sizeof version;