Whamcloud - gitweb
LU-13903 utils: separate out server code for wiretest
[fs/lustre-release.git] / lustre / utils / liblustreapi_fid.c
1 /*
2  * LGPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * All rights reserved. This program and the accompanying materials
7  * are made available under the terms of the GNU Lesser General Public License
8  * (LGPL) version 2.1 or (at your discretion) any later version.
9  * (LGPL) version 2.1 accompanies this distribution, and is available at
10  * http://www.gnu.org/licenses/lgpl-2.1.html
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * LGPL HEADER END
18  */
19 /*
20  * lustre/utils/liblustreapi_fid.c
21  *
22  * lustreapi library for FID mapping calls for determining the pathname
23  * of Lustre files from the File IDentifier.
24  *
25  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
26  * Use is subject to license terms.
27  *
28  * Copyright (c) 2011, 2017, Intel Corporation.
29  *
30  * Copyright (c) 2018, 2019, Data Direct Networks
31  */
32
33 /* for O_DIRECTORY */
34 #ifndef _GNU_SOURCE
35 #define _GNU_SOURCE
36 #endif
37
38 #include <ctype.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <sys/ioctl.h>
44 #include <sys/xattr.h>
45 #include <unistd.h>
46
47 #include <libcfs/util/ioctl.h>
48 #include <lustre/lustreapi.h>
49 #include <linux/lustre/lustre_fid.h>
50 #include "lustreapi_internal.h"
51
52 /* strip instances of // (DNE striped directory) when copying to reply buffer */
53 static int copy_strip_dne_path(const char *src, char *tgt, size_t tgtlen)
54 {
55         const char *a;
56         char *b;
57
58         for (a = src, b = tgt; *a != '\0' && b - tgt < tgtlen; a++) {
59                 if (*a == '/' && *(a + 1) == '/')
60                         continue;
61                 *b = *a;
62                 b++;
63         }
64         if (b - tgt >= tgtlen) {
65                 errno = ERANGE;
66                 return -errno;
67         }
68
69         *b = '\0';
70
71         if (tgt[0] == '\0') { /* ROOT path */
72                 tgt[0] = '/';
73                 tgt[1] = '\0';
74         }
75
76         return 0;
77 }
78
79 /**
80  * parse a FID from a string into a binary lu_fid
81  *
82  * Only the format of the FID is checked, not whether the numeric value
83  * contains a valid FID sequence or object ID or version. Optional leading
84  * whitespace and '[' from the standard FID format are skipped.
85  *
86  * \param[in] fidstr    string to be parsed
87  * \param[out] fid      Lustre File IDentifier
88  * \param[out] endptr   pointer to first invalid/unused character in @fidstr
89  *
90  * \retval      0 on success
91  * \retval      -errno on failure
92  */
93 int llapi_fid_parse(const char *fidstr, struct lu_fid *fid, char **endptr)
94 {
95         unsigned long long val;
96         bool bracket = false;
97         char *end = (char *)fidstr;
98         int rc = 0;
99
100         if (!fidstr || !fid) {
101                 rc = -EINVAL;
102                 goto out;
103         }
104
105         while (isspace(*fidstr))
106                 fidstr++;
107         while (*fidstr == '[') {
108                 bracket = true;
109                 fidstr++;
110         }
111
112         /* Parse the FID fields individually with strtoull() instead of a
113          * single call to sscanf() so that the character after the FID can
114          * be returned in @endptr, in case the string has more to parse.
115          * If values are present, but too large for the field, continue
116          * parsing to consume the whole FID and return -ERANGE at the end.
117          */
118         errno = 0;
119         val = strtoull(fidstr, &end, 0);
120         if ((val == 0 && errno == EINVAL) || *end != ':') {
121                 rc = -EINVAL;
122                 goto out;
123         }
124         if (val >= UINT64_MAX)
125                 rc = -ERANGE;
126         else
127                 fid->f_seq = val;
128
129         fidstr = end + 1; /* skip first ':', checked above */
130         errno = 0;
131         val = strtoull(fidstr, &end, 0);
132         if ((val == 0 && errno == EINVAL) || *end != ':') {
133                 rc = -EINVAL;
134                 goto out;
135         }
136         if (val > UINT32_MAX)
137                 rc = -ERANGE;
138         else
139                 fid->f_oid = val;
140
141         fidstr = end + 1; /* skip second ':', checked above */
142         errno = 0;
143         val = strtoull(fidstr, &end, 0);
144         if (val == 0 && errno == EINVAL) {
145                 rc = -EINVAL;
146                 goto out;
147         }
148         if (val > UINT32_MAX)
149                 rc = -ERANGE;
150         else
151                 fid->f_ver = val;
152
153         if (bracket && *end == ']')
154                 end++;
155 out:
156         if (endptr)
157                 *endptr = end;
158
159         errno = -rc;
160         return rc;
161 }
162
163 static inline char *get_gf_path(struct getinfo_fid2path *gf)
164 {
165 #ifndef HAVE_FID2PATH_ANON_UNIONS
166         return gf->gf_u.gf_path;
167 #else
168         return gf->gf_path;
169 #endif
170 }
171
172 int llapi_fid2path_at(int mnt_fd, const struct lu_fid *fid,
173                       char *path_buf, int path_buf_size,
174                       long long *recno, int *linkno)
175 {
176         struct getinfo_fid2path *gf = NULL;
177         int rc;
178
179         gf = calloc(1, sizeof(*gf) + path_buf_size);
180         if (gf == NULL) {
181                 rc = -ENOMEM;
182                 goto out;
183         }
184
185         gf->gf_fid = *fid;
186         if (recno != NULL)
187                 gf->gf_recno = *recno;
188
189         if (linkno != NULL)
190                 gf->gf_linkno = *linkno;
191
192         gf->gf_pathlen = path_buf_size;
193
194         rc = ioctl(mnt_fd, OBD_IOC_FID2PATH, gf);
195         if (rc) {
196                 rc = -errno;
197                 goto out;
198         }
199
200         rc = copy_strip_dne_path(get_gf_path(gf), path_buf, path_buf_size);
201
202         if (recno != NULL)
203                 *recno = gf->gf_recno;
204
205         if (linkno != NULL)
206                 *linkno = gf->gf_linkno;
207 out:
208         free(gf);
209
210         return rc;
211 }
212
213 int llapi_fid2path(const char *path_or_device, const char *fidstr, char *path,
214                    int pathlen, long long *recno, int *linkno)
215 {
216         struct lu_fid fid;
217         int mnt_fd = -1;
218         int rc;
219
220         if (path_or_device == NULL || *path_or_device == '\0') {
221                 rc = -EINVAL;
222                 goto out;
223         }
224
225         if (*path_or_device == '/')
226                 rc = get_root_path(WANT_FD, NULL, &mnt_fd,
227                                    (char *)path_or_device, -1);
228         else
229                 rc = get_root_path(WANT_FD, (char *)path_or_device,
230                                    &mnt_fd, NULL, -1);
231
232         if (rc < 0)
233                 goto out;
234
235         rc = llapi_fid_parse(fidstr, &fid, NULL);
236         if (rc < 0) {
237                 llapi_err_noerrno(LLAPI_MSG_ERROR,
238                                   "bad FID format '%s', should be [seq:oid:ver] (e.g. "DFID")\n",
239                                   fidstr,
240                                   (unsigned long long)FID_SEQ_NORMAL, 2, 0);
241                 goto out;
242         }
243
244         rc = llapi_fid2path_at(mnt_fd, &fid, path, pathlen, recno, linkno);
245 out:
246         if (!(mnt_fd < 0))
247                 close(mnt_fd);
248
249         return rc;
250 }
251
252 int llapi_get_mdt_index_by_fid(int fd, const struct lu_fid *fid,
253                                int *mdt_index)
254 {
255         int rc;
256
257         rc = ioctl(fd, LL_IOC_FID2MDTIDX, fid);
258         if (rc < 0)
259                 return -errno;
260
261         if (mdt_index)
262                 *mdt_index = rc;
263
264         return rc;
265 }
266
267 static int fid_from_lma(const char *path, int fd, struct lu_fid *fid)
268 {
269 #ifdef HAVE_SERVER_SUPPORT
270         struct lustre_mdt_attrs *lma;
271         char buf[512];
272         int rc = -1;
273
274         if (path == NULL)
275                 rc = fgetxattr(fd, XATTR_NAME_LMA, buf, sizeof(buf));
276         else
277                 rc = lgetxattr(path, XATTR_NAME_LMA, buf, sizeof(buf));
278         if (rc < 0)
279                 return -errno;
280
281         lma = (struct lustre_mdt_attrs *)buf;
282         memcpy(fid, &lma->lma_self_fid, sizeof(lma->lma_self_fid));
283         return 0;
284 #else
285         return -ENOTSUP;
286 #endif
287 }
288
289 int llapi_fd2fid(int fd, struct lu_fid *fid)
290 {
291         const struct lustre_file_handle *data;
292         struct file_handle *handle;
293         char buffer[sizeof(*handle) + MAX_HANDLE_SZ];
294         int mount_id;
295
296         memset(fid, 0, sizeof(*fid));
297
298         /* A lustre file handle should always fit in a 128 bytes long buffer
299          * (which is the value of MAX_HANDLE_SZ at the time this is written)
300          */
301         handle = (struct file_handle *)buffer;
302         handle->handle_bytes = MAX_HANDLE_SZ;
303
304         if (name_to_handle_at(fd, "", handle, &mount_id, AT_EMPTY_PATH)) {
305                 if (errno == EOVERFLOW)
306                         /* A Lustre file_handle would have fit */
307                         return -ENOTTY;
308                 return -errno;
309         }
310
311         if (handle->handle_type != FILEID_LUSTRE)
312                 /* Might be a locally mounted Lustre target */
313                 return fid_from_lma(NULL, fd, fid);
314         if (handle->handle_bytes < sizeof(*fid))
315                 /* Unexpected error try and recover */
316                 return fid_from_lma(NULL, fd, fid);
317
318         /* Parse the FID out of the handle */
319         data = (const struct lustre_file_handle *)handle->f_handle;
320         memcpy(fid, &data->lfh_child, sizeof(data->lfh_child));
321
322         return 0;
323 }
324
325 int llapi_path2fid(const char *path, struct lu_fid *fid)
326 {
327         int fd, rc;
328
329         fd = open(path, O_RDONLY | O_PATH | O_CLOEXEC | O_NOFOLLOW);
330         if (fd < 0)
331                 return -errno;
332
333         rc = llapi_fd2fid(fd, fid);
334         close(fd);
335
336         if (rc == -EBADF)
337                 /* Might be a locally mounted Lustre target
338                  *
339                  * Cannot use `fd' as fgetxattr() does not work on file
340                  * descriptor opened with O_PATH
341                  */
342                 rc = fid_from_lma(path, -1, fid);
343
344         return rc;
345 }
346
347 int llapi_fd2parent(int fd, unsigned int linkno, struct lu_fid *parent_fid,
348                     char *name, size_t name_size)
349 {
350         struct getparent *gp;
351         int rc;
352
353         if (name && name_size <= 1) {
354                 errno = EOVERFLOW;
355                 return -errno;
356         }
357
358         gp = malloc(sizeof(*gp) + name_size);
359         if (gp == NULL) {
360                 errno = ENOMEM;
361                 return -errno;
362         }
363
364         gp->gp_linkno = linkno;
365         gp->gp_name_size = name_size;
366
367         rc = ioctl(fd, LL_IOC_GETPARENT, gp);
368         if (rc < 0) {
369                 rc = -errno;
370                 goto err_free;
371         }
372
373         if (parent_fid)
374                 *parent_fid = gp->gp_fid;
375
376         if (name)
377                 rc = copy_strip_dne_path(gp->gp_name, name, name_size);
378
379 err_free:
380         free(gp);
381         return rc;
382 }
383
384 int llapi_path2parent(const char *path, unsigned int linkno,
385                       struct lu_fid *parent_fid, char *name, size_t name_size)
386 {
387         int fd;
388         int rc;
389
390         fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
391         if (fd < 0)
392                 return -errno;
393
394         rc = llapi_fd2parent(fd, linkno, parent_fid, name, name_size);
395         close(fd);
396
397         return rc;
398 }
399
400 /**
401  * Attempt to open a file with Lustre file identifier \a fid
402  * and return an open file descriptor.
403  *
404  * \param[in] lustre_dir        path within Lustre filesystem containing \a fid
405  * \param[in] fid               Lustre file identifier of file to open
406  * \param[in] flags             open() flags
407  *
408  * \retval                      non-negative file descriptor on successful open
409  * \retval                      negative errno if an error occurred
410  */
411 int llapi_open_by_fid(const char *lustre_dir, const struct lu_fid *fid,
412                       int flags)
413 {
414         char mntdir[PATH_MAX];
415         char path[PATH_MAX + 64];
416         int rc;
417
418         rc = llapi_search_mounts(lustre_dir, 0, mntdir, NULL);
419         if (rc)
420                 return rc;
421
422         snprintf(path, sizeof(path), "%s/.lustre/fid/"DFID, mntdir, PFID(fid));
423         rc = open(path, flags);
424         if (rc < 0)
425                 rc = -errno;
426
427         return rc;
428 }