X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Futils%2Fliblustreapi_param.c;h=8a8ae45aa8e1bf20ae10b1fa12ec7923e9b6045e;hb=14db26a85c52561d186b5c400981a0025d45864a;hp=6c3a48d69cad1a99384b3a4e1217e8345e20d6ba;hpb=ccabce23bd9e366c345c852f565766a799f61238;p=fs%2Flustre-release.git diff --git a/lustre/utils/liblustreapi_param.c b/lustre/utils/liblustreapi_param.c index 6c3a48d..8a8ae45 100644 --- a/lustre/utils/liblustreapi_param.c +++ b/lustre/utils/liblustreapi_param.c @@ -25,7 +25,13 @@ * Copyright (c) 2016, Intel Corporation. */ #include +#include #include +#include +#include +#include +#include +#include #include #include @@ -83,7 +89,7 @@ get_lustre_param_path(const char *obd_type, const char *filter, } if (strlen(pattern) + 3 > sizeof(pattern)) return -E2BIG; - strncat(pattern, "-*", sizeof(pattern)); + strncat(pattern, "-*", sizeof(pattern) - 1); break; case FILTER_BY_FS_NAME: rc = snprintf(pattern, sizeof(pattern) - 1, "%s-*", filter); @@ -181,3 +187,239 @@ err: return rc; } + +int llapi_param_get_paths(const char *pattern, glob_t *paths) +{ + return get_lustre_param_path(NULL, NULL, FILTER_BY_NONE, + pattern, paths); +} + +/** + * Read to the end of the file and count the bytes read. + */ +static int bytes_remaining(int fd, size_t *file_size) +{ + int rc = 0; + size_t bytes_read = 0; + long page_size = sysconf(_SC_PAGESIZE); + char *temp_buf; + + temp_buf = malloc(page_size); + if (temp_buf == NULL) + return -ENOMEM; + + while (1) { + ssize_t count = read(fd, temp_buf, page_size); + + if (count == 0) { + *file_size = bytes_read; + break; + } + + if (count < 0) { + rc = -errno; + break; + } + bytes_read += count; + } + + free(temp_buf); + return rc; +} + +/** + * Determine the size of a file by reading it. + */ +static int required_size(const char *path, size_t *file_size) +{ + int rc = 0; + int fd; + + fd = open(path, O_RDONLY); + if (fd < 0) + return -errno; + + rc = bytes_remaining(fd, file_size); + + close(fd); + *file_size += 1; + return rc; +} + +static +int copy_file_expandable(const char *path, char **buf, size_t *file_size) +{ + long page_size = sysconf(_SC_PAGESIZE); + int rc = 0; + char *temp_buf; + int fd; + FILE *fp; + + fp = open_memstream(buf, file_size); + if (fp == NULL) { + rc = -errno; + goto out; + } + + fd = open(path, O_RDONLY); + if (fd < 0) { + rc = -errno; + goto close_stream; + } + + temp_buf = calloc(1, page_size); + if (buf == NULL) { + rc = -ENOMEM; + goto close_file; + } + + while (1) { + ssize_t count = read(fd, temp_buf, page_size); + + if (count == 0) + break; + if (count < 0) { + rc = -errno; + break; + } + + if (fwrite(temp_buf, 1, count, fp) != count) { + rc = -errno; + break; + } + } + + free(temp_buf); +close_file: + close(fd); +close_stream: + fclose(fp); +out: + /* If rc != 0 and *buf != NULL, the caller may retry. + * This would likely result in copy_file_fixed() being called + * on accident, and a likely memory error. + */ + if (rc != 0) { + free(*buf); + *buf = NULL; + } + return rc; +} + +/** + * Copy file to a buffer and write the number of bytes copied + */ +static int copy_file_fixed(const char *path, char *buf, size_t *buflen) +{ + int rc = 0; + size_t bytes_read = 0; + size_t max_read = *buflen - 1; + size_t remaining = 0; + int fd; + + fd = open(path, O_RDONLY); + if (fd < 0) + return -errno; + + while (bytes_read < max_read) { + ssize_t count = read(fd, + buf + bytes_read, + max_read - bytes_read); + + /* read the entire file */ + if (count == 0) { + *buflen = bytes_read + 1; + buf[bytes_read] = '\0'; + goto out; + } + + if (count < 0) + goto check_size; + + bytes_read += count; + } + +check_size: + /* need to check size in case error due to buf being too small + * for read() or exited loop due to buf being full + */ + buf[max_read] = '\0'; + + rc = bytes_remaining(fd, &remaining); + if (rc != 0) { + rc = -errno; + goto out; + } + *buflen = bytes_read + remaining; + + /* file was not (*buflen - 1) bytes, add 1 for reallocating */ + if (remaining != 0) { + *buflen += 1; + rc = -EOVERFLOW; + } + +out: + close(fd); + + return rc; +} + +/** + * Read the value of the file with location \a path + * into a buffer. + * + * \param path[in] the location of a parameter file + * \param buf[in,out] a pointer to a pointer to a buffer + * \param buflen[in,out] the length of a pre-allocated buffer + * when passed in, and either the number + * of bytes written or the suggested + * size of *buf when passed out. + * + * There are 3 behaviors based on the value of buf. + * If buf == NULL, then the buffer size needed to read the file at + * \a path will be written to \a *buflen. + * If \a buf != NULL and \a *buf == NULL, the value of *buf will point + * to a buffer that will be automatically sized to fit the file + * contents. A NUL byte will be added to the end of the buffer. + * The value of \a *buflen will be set to the number of bytes written + * excuding the NUL byte. + * If \a buf != NULL and \a *buf != NULL, it will be assumed that \a *buf + * points to a pre-allocated buffer with a capacity of \a *buflen. + * If there is sufficient space, the file contents and NUL terminating + * byte will be written to the buffer at .\a *buf. + * Otherwise, the required size of \a *buflen with be written to \a *buflen. + * + * Returns 0 for success with null terminated string in \a *buf. + * Returns negative errno value on error. + * For case of \a buf != NULL and \a *buf != NULL, a return value + * of -EOVERFLOW indicates that it's possible retry with a larger + * buffer. + */ +int llapi_param_get_value(const char *path, char **buf, size_t *buflen) +{ + int rc = 0; + + if (path == NULL || buflen == NULL) + rc = -EINVAL; + else if (buf == NULL) + rc = required_size(path, buflen); + /* handle for buffer, but no buffer + * create a buffer of the required size + */ + else if (*buf == NULL) + rc = copy_file_expandable(path, buf, buflen); + /* preallocated buffer given, attempt to copy + * file to it, return file size if buffer too small + */ + else + rc = copy_file_fixed(path, *buf, buflen); + + errno = -rc; + + return rc; +} + +void llapi_param_paths_free(glob_t *paths) +{ + cfs_free_param_data(paths); +}