Whamcloud - gitweb
LU-13153 lib: fix llapi_get_version_string
[fs/lustre-release.git] / lustre / utils / liblustreapi_util.c
1 /*
2  * LGPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * (C) Copyright (c) 2015, Cray Inc, all rights reserved.
7  *
8  * Copyright (c) 2016, 2017, Intel Corporation.
9  *
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
15  *
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.
20  *
21  * LGPL HEADER END
22  */
23 /*
24  * lustre/utils/liblustreapi_util.c
25  *
26  * Misc LGPL-licenced utility functions for liblustreapi.
27  *
28  * Author: Frank Zago <fzago@cray.com>
29  */
30
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdbool.h>
34 #include <stddef.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <sys/ioctl.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <sys/time.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <sys/syscall.h>
44 #include <lustre/lustreapi.h>
45 #include <linux/lustre/lustre_ver.h>    /* only until LUSTRE_VERSION_CODE is gone */
46 #include "lustreapi_internal.h"
47
48 /*
49  * Indicate whether the liblustreapi_init() constructor below has run or not.
50  *
51  * This can be used by external programs to ensure that the initialization
52  * mechanism has actually worked.
53  */
54 bool liblustreapi_initialized;
55
56 /**
57  * Initialize the library once at startup.
58  *
59  * Initializes the random number generator (random()). Get
60  * data from different places in case one of them fails. This
61  * is enough to get reasonably random numbers, but is not
62  * strong enough to be used for cryptography.
63  */
64 static __attribute__ ((constructor)) void liblustreapi_init(void)
65 {
66         unsigned int    seed;
67         struct timeval  tv;
68         int             fd;
69
70         seed = syscall(SYS_gettid);
71
72         if (gettimeofday(&tv, NULL) == 0) {
73                 seed ^= tv.tv_sec;
74                 seed ^= tv.tv_usec;
75         }
76
77         fd = open("/dev/urandom", O_RDONLY | O_NOFOLLOW);
78         if (fd >= 0) {
79                 unsigned int rnumber;
80                 ssize_t ret;
81
82                 ret = read(fd, &rnumber, sizeof(rnumber));
83                 seed ^= rnumber ^ ret;
84                 close(fd);
85         }
86
87         srandom(seed);
88         liblustreapi_initialized = true;
89 }
90
91 /**
92  * Return the release version for the Lustre modules, e.g. 2.6.92.
93  *
94  * The "version" file in /proc currently returns only the line:
95  * lustre: 2.8.52
96  *
97  * but in the past it also returned more lines that should be ignored:
98  * kernel: patchless_client
99  * build: v2_6_92_0-gadb3ee4-2.6.32-431.29.2.el6_lustre.g36cd22b.x86_64
100  *
101  * \param version[in,out]       buffer to store build version string
102  * \param version_size[in]      size of \a version
103  *
104  * \retval                      0 on success
105  * \retval                      -1 on failure, errno set
106  */
107 int llapi_get_version_string(char *version, unsigned int version_size)
108 {
109         char buffer[4096];
110         char *ptr;
111         int rc;
112
113         if (version == NULL || version_size == 0) {
114                 errno = EINVAL;
115                 return -1;
116         }
117
118         rc = get_lustre_param_value(NULL, NULL, FILTER_BY_NONE, "version",
119                                     buffer, sizeof(buffer));
120         if (rc < 0) {
121                 errno = -rc;
122                 return -1;
123         }
124
125         ptr = strstr(buffer, "lustre:");
126         if (ptr) {
127                 ptr += strlen("lustre:");
128                 while (*ptr == ' ' || *ptr == '\t')
129                         ptr++;
130         } else {
131                 ptr = buffer;
132         }
133         llapi_chomp_string(ptr);
134
135         if (ptr[0] == '\0') {
136                 errno = ENODATA;
137                 return -1;
138         }
139
140         if (snprintf(version, version_size, "%s", ptr) >= version_size) {
141                 errno = EOVERFLOW;
142                 return -1;
143         }
144         return 0;
145 }
146
147 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 4, 53, 0)
148 /**
149  * Return the build version of the Lustre code.
150  *
151  * The **version argument is pointless, so llapi_get_version_string() is
152  * better to use in the future, but give users a few versions to fix * it.
153  *
154  * \param buffer[in]            temporary buffer to hold version string
155  * \param buffer_size[in]       length of the \a buffer
156  * \param version[out]          pointer to the start of build version string
157  *
158  * \retval                      0 on success
159  * \retval                      -ve errno on failure
160  */
161 int llapi_get_version(char *buffer, int buffer_size, char **version)
162 {
163         int rc;
164 #if LUSTRE_VERSION_CODE > OBD_OCD_VERSION(2, 8, 53, 0)
165         static bool printed;
166         if (!printed) {
167                 fprintf(stderr,
168                         "%s deprecated, use llapi_get_version_string()\n",
169                         __func__);
170                 printed = true;
171         }
172 #endif
173
174         rc = llapi_get_version_string(buffer, buffer_size);
175         /* keep old return style for this legacy function */
176         if (rc == -1)
177                 rc = -errno;
178         else
179                 *version = buffer;
180
181         return rc;
182 }
183 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 4, 53, 0) */
184
185 /*
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
192  */
193 int llapi_search_tgt(const char *fsname, const char *poolname,
194                      const char *tgtname, bool is_mdt)
195 {
196         char buffer[PATH_MAX];
197         size_t len = 0;
198         glob_t param;
199         FILE *fd;
200         int rc;
201
202         if (fsname && fsname[0] == '\0')
203                 fsname = NULL;
204         if (!fsname) {
205                 rc = -EINVAL;
206                 goto out;
207         }
208
209         if (poolname && poolname[0] == '\0')
210                 poolname = NULL;
211         if (tgtname) {
212                 if (tgtname[0] == '\0')
213                         tgtname = NULL;
214                 else
215                         len = strlen(tgtname);
216         }
217
218         /* You need one or the other to have something in it */
219         if (!poolname && !tgtname) {
220                 rc = -EINVAL;
221                 goto out;
222         }
223
224         if (poolname) {
225                 rc = poolpath(&param, fsname, NULL);
226                 if (!rc) {
227                         snprintf(buffer, sizeof(buffer) - 1, "%s/%s",
228                                  param.gl_pathv[0], poolname);
229                         buffer[sizeof(buffer) - 1] = '\0';
230                 }
231         } else {
232                 rc = get_lustre_param_path(is_mdt ? "lmv" : "lov", fsname,
233                                            FILTER_BY_FS_NAME,
234                                            "target_obd", &param);
235                 if (!rc) {
236                         strncpy(buffer, param.gl_pathv[0],
237                                 sizeof(buffer) - 1);
238                         buffer[sizeof(buffer) - 1] = '\0';
239                 }
240         }
241         cfs_free_param_data(&param);
242         if (rc)
243                 goto out;
244
245         fd = fopen(buffer, "r");
246         if (!fd) {
247                 rc = -errno;
248                 goto out;
249         }
250
251         while (fgets(buffer, sizeof(buffer), fd)) {
252                 if (!poolname) {
253                         char *ptr;
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) {
258                                 rc = 1;
259                                 goto out_close;
260                         }
261                 } else {
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) {
265                                 rc = 1;
266                                 goto out_close;
267                         }
268                 }
269         }
270 out_close:
271         fclose(fd);
272 out:
273         if (rc < 0)
274                 errno = -rc;
275         return rc;
276 }
277
278 int llapi_search_mdt(const char *fsname, const char *poolname,
279                      const char *mdtname)
280 {
281         return llapi_search_tgt(fsname, poolname, mdtname, true);
282 }
283
284 int llapi_search_ost(const char *fsname, const char *poolname,
285                      const char *ostname)
286 {
287         return llapi_search_tgt(fsname, poolname, ostname, false);
288 }
289
290 int llapi_rmfid(const char *path, struct fid_array *fa)
291 {
292         char rootpath[PATH_MAX];
293         int fd, rc;
294
295 retry_open:
296         fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
297         if (fd < 0) {
298                 if (errno == ENOENT && path != rootpath) {
299                         rc = llapi_search_rootpath(rootpath, path);
300                         if (!rc) {
301                                 path = rootpath;
302                                 goto retry_open;
303                         }
304                 } else {
305                         return -errno;
306                 }
307         }
308
309         rc = ioctl(fd, LL_IOC_RMFID, fa);
310         close(fd);
311
312         return rc ? -errno : 0;
313 }
314
315 int llapi_get_fsname_instance(const char *path, char *fsname, size_t fsname_len,
316                               char *instance, size_t instance_len)
317 {
318         struct obd_uuid uuid_buf;
319         char *uuid = uuid_buf.uuid;
320         char *ptr;
321         int rc;
322
323         memset(&uuid_buf, 0, sizeof(uuid_buf));
324         rc = llapi_file_get_lov_uuid(path, &uuid_buf);
325         if (rc)
326                 return rc;
327
328         /*
329          * We want to turn fs-foo-clilov-ffff88002738bc00 into 'fs-foo' and
330          * 'ffff88002738bc00' in a portable way that doesn't depend on what is
331          * after "-clilov-" as it may change to a UUID string in the future.
332          * Unfortunately, the "fsname" part may contain a dash, so we can't
333          * just skip to the first dash, and if the "instance" is a UUID in the
334          * future we can't necessarily go to the last dash either.
335          */
336         ptr = strstr(uuid, "-clilov-");
337         if (!ptr || (!fsname && !instance)) {
338                 rc = -EINVAL;
339                 goto out;
340         }
341
342         *ptr = '\0';
343         ptr += strlen("-clilov-");
344         if (instance) {
345                 snprintf(instance, instance_len, "%s", ptr);
346                 if (strlen(ptr) >= instance_len)
347                         rc = -ENAMETOOLONG;
348         }
349
350         if (fsname) {
351                 snprintf(fsname, fsname_len, "%s", uuid);
352                 if (strlen(uuid) >= fsname_len)
353                         rc = -ENAMETOOLONG;
354         }
355
356 out:
357         errno = -rc;
358         return rc;
359 }
360
361 int llapi_getname(const char *path, char *name, size_t namelen)
362 {
363         char fsname[16];
364         char instance[40];
365         int rc;
366
367         rc = llapi_get_fsname_instance(path, fsname, sizeof(fsname),
368                                        instance, sizeof(instance));
369         if (rc)
370                 return rc;
371
372         snprintf(name, namelen, "%s-%s", fsname, instance);
373         if (strlen(fsname) + 1 + strlen(instance) >= namelen) {
374                 rc = -ENAMETOOLONG;
375                 errno = -rc;
376         }
377
378         return rc;
379 }
380
381 int llapi_get_instance(const char *path, char *instance, size_t instance_len)
382 {
383         return llapi_get_fsname_instance(path, NULL, 0, instance, instance_len);
384 }
385
386 int llapi_get_fsname(const char *path, char *fsname, size_t fsname_len)
387 {
388         return llapi_get_fsname_instance(path, fsname, fsname_len, NULL, 0);
389 }