Whamcloud - gitweb
LU-16518 utils: fix unused function errors
[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 and struct file_handle */
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 #include <sched.h>
47
48 #include <libcfs/util/ioctl.h>
49 #include <libcfs/util/hash.h>
50 #include <lustre/lustreapi.h>
51 #include <linux/lustre/lustre_fid.h>
52 #include "lustreapi_internal.h"
53
54 /* strip instances of // (DNE striped directory) when copying to reply buffer */
55 static int copy_strip_dne_path(const char *src, char *tgt, size_t tgtlen)
56 {
57         const char *a;
58         char *b;
59
60         for (a = src, b = tgt; *a != '\0' && b - tgt < tgtlen; a++) {
61                 if (*a == '/' && *(a + 1) == '/')
62                         continue;
63                 *b = *a;
64                 b++;
65         }
66         if (b - tgt >= tgtlen) {
67                 errno = ERANGE;
68                 return -errno;
69         }
70
71         *b = '\0';
72
73         if (tgt[0] == '\0') { /* ROOT path */
74                 tgt[0] = '/';
75                 tgt[1] = '\0';
76         }
77
78         return 0;
79 }
80
81 /**
82  * parse a FID from a string into a binary lu_fid
83  *
84  * Only the format of the FID is checked, not whether the numeric value
85  * contains a valid FID sequence or object ID or version. Optional leading
86  * whitespace and '[' from the standard FID format are skipped.
87  *
88  * \param[in] fidstr    string to be parsed
89  * \param[out] fid      Lustre File IDentifier
90  * \param[out] endptr   pointer to first invalid/unused character in @fidstr
91  *
92  * \retval      0 on success
93  * \retval      -errno on failure
94  */
95 int llapi_fid_parse(const char *fidstr, struct lu_fid *fid, char **endptr)
96 {
97         unsigned long long val;
98         bool bracket = false;
99         char *end = (char *)fidstr;
100         int rc = 0;
101
102         if (!fidstr || !fid) {
103                 rc = -EINVAL;
104                 goto out;
105         }
106
107         while (isspace(*fidstr))
108                 fidstr++;
109         while (*fidstr == '[') {
110                 bracket = true;
111                 fidstr++;
112         }
113
114         /* Parse the FID fields individually with strtoull() instead of a
115          * single call to sscanf() so that the character after the FID can
116          * be returned in @endptr, in case the string has more to parse.
117          * If values are present, but too large for the field, continue
118          * parsing to consume the whole FID and return -ERANGE at the end.
119          */
120         errno = 0;
121         val = strtoull(fidstr, &end, 0);
122         if ((val == 0 && errno == EINVAL) || *end != ':') {
123                 rc = -EINVAL;
124                 goto out;
125         }
126         if (val >= UINT64_MAX)
127                 rc = -ERANGE;
128         else
129                 fid->f_seq = val;
130
131         fidstr = end + 1; /* skip first ':', checked above */
132         errno = 0;
133         val = strtoull(fidstr, &end, 0);
134         if ((val == 0 && errno == EINVAL) || *end != ':') {
135                 rc = -EINVAL;
136                 goto out;
137         }
138         if (val > UINT32_MAX)
139                 rc = -ERANGE;
140         else
141                 fid->f_oid = val;
142
143         fidstr = end + 1; /* skip second ':', checked above */
144         errno = 0;
145         val = strtoull(fidstr, &end, 0);
146         if (val == 0 && errno == EINVAL) {
147                 rc = -EINVAL;
148                 goto out;
149         }
150         if (val > UINT32_MAX)
151                 rc = -ERANGE;
152         else
153                 fid->f_ver = val;
154
155         if (bracket && *end == ']')
156                 end++;
157 out:
158         if (endptr)
159                 *endptr = end;
160
161         errno = -rc;
162         return rc;
163 }
164
165 static inline char *get_gf_path(struct getinfo_fid2path *gf)
166 {
167 #ifndef HAVE_FID2PATH_ANON_UNIONS
168         return gf->gf_u.gf_path;
169 #else
170         return gf->gf_path;
171 #endif
172 }
173
174 int llapi_fid2path_at(int mnt_fd, const struct lu_fid *fid,
175                       char *path_buf, int path_buf_size,
176                       long long *recno, int *linkno)
177 {
178         struct getinfo_fid2path *gf = NULL;
179         int rc;
180
181         gf = calloc(1, sizeof(*gf) + path_buf_size);
182         if (gf == NULL) {
183                 rc = -ENOMEM;
184                 goto out;
185         }
186
187         gf->gf_fid = *fid;
188         if (recno != NULL)
189                 gf->gf_recno = *recno;
190
191         if (linkno != NULL)
192                 gf->gf_linkno = *linkno;
193
194         gf->gf_pathlen = path_buf_size;
195
196         rc = ioctl(mnt_fd, OBD_IOC_FID2PATH, gf);
197         if (rc) {
198                 rc = -errno;
199                 goto out;
200         }
201
202         rc = copy_strip_dne_path(get_gf_path(gf), path_buf, path_buf_size);
203
204         if (recno != NULL)
205                 *recno = gf->gf_recno;
206
207         if (linkno != NULL)
208                 *linkno = gf->gf_linkno;
209 out:
210         free(gf);
211
212         return rc;
213 }
214
215 int llapi_fid2path(const char *path_or_device, const char *fidstr, char *path,
216                    int pathlen, long long *recno, int *linkno)
217 {
218         struct lu_fid fid;
219         int mnt_fd = -1;
220         int rc;
221
222         if (path_or_device == NULL || *path_or_device == '\0') {
223                 rc = -EINVAL;
224                 goto out;
225         }
226
227         rc = llapi_fid_parse(fidstr, &fid, NULL);
228         if (rc < 0) {
229                 llapi_err_noerrno(LLAPI_MSG_ERROR,
230                                   "bad FID format '%s', should be [seq:oid:ver] (e.g. "DFID")\n",
231                                   fidstr,
232                                   (unsigned long long)FID_SEQ_NORMAL, 2, 0);
233                 goto out;
234         }
235
236         if (path_or_device[0] == '/')
237                 rc = get_root_path(WANT_FD, NULL, &mnt_fd,
238                                    (char *)path_or_device, -1, NULL, NULL);
239         else
240                 rc = get_root_path(WANT_FD, (char *)path_or_device,
241                                    &mnt_fd, NULL, -1, NULL, NULL);
242
243         if (rc < 0)
244                 goto out;
245
246         /* mnt_fd is cached internally, no need to close it */
247         rc = llapi_fid2path_at(mnt_fd, &fid, path, pathlen, recno, linkno);
248
249 out:
250         return rc;
251 }
252
253 int llapi_get_mdt_index_by_fid(int fd, const struct lu_fid *fid,
254                                int *mdt_index)
255 {
256         int rc;
257
258         rc = ioctl(fd, LL_IOC_FID2MDTIDX, fid);
259         if (rc < 0)
260                 return -errno;
261
262         if (mdt_index)
263                 *mdt_index = rc;
264
265         return rc;
266 }
267
268 static int fid_from_lma(const char *path, int fd, struct lu_fid *fid)
269 {
270 #ifdef HAVE_SERVER_SUPPORT
271         struct lustre_mdt_attrs *lma;
272         char buf[512];
273         int rc = -1;
274
275         if (path == NULL)
276                 rc = fgetxattr(fd, XATTR_NAME_LMA, buf, sizeof(buf));
277         else
278                 rc = lgetxattr(path, XATTR_NAME_LMA, buf, sizeof(buf));
279         if (rc < 0)
280                 return -errno;
281
282         lma = (struct lustre_mdt_attrs *)buf;
283         memcpy(fid, &lma->lma_self_fid, sizeof(lma->lma_self_fid));
284         return 0;
285 #else
286         return -ENOTSUP;
287 #endif
288 }
289
290 int llapi_fd2fid(int fd, struct lu_fid *fid)
291 {
292         const struct lustre_file_handle *data;
293         struct file_handle *handle;
294         char buffer[sizeof(*handle) + MAX_HANDLE_SZ];
295         int mount_id;
296
297         memset(fid, 0, sizeof(*fid));
298
299         /* A lustre file handle should always fit in a 128 bytes long buffer
300          * (which is the value of MAX_HANDLE_SZ at the time this is written)
301          */
302         handle = (struct file_handle *)buffer;
303         handle->handle_bytes = MAX_HANDLE_SZ;
304
305         if (name_to_handle_at(fd, "", handle, &mount_id, AT_EMPTY_PATH)) {
306                 if (errno == EOVERFLOW)
307                         /* A Lustre file_handle would have fit */
308                         return -ENOTTY;
309                 return -errno;
310         }
311
312         if (handle->handle_type != FILEID_LUSTRE)
313                 /* Might be a locally mounted Lustre target */
314                 return fid_from_lma(NULL, fd, fid);
315         if (handle->handle_bytes < sizeof(*fid))
316                 /* Unexpected error try and recover */
317                 return fid_from_lma(NULL, fd, fid);
318
319         /* Parse the FID out of the handle */
320         data = (const struct lustre_file_handle *)handle->f_handle;
321         memcpy(fid, &data->lfh_child, sizeof(data->lfh_child));
322
323         return 0;
324 }
325
326 int llapi_path2fid(const char *path, struct lu_fid *fid)
327 {
328         int fd, rc;
329
330         fd = open(path, O_RDONLY | O_PATH | O_CLOEXEC | O_NOFOLLOW);
331         if (fd < 0)
332                 return -errno;
333
334         rc = llapi_fd2fid(fd, fid);
335         close(fd);
336
337         if (rc == -EBADF)
338                 /* Might be a locally mounted Lustre target
339                  *
340                  * Cannot use `fd' as fgetxattr() does not work on file
341                  * descriptor opened with O_PATH
342                  */
343                 rc = fid_from_lma(path, -1, fid);
344
345         return rc;
346 }
347
348 int llapi_fd2parent(int fd, unsigned int linkno, struct lu_fid *parent_fid,
349                     char *name, size_t name_size)
350 {
351         struct getparent *gp;
352         int rc;
353
354         if (name && name_size <= 1) {
355                 errno = EOVERFLOW;
356                 return -errno;
357         }
358
359         gp = malloc(sizeof(*gp) + name_size);
360         if (gp == NULL) {
361                 errno = ENOMEM;
362                 return -errno;
363         }
364
365         gp->gp_linkno = linkno;
366         gp->gp_name_size = name_size;
367
368         rc = ioctl(fd, LL_IOC_GETPARENT, gp);
369         if (rc < 0) {
370                 rc = -errno;
371                 goto err_free;
372         }
373
374         if (parent_fid)
375                 *parent_fid = gp->gp_fid;
376
377         if (name)
378                 rc = copy_strip_dne_path(gp->gp_name, name, name_size);
379
380 err_free:
381         free(gp);
382         return rc;
383 }
384
385 int llapi_path2parent(const char *path, unsigned int linkno,
386                       struct lu_fid *parent_fid, char *name, size_t name_size)
387 {
388         int fd;
389         int rc;
390
391         fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
392         if (fd < 0)
393                 return -errno;
394
395         rc = llapi_fd2parent(fd, linkno, parent_fid, name, name_size);
396         close(fd);
397
398         return rc;
399 }
400
401 /**
402  * Convert a struct lu_fid into a struct file_handle
403  *
404  * \param[out] _handle  a newly allocated struct file_handle on success
405  * \param[in]  fid      a Lustre File IDentifier
406  *
407  * \retval              0 on success
408  * \retval              negative errno if an error occured
409  *
410  * On success, the caller is responsible for freeing \p handle.
411  */
412 int llapi_fid_to_handle(struct file_handle **_handle, const struct lu_fid *fid)
413 {
414         struct lustre_file_handle *lfh;
415         struct file_handle *handle;
416
417         if (!_handle || !fid)
418                 return -EINVAL;
419
420         handle = calloc(1, sizeof(*handle) + sizeof(*lfh));
421         if (handle == NULL)
422                 return -errno;
423
424         handle->handle_bytes = sizeof(*lfh);
425         handle->handle_type = FILEID_LUSTRE;
426         lfh = (struct lustre_file_handle *)handle->f_handle;
427         /* Only lfh->lfh_child needs to be set */
428         lfh->lfh_child = *fid;
429
430         *_handle = handle;
431         return 0;
432 }
433
434 /**
435  * Attempt to open a file with a Lustre File IDentifier
436  *
437  * \param[in] lustre_fd         an open file descriptor for an object in lustre
438  * \param[in] fid               a Lustre File IDentifier of the file to open
439  * \param[in] flags             open(2) flags
440  *
441  * \retval                      non-negative file descriptor on success
442  * \retval                      negative errno if an error occured
443  */
444 int llapi_open_by_fid_at(int lustre_fd, const struct lu_fid *fid, int flags)
445 {
446         struct file_handle *handle;
447         int fd;
448         int rc;
449
450         rc = llapi_fid_to_handle(&handle, fid);
451         if (rc < 0)
452                 return rc;
453
454         /* Sadly open_by_handle_at() only works for root, but this is also the
455          * case for the original approach of opening $MOUNT/.lustre/FID.
456          */
457         fd = open_by_handle_at(lustre_fd, handle, flags);
458         rc = -errno;
459         free(handle);
460
461         return fd < 0 ? rc : fd;
462 }
463
464 /**
465  * Attempt to open a file with Lustre file identifier \a fid
466  * and return an open file descriptor.
467  *
468  * \param[in] lustre_dir        path within Lustre filesystem containing \a fid
469  * \param[in] fid               Lustre file identifier of file to open
470  * \param[in] flags             open() flags
471  *
472  * \retval                      non-negative file descriptor on successful open
473  * \retval                      negative errno if an error occurred
474  */
475 int llapi_open_by_fid(const char *lustre_dir, const struct lu_fid *fid,
476                       int flags)
477 {
478         int mnt_fd, rc;
479
480         /* this will return a cached FD if available, so only one open needed.
481          * WANT_FD doesn't modify lustre_dir so casting away "const" is OK */
482         rc = get_root_path(WANT_FD, NULL, &mnt_fd, (char *)lustre_dir, 0, NULL,
483                            NULL);
484         if (rc)
485                 goto out;
486
487         /* "mnt_fd" is cached internally for reuse, no need to close it */
488         rc = llapi_open_by_fid_at(mnt_fd, fid, flags);
489 out:
490         return rc;
491 }
492
493 unsigned long llapi_fid_hash(const struct lu_fid *f, unsigned int shift)
494 {
495         return hash_long(fid_flatten_long(f), shift);
496 }