Whamcloud - gitweb
LU-11264 llapi: clean up llapi_search_tgt() code
[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 <string.h>
38 #include <unistd.h>
39 #include <sys/time.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <sys/syscall.h>
43 #include <lustre/lustreapi.h>
44 #include <linux/lustre/lustre_ver.h>    /* only until LUSTRE_VERSION_CODE is gone */
45 #include "lustreapi_internal.h"
46
47 /*
48  * Indicate whether the liblustreapi_init() constructor below has run or not.
49  *
50  * This can be used by external programs to ensure that the initialization
51  * mechanism has actually worked.
52  */
53 bool liblustreapi_initialized;
54
55 /**
56  * Initialize the library once at startup.
57  *
58  * Initializes the random number generator (random()). Get
59  * data from different places in case one of them fails. This
60  * is enough to get reasonably random numbers, but is not
61  * strong enough to be used for cryptography.
62  */
63 static __attribute__ ((constructor)) void liblustreapi_init(void)
64 {
65         unsigned int    seed;
66         struct timeval  tv;
67         int             fd;
68
69         seed = syscall(SYS_gettid);
70
71         if (gettimeofday(&tv, NULL) == 0) {
72                 seed ^= tv.tv_sec;
73                 seed ^= tv.tv_usec;
74         }
75
76         fd = open("/dev/urandom", O_RDONLY | O_NOFOLLOW);
77         if (fd >= 0) {
78                 unsigned int rnumber;
79                 ssize_t ret;
80
81                 ret = read(fd, &rnumber, sizeof(rnumber));
82                 seed ^= rnumber ^ ret;
83                 close(fd);
84         }
85
86         srandom(seed);
87         liblustreapi_initialized = true;
88 }
89
90 /**
91  * Return the release version for the Lustre modules, e.g. 2.6.92.
92  *
93  * The "version" file in /proc currently returns only the line:
94  * lustre: 2.8.52
95  *
96  * but in the past it also returned more lines that should be ignored:
97  * kernel: patchless_client
98  * build: v2_6_92_0-gadb3ee4-2.6.32-431.29.2.el6_lustre.g36cd22b.x86_64
99  *
100  * \param version[in,out]       buffer to store build version string
101  * \param version_size[in]      size of \a version
102  *
103  * \retval                      0 on success
104  * \retval                      -1 on failure, errno set
105  */
106 int llapi_get_version_string(char *version, unsigned int version_size)
107 {
108         char buffer[4096];
109         char *ptr;
110         int rc;
111
112         if (version == NULL || version_size == 0) {
113                 errno = EINVAL;
114                 return -1;
115         }
116
117         rc = get_lustre_param_value(NULL, NULL, FILTER_BY_NONE, buffer,
118                                     "version", sizeof(buffer));
119         if (rc < 0) {
120                 errno = -rc;
121                 return -1;
122         }
123
124         ptr = strstr(buffer, "lustre:");
125         if (ptr) {
126                 ptr += strlen("lustre:");
127                 while (*ptr == ' ' || *ptr == '\t')
128                         ptr++;
129         } else {
130                 ptr = buffer;
131         }
132         llapi_chomp_string(ptr);
133
134         if (ptr[0] == '\0') {
135                 errno = ENODATA;
136                 return -1;
137         }
138
139         if (snprintf(version, version_size, "%s", ptr) >= version_size) {
140                 errno = EOVERFLOW;
141                 return -1;
142         }
143         return 0;
144 }
145
146 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 4, 53, 0)
147 /**
148  * Return the build version of the Lustre code.
149  *
150  * The **version argument is pointless, so llapi_get_version_string() is
151  * better to use in the future, but give users a few versions to fix * it.
152  *
153  * \param buffer[in]            temporary buffer to hold version string
154  * \param buffer_size[in]       length of the \a buffer
155  * \param version[out]          pointer to the start of build version string
156  *
157  * \retval                      0 on success
158  * \retval                      -ve errno on failure
159  */
160 int llapi_get_version(char *buffer, int buffer_size, char **version)
161 {
162         int rc;
163 #if LUSTRE_VERSION_CODE > OBD_OCD_VERSION(2, 8, 53, 0)
164         static bool printed;
165         if (!printed) {
166                 fprintf(stderr,
167                         "%s deprecated, use llapi_get_version_string()\n",
168                         __func__);
169                 printed = true;
170         }
171 #endif
172
173         rc = llapi_get_version_string(buffer, buffer_size);
174         /* keep old return style for this legacy function */
175         if (rc == -1)
176                 rc = -errno;
177         else
178                 *version = buffer;
179
180         return rc;
181 }
182 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 4, 53, 0) */
183
184 /*
185  * fsname must be specified
186  * if poolname is NULL, search tgtname in fsname
187  * if poolname is not NULL:
188  *  if poolname not found returns errno < 0
189  *  if tgtname is NULL, returns 1 if pool is not empty and 0 if pool empty
190  *  if tgtname is not NULL, returns 1 if target is in pool and 0 if not
191  */
192 int llapi_search_tgt(const char *fsname, const char *poolname,
193                      const char *tgtname, bool is_mdt)
194 {
195         char buffer[PATH_MAX];
196         size_t len = 0;
197         glob_t param;
198         FILE *fd;
199         int rc;
200
201         if (fsname && fsname[0] == '\0')
202                 fsname = NULL;
203         if (!fsname) {
204                 rc = -EINVAL;
205                 goto out;
206         }
207
208         if (poolname && poolname[0] == '\0')
209                 poolname = NULL;
210         if (tgtname) {
211                 if (tgtname[0] == '\0')
212                         tgtname = NULL;
213                 else
214                         len = strlen(tgtname);
215         }
216
217         /* You need one or the other to have something in it */
218         if (!poolname && !tgtname) {
219                 rc = -EINVAL;
220                 goto out;
221         }
222
223         if (poolname) {
224                 rc = poolpath(&param, fsname, NULL);
225                 if (!rc) {
226                         snprintf(buffer, sizeof(buffer) - 1, "%s/%s",
227                                  param.gl_pathv[0], poolname);
228                         buffer[sizeof(buffer) - 1] = '\0';
229                 }
230         } else {
231                 rc = get_lustre_param_path(is_mdt ? "lmv" : "lov", fsname,
232                                            FILTER_BY_FS_NAME,
233                                            "target_obd", &param);
234                 if (!rc) {
235                         strncpy(buffer, param.gl_pathv[0],
236                                 sizeof(buffer) - 1);
237                         buffer[sizeof(buffer) - 1] = '\0';
238                 }
239         }
240         cfs_free_param_data(&param);
241         if (rc)
242                 goto out;
243
244         fd = fopen(buffer, "r");
245         if (!fd) {
246                 rc = -errno;
247                 goto out;
248         }
249
250         while (fgets(buffer, sizeof(buffer), fd)) {
251                 if (!poolname) {
252                         char *ptr;
253                         /* Search for an tgtname in the list of all targets
254                          * Line format is IDX: fsname-OST/MDTxxxx_UUID STATUS */
255                         ptr = strchr(buffer, ' ');
256                         if (ptr && strncmp(ptr + 1, tgtname, len) == 0) {
257                                 rc = 1;
258                                 goto out_close;
259                         }
260                 } else {
261                         /* Search for an tgtname in a pool,
262                          * (or an existing non-empty pool if no tgtname) */
263                         if (!tgtname || strncmp(buffer, tgtname, len) == 0) {
264                                 rc = 1;
265                                 goto out_close;
266                         }
267                 }
268         }
269 out_close:
270         fclose(fd);
271 out:
272         if (rc < 0)
273                 errno = -rc;
274         return rc;
275 }
276
277 int llapi_search_mdt(const char *fsname, const char *poolname,
278                      const char *mdtname)
279 {
280         return llapi_search_tgt(fsname, poolname, mdtname, true);
281 }
282
283 int llapi_search_ost(const char *fsname, const char *poolname,
284                      const char *ostname)
285 {
286         return llapi_search_tgt(fsname, poolname, ostname, false);
287 }
288