4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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
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.
20 * lustre/utils/liblustreapi_param.c
22 * This code handles user interaction with the configuration interface
23 * to the Lustre file system to fine tune it.
25 * Copyright (c) 2016, Intel Corporation.
33 #include <sys/types.h>
36 #include <libcfs/util/param.h>
37 #include <linux/lustre/lustre_user.h>
38 #include <lustre/lustreapi.h>
39 #include "lustreapi_internal.h"
42 * return the parameter's path for a specific device type or mountpoint
44 * \param param the results returned to the caller
45 * \param obd_type Lustre OBD device type
47 * \param filter filter combined with the type agrument allow the
48 * \param type caller to limit the scope of the search for the
49 * parameter's path. Typical options are search by
50 * Lustre filesystem name or by the path to a file
51 * or directory in the filesystem.
53 * \param param_name parameter name to fetch
55 * Using filter and the type argument we can limit the scope of the
56 * search to either the parameter belonging to a specific lustre filesystem
57 * (if it exists) or using a given file or directory path located on a
58 * mounted Lustre filesystem. The last case it can do is a special search
59 * based on exactly what the user passed instead of scanning file paths
60 * or specific file systems.
62 * If "obd_type" matches a Lustre device then the first matching device
63 * (as with "lctl dl", constrained by \param filter and \param type)
64 * will be used to provide the return value, otherwise the first such
65 * device found will be used.
67 * Return 0 for success, with the results stored in \param param.
68 * Return -ve value for error.
71 get_lustre_param_path(const char *obd_type, const char *filter,
72 enum param_filter type, const char *param_name,
75 char pattern[PATH_MAX];
78 if (filter == NULL && type != FILTER_BY_NONE)
83 rc = llapi_search_fsname(filter, pattern);
85 llapi_error(LLAPI_MSG_ERROR, rc,
86 "'%s' is not on a Lustre filesystem",
90 if (strlen(pattern) + 3 > sizeof(pattern))
92 strncat(pattern, "-*", sizeof(pattern) - 1);
94 case FILTER_BY_FS_NAME:
95 rc = snprintf(pattern, sizeof(pattern) - 1, "%s-*", filter);
98 else if (rc >= sizeof(pattern))
102 case FILTER_BY_EXACT:
103 if (strlen(filter) + 1 > sizeof(pattern))
105 strncpy(pattern, filter, sizeof(pattern));
112 if (type == FILTER_BY_NONE) {
113 if (cfs_get_param_paths(param, "%s", param_name) != 0)
115 } else if (param_name != NULL) {
116 if (cfs_get_param_paths(param, "%s/%s/%s",
117 obd_type, pattern, param_name) != 0)
120 if (cfs_get_param_paths(param, "%s/%s",
121 obd_type, pattern) != 0)
129 * return a parameter of a single line value for a specific device type
132 * \param obd_type Lustre OBD device type
134 * \param filter filter combined with the type agruments allow the
135 * \param type caller to limit the scope of the search for the
136 * parameter's path. Typical options are search by
137 * Lustre filesystem name or by the path to a file
138 * or directory in the filesystem.
140 * \param param_name parameter name to fetch
141 * \param value return buffer for parameter value string
142 * \param val_len size of buffer for return value
144 * Using filter and the type argument we can limit the scope of the
145 * search to either the parameter belonging to a specific lustre filesystem
146 * (if it exists) or using a given file or directory path located on a
147 * mounted Lustre filesystem. The last case it can do is a special search
148 * based on exactly what the user passed instead of scanning file paths
149 * or specific file systems.
151 * If "obd_type" matches a Lustre device then the first matching device
152 * (as with "lctl dl", constrained by \param filter and \param type)
153 * will be used to provide the return value, otherwise the first such
154 * device found will be used.
156 * Return 0 for success, with a NUL-terminated string in \param value.
157 * Return negative errno value for error.
160 get_lustre_param_value(const char *obd_type, const char *filter,
161 enum param_filter type, const char *param_name,
162 char *value, size_t val_len)
168 rc = get_lustre_param_path(obd_type, filter, type, param_name, ¶m);
172 fp = fopen(param.gl_pathv[0], "r");
175 llapi_error(LLAPI_MSG_ERROR, rc, "error: opening '%s'",
180 if (fgets(value, val_len, fp) == NULL) {
186 cfs_free_param_data(¶m);
191 int llapi_param_get_paths(const char *pattern, glob_t *paths)
193 return get_lustre_param_path(NULL, NULL, FILTER_BY_NONE,
198 * Read to the end of the file and count the bytes read.
200 static int bytes_remaining(int fd, size_t *file_size)
203 size_t bytes_read = 0;
204 long page_size = sysconf(_SC_PAGESIZE);
207 temp_buf = malloc(page_size);
208 if (temp_buf == NULL)
212 ssize_t count = read(fd, temp_buf, page_size);
215 *file_size = bytes_read;
231 * Determine the size of a file by reading it.
233 static int required_size(const char *path, size_t *file_size)
238 fd = open(path, O_RDONLY);
242 rc = bytes_remaining(fd, file_size);
250 int copy_file_expandable(const char *path, char **buf, size_t *file_size)
252 long page_size = sysconf(_SC_PAGESIZE);
258 fp = open_memstream(buf, file_size);
264 fd = open(path, O_RDONLY);
270 temp_buf = calloc(1, page_size);
277 ssize_t count = read(fd, temp_buf, page_size);
286 if (fwrite(temp_buf, 1, count, fp) != count) {
298 /* If rc != 0 and *buf != NULL, the caller may retry.
299 * This would likely result in copy_file_fixed() being called
300 * on accident, and a likely memory error.
310 * Copy file to a buffer and write the number of bytes copied
312 static int copy_file_fixed(const char *path, char *buf, size_t *buflen)
315 size_t bytes_read = 0;
316 size_t max_read = *buflen - 1;
317 size_t remaining = 0;
320 fd = open(path, O_RDONLY);
324 while (bytes_read < max_read) {
325 ssize_t count = read(fd,
327 max_read - bytes_read);
329 /* read the entire file */
331 *buflen = bytes_read + 1;
332 buf[bytes_read] = '\0';
343 /* need to check size in case error due to buf being too small
344 * for read() or exited loop due to buf being full
346 buf[max_read] = '\0';
348 rc = bytes_remaining(fd, &remaining);
353 *buflen = bytes_read + remaining;
355 /* file was not (*buflen - 1) bytes, add 1 for reallocating */
356 if (remaining != 0) {
368 * Read the value of the file with location \a path
371 * \param path[in] the location of a parameter file
372 * \param buf[in,out] a pointer to a pointer to a buffer
373 * \param buflen[in,out] the length of a pre-allocated buffer
374 * when passed in, and either the number
375 * of bytes written or the suggested
376 * size of *buf when passed out.
378 * There are 3 behaviors based on the value of buf.
379 * If buf == NULL, then the buffer size needed to read the file at
380 * \a path will be written to \a *buflen.
381 * If \a buf != NULL and \a *buf == NULL, the value of *buf will point
382 * to a buffer that will be automatically sized to fit the file
383 * contents. A NUL byte will be added to the end of the buffer.
384 * The value of \a *buflen will be set to the number of bytes written
385 * excuding the NUL byte.
386 * If \a buf != NULL and \a *buf != NULL, it will be assumed that \a *buf
387 * points to a pre-allocated buffer with a capacity of \a *buflen.
388 * If there is sufficient space, the file contents and NUL terminating
389 * byte will be written to the buffer at .\a *buf.
390 * Otherwise, the required size of \a *buflen with be written to \a *buflen.
392 * Returns 0 for success with null terminated string in \a *buf.
393 * Returns negative errno value on error.
394 * For case of \a buf != NULL and \a *buf != NULL, a return value
395 * of -EOVERFLOW indicates that it's possible retry with a larger
398 int llapi_param_get_value(const char *path, char **buf, size_t *buflen)
402 if (path == NULL || buflen == NULL)
404 else if (buf == NULL)
405 rc = required_size(path, buflen);
406 /* handle for buffer, but no buffer
407 * create a buffer of the required size
409 else if (*buf == NULL)
410 rc = copy_file_expandable(path, buf, buflen);
411 /* preallocated buffer given, attempt to copy
412 * file to it, return file size if buffer too small
415 rc = copy_file_fixed(path, *buf, buflen);
422 void llapi_param_paths_free(glob_t *paths)
424 cfs_free_param_data(paths);