4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * (C) Copyright (c) 2015, Cray Inc, all rights reserved.
8 * Copyright (c) 2016, 2017, Intel Corporation.
10 * All rights reserved. This program and the accompanying materials
11 * are made available under the terms of the GNU Lesser General Public License
12 * LGPL version 2.1 or (at your discretion) any later version.
13 * LGPL version 2.1 accompanies this distribution, and is available at
14 * http://www.gnu.org/licenses/lgpl-2.1.html
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
24 * lustre/utils/liblustreapi_util.c
26 * Misc LGPL-licenced utility functions for liblustreapi.
28 * Author: Frank Zago <fzago@cray.com>
37 #include <sys/ioctl.h>
41 #include <sys/types.h>
43 #include <sys/syscall.h>
44 #include <libgen.h> /* for dirname() */
45 #include <lustre/lustreapi.h>
46 #include <linux/lustre/lustre_ver.h> /* only until LUSTRE_VERSION_CODE is gone */
47 #include "lustreapi_internal.h"
50 * Indicate whether the liblustreapi_init() constructor below has run or not.
52 * This can be used by external programs to ensure that the initialization
53 * mechanism has actually worked.
55 bool liblustreapi_initialized;
58 * Initialize the library once at startup.
60 * Initializes the random number generator (random()). Get
61 * data from different places in case one of them fails. This
62 * is enough to get reasonably random numbers, but is not
63 * strong enough to be used for cryptography.
65 static __attribute__ ((constructor)) void liblustreapi_init(void)
71 seed = syscall(SYS_gettid);
73 if (gettimeofday(&tv, NULL) == 0) {
78 fd = open("/dev/urandom", O_RDONLY | O_NOFOLLOW);
83 ret = read(fd, &rnumber, sizeof(rnumber));
84 seed ^= rnumber ^ ret;
89 liblustreapi_initialized = true;
93 * Return the release version for the Lustre modules, e.g. 2.6.92.
95 * The "version" file in /proc currently returns only the line:
98 * but in the past it also returned more lines that should be ignored:
99 * kernel: patchless_client
100 * build: v2_6_92_0-gadb3ee4-2.6.32-431.29.2.el6_lustre.g36cd22b.x86_64
102 * \param version[in,out] buffer to store build version string
103 * \param version_size[in] size of \a version
105 * \retval 0 on success
106 * \retval -1 on failure, errno set
108 int llapi_get_version_string(char *version, unsigned int version_size)
114 if (version == NULL || version_size == 0) {
119 rc = get_lustre_param_value(NULL, NULL, FILTER_BY_NONE, "version",
120 buffer, sizeof(buffer));
126 ptr = strstr(buffer, "lustre:");
128 ptr += strlen("lustre:");
129 while (*ptr == ' ' || *ptr == '\t')
134 llapi_chomp_string(ptr);
136 if (ptr[0] == '\0') {
141 if (snprintf(version, version_size, "%s", ptr) >= version_size) {
148 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 4, 53, 0)
150 * Return the build version of the Lustre code.
152 * The **version argument is pointless, so llapi_get_version_string() is
153 * better to use in the future, but give users a few versions to fix * it.
155 * \param buffer[in] temporary buffer to hold version string
156 * \param buffer_size[in] length of the \a buffer
157 * \param version[out] pointer to the start of build version string
159 * \retval 0 on success
160 * \retval -ve errno on failure
162 int llapi_get_version(char *buffer, int buffer_size, char **version)
169 "%s deprecated, use llapi_get_version_string()\n",
174 rc = llapi_get_version_string(buffer, buffer_size);
175 /* keep old return style for this legacy function */
183 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 4, 53, 0) */
186 * fsname must be specified
187 * if poolname is NULL, search tgtname in fsname
188 * if poolname is not NULL:
189 * if poolname not found returns errno < 0
190 * if tgtname is NULL, returns 1 if pool is not empty and 0 if pool empty
191 * if tgtname is not NULL, returns 1 if target is in pool and 0 if not
193 int llapi_search_tgt(const char *fsname, const char *poolname,
194 const char *tgtname, bool is_mdt)
196 char buffer[PATH_MAX];
202 if (fsname && fsname[0] == '\0')
209 if (poolname && poolname[0] == '\0')
212 if (tgtname[0] == '\0')
215 len = strlen(tgtname);
218 /* You need one or the other to have something in it */
219 if (!poolname && !tgtname) {
225 rc = poolpath(¶m, fsname, NULL);
227 snprintf(buffer, sizeof(buffer) - 1, "%s/%s",
228 param.gl_pathv[0], poolname);
229 buffer[sizeof(buffer) - 1] = '\0';
232 rc = get_lustre_param_path(is_mdt ? "lmv" : "lov", fsname,
234 "target_obd", ¶m);
236 strncpy(buffer, param.gl_pathv[0],
238 buffer[sizeof(buffer) - 1] = '\0';
241 cfs_free_param_data(¶m);
245 fd = fopen(buffer, "r");
251 while (fgets(buffer, sizeof(buffer), fd)) {
254 /* Search for an tgtname in the list of all targets
255 * Line format is IDX: fsname-OST/MDTxxxx_UUID STATUS */
256 ptr = strchr(buffer, ' ');
257 if (ptr && strncmp(ptr + 1, tgtname, len) == 0) {
262 /* Search for an tgtname in a pool,
263 * (or an existing non-empty pool if no tgtname) */
264 if (!tgtname || strncmp(buffer, tgtname, len) == 0) {
278 int llapi_search_mdt(const char *fsname, const char *poolname,
281 return llapi_search_tgt(fsname, poolname, mdtname, true);
284 int llapi_search_ost(const char *fsname, const char *poolname,
287 return llapi_search_tgt(fsname, poolname, ostname, false);
291 * Return the open fd for a given device/path provided
293 * \param device[in] buffer holding device or path string
294 * \param rootfd[out] file descriptor after successful opening of
295 * of above path or device
297 * \retval 0 on success
298 * \retval -ve on failure
300 int llapi_root_path_open(const char *device, int *rootfd)
305 rc = get_root_path(WANT_FD, NULL, &tmp_fd,
306 (char *)device, -1, NULL, NULL);
308 rc = get_root_path(WANT_FD, (char *)device, &tmp_fd,
309 NULL, -1, NULL, NULL);
312 *rootfd = dup(tmp_fd);
318 * Call IOCTL to remove file by fid. The fd must be valid and fa
319 * (fid_array) struct must allready be populated.
321 * \param fd[in] valid descriptor of device/path
322 * \param fa[in] fid_array struct holding fids
324 * \retval 0 on success
325 * \retval -ve/errno on failure
327 int llapi_rmfid_at(int fd, struct fid_array *fa)
329 return ioctl(fd, LL_IOC_RMFID, fa) ? -errno : 0;
332 int llapi_rmfid(const char *path, struct fid_array *fa)
336 rc = llapi_root_path_open(path, &rootfd);
339 "lfs rmfid: error opening device/fsname '%s': %s\n",
340 path, strerror(-rc));
344 rc = llapi_rmfid_at(rootfd, fa);
346 fprintf(stderr, "lfs rmfid: cannot remove FIDs: %s\n",
351 return rc ? -errno : 0;
354 int llapi_direntry_remove(char *dname)
356 #ifdef LL_IOC_REMOVE_ENTRY
357 char *dirpath = NULL;
358 char *namepath = NULL;
364 dirpath = strdup(dname);
365 namepath = strdup(dname);
366 if (!dirpath || !namepath)
369 filename = basename(namepath);
371 dir = dirname(dirpath);
373 fd = open(dir, O_DIRECTORY | O_RDONLY);
376 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'",
381 if (ioctl(fd, LL_IOC_REMOVE_ENTRY, filename))
382 llapi_error(LLAPI_MSG_ERROR, errno,
383 "error on ioctl %#lx for '%s' (%d)",
384 (long)LL_IOC_LMV_SETSTRIPE, filename, fd);
396 int llapi_unlink_foreign(char *name)
401 fd = open(name, O_DIRECTORY | O_RDONLY | O_NOFOLLOW);
402 if (fd < 0 && errno != ENOTDIR) {
404 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name);
406 } else if (errno == ENOTDIR) {
407 fd = open(name, O_RDONLY | O_NOFOLLOW);
410 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'",
416 /* allow foreign symlink file/dir to be unlinked */
417 if (ioctl(fd, LL_IOC_UNLOCK_FOREIGN)) {
418 llapi_error(LLAPI_MSG_ERROR, errno,
419 "error on ioctl %#lx for '%s' (%d)",
420 (long)LL_IOC_UNLOCK_FOREIGN, name, fd);
424 /* XXX do not set AT_REMOVEDIR in flags even for a dir, as due to the
425 * hack for foreign symlink it will fail the directory check in
426 * Kernel's syscall code and return ENOTDIR, so treat all as files
428 rc = unlinkat(AT_FDCWD, name, 0);
429 if (rc == -1 && errno == EISDIR)
430 rc = unlinkat(AT_FDCWD, name, AT_REMOVEDIR);
433 llapi_error(LLAPI_MSG_ERROR, errno,
434 "error on unlinkat for '%s' (%d)", name, fd);
444 int llapi_get_fsname_instance(const char *path, char *fsname, size_t fsname_len,
445 char *instance, size_t instance_len)
447 struct obd_uuid uuid_buf;
448 char *uuid = uuid_buf.uuid;
452 memset(&uuid_buf, 0, sizeof(uuid_buf));
453 rc = llapi_file_get_lov_uuid(path, &uuid_buf);
458 * We want to turn fs-foo-clilov-ffff88002738bc00 into 'fs-foo' and
459 * 'ffff88002738bc00' in a portable way that doesn't depend on what is
460 * after "-clilov-" as it may change to a UUID string in the future.
461 * Unfortunately, the "fsname" part may contain a dash, so we can't
462 * just skip to the first dash, and if the "instance" is a UUID in the
463 * future we can't necessarily go to the last dash either.
465 ptr = strstr(uuid, "-clilov-");
466 if (!ptr || (!fsname && !instance)) {
472 ptr += strlen("-clilov-");
474 snprintf(instance, instance_len, "%s", ptr);
475 if (strlen(ptr) >= instance_len)
480 snprintf(fsname, fsname_len, "%s", uuid);
481 if (strlen(uuid) >= fsname_len)
490 int llapi_getname(const char *path, char *name, size_t namelen)
496 rc = llapi_get_fsname_instance(path, fsname, sizeof(fsname),
497 instance, sizeof(instance));
501 snprintf(name, namelen, "%s-%s", fsname, instance);
502 if (strlen(fsname) + 1 + strlen(instance) >= namelen) {
510 int llapi_get_instance(const char *path, char *instance, size_t instance_len)
512 return llapi_get_fsname_instance(path, NULL, 0, instance, instance_len);
515 int llapi_get_fsname(const char *path, char *fsname, size_t fsname_len)
517 return llapi_get_fsname_instance(path, fsname, fsname_len, NULL, 0);