/* * Copyright (c) 2006 Cisco Systems, Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include "ibverbs.h" static const char *sysfs_path; const char *ibv_get_sysfs_path(void) { const char *env = NULL; if (sysfs_path) return sysfs_path; /* * Only follow use path passed in through the calling user's * environment if we're not running SUID. */ if (getuid() == geteuid()) env = getenv("SYSFS_PATH"); if (env) { int len; char *dup; sysfs_path = dup = strndup(env, IBV_SYSFS_PATH_MAX); len = strlen(dup); while (len > 0 && dup[len - 1] == '/') { --len; dup[len] = '\0'; } } else sysfs_path = "/sys"; return sysfs_path; } int ibv_read_sysfs_file_at(int dirfd, const char *file, char *buf, size_t size) { ssize_t len; int fd; fd = openat(dirfd, file, O_RDONLY | O_CLOEXEC); if (fd < 0) return -1; len = read(fd, buf, size); close(fd); if (len > 0) { if (buf[len - 1] == '\n') buf[--len] = '\0'; else if (len < size) buf[len] = '\0'; else /* We would have to truncate the contents to NULL * terminate, so we are going to fail no matter * what we do, either right now or later when * we pass around an unterminated string. Fail now. */ return -1; } return len; } int ibv_read_sysfs_file(const char *dir, const char *file, char *buf, size_t size) { char *path; int res; if (asprintf(&path, "%s/%s", dir, file) < 0) return -1; res = ibv_read_sysfs_file_at(AT_FDCWD, path, buf, size); free(path); return res; } int ibv_read_ibdev_sysfs_file(char *buf, size_t size, struct verbs_sysfs_dev *sysfs_dev, const char *fnfmt, ...) { char *path; va_list va; int res; if (!sysfs_dev) { errno = EINVAL; return -1; } va_start(va, fnfmt); if (vasprintf(&path, fnfmt, va) < 0) { va_end(va); return -1; } va_end(va); res = ibv_read_sysfs_file(sysfs_dev->ibdev_path, path, buf, size); free(path); return res; }