Whamcloud - gitweb
LU-5969 lustreapi: allow "version" without "lustre:"
[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 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 <libcfs/util/string.h> /* only needed for compat strlcpy() */
45 #include <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 /**
58  * Initialize the library once at startup.
59  *
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.
64  */
65 static __attribute__ ((constructor)) void liblustreapi_init(void)
66 {
67         unsigned int    seed;
68         struct timeval  tv;
69         int             fd;
70
71         seed = syscall(SYS_gettid);
72
73         if (gettimeofday(&tv, NULL) == 0) {
74                 seed ^= tv.tv_sec;
75                 seed ^= tv.tv_usec;
76         }
77
78         fd = open("/dev/urandom", O_RDONLY | O_NOFOLLOW);
79         if (fd >= 0) {
80                 unsigned int rnumber;
81                 ssize_t ret;
82
83                 ret = read(fd, &rnumber, sizeof(rnumber));
84                 seed ^= rnumber ^ ret;
85                 close(fd);
86         }
87
88         srandom(seed);
89         liblustreapi_initialized = true;
90 }
91
92 /**
93  * Return the release version for the Lustre modules, e.g. 2.6.92.
94  *
95  * The "version" file in /proc currently returns only the line:
96  * lustre: 2.8.52
97  *
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
101  *
102  * \param version[in,out]       buffer to store build version string
103  * \param version_size[in]      size of \a version
104  *
105  * \retval                      0 on success
106  * \retval                      -1 on failure, errno set
107  */
108 int llapi_get_version_string(char *version, unsigned int version_size)
109 {
110         char buffer[4096];
111         char *ptr;
112         int rc;
113
114         if (version == NULL || version_size == 0) {
115                 errno = EINVAL;
116                 return -1;
117         }
118
119         rc = get_lustre_param_value(NULL, NULL, FILTER_BY_NONE, buffer,
120                                     "version", sizeof(buffer));
121         if (rc < 0) {
122                 errno = -rc;
123                 return -1;
124         }
125
126         ptr = strstr(buffer, "lustre:");
127         if (ptr) {
128                 ptr += strlen("lustre:");
129                 while (*ptr == ' ' || *ptr == '\t')
130                         ptr++;
131         } else {
132                 ptr = buffer;
133         }
134         llapi_chomp_string(ptr);
135
136         if (ptr[0] == '\0') {
137                 errno = ENODATA;
138                 return -1;
139         }
140
141         if (strlcpy(version, ptr, version_size) >= version_size) {
142                 errno = EOVERFLOW;
143                 return -1;
144         }
145         return 0;
146 }
147
148 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 4, 53, 0)
149 /**
150  * Return the build version of the Lustre code.
151  *
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.
154  *
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
158  *
159  * \retval                      0 on success
160  * \retval                      -ve errno on failure
161  */
162 int llapi_get_version(char *buffer, int buffer_size, char **version)
163 {
164         int rc;
165 #if LUSTRE_VERSION_CODE > OBD_OCD_VERSION(2, 8, 53, 0)
166         static bool printed;
167         if (!printed) {
168                 fprintf(stderr,
169                         "%s deprecated, use llapi_get_version_string()\n",
170                         __func__);
171                 printed = true;
172         }
173 #endif
174
175         rc = llapi_get_version_string(buffer, buffer_size);
176         /* keep old return style for this legacy function */
177         if (rc == -1)
178                 rc = -errno;
179         else
180                 *version = buffer;
181
182         return rc;
183 }
184 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 4, 53, 0) */