1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2008 Voltaire Inc. All rights reserved. 3219820Sjeff * 4219820Sjeff * This software is available to you under a choice of one of two 5219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 6219820Sjeff * General Public License (GPL) Version 2, available from the file 7219820Sjeff * COPYING in the main directory of this source tree, or the 8219820Sjeff * OpenIB.org BSD license below: 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or 11219820Sjeff * without modification, are permitted provided that the following 12219820Sjeff * conditions are met: 13219820Sjeff * 14219820Sjeff * - Redistributions of source code must retain the above 15219820Sjeff * copyright notice, this list of conditions and the following 16219820Sjeff * disclaimer. 17219820Sjeff * 18219820Sjeff * - Redistributions in binary form must reproduce the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer in the documentation and/or other materials 21219820Sjeff * provided with the distribution. 22219820Sjeff * 23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219820Sjeff * SOFTWARE. 31219820Sjeff * 32219820Sjeff */ 33219820Sjeff 34219820Sjeff#define _GNU_SOURCE 35219820Sjeff 36219820Sjeff#if HAVE_CONFIG_H 37219820Sjeff# include <config.h> 38219820Sjeff#endif /* HAVE_CONFIG_H */ 39219820Sjeff 40219820Sjeff#include <inttypes.h> 41219820Sjeff#include <string.h> 42219820Sjeff#include <errno.h> 43219820Sjeff#include <stdio.h> 44219820Sjeff#include <stdlib.h> 45219820Sjeff#include <unistd.h> 46219820Sjeff#include <stdarg.h> 47219820Sjeff#include <sys/types.h> 48219820Sjeff#include <sys/stat.h> 49219820Sjeff#include <fcntl.h> 50219820Sjeff#include <sys/ioctl.h> 51219820Sjeff#include <unistd.h> 52219820Sjeff#include <string.h> 53219820Sjeff#include <endian.h> 54219820Sjeff#include <byteswap.h> 55219820Sjeff#include <sys/poll.h> 56219820Sjeff#include <syslog.h> 57219820Sjeff#include <netinet/in.h> 58219820Sjeff#include <errno.h> 59219820Sjeff 60219820Sjeff#include <sys/types.h> 61219820Sjeff#include <sys/sysctl.h> 62219820Sjeff 63219820Sjeff#include "common.h" 64219820Sjeff 65219820Sjeffstatic int 66219820Sjeffret_code(void) 67219820Sjeff{ 68219820Sjeff int e = errno; 69219820Sjeff 70219820Sjeff if (e > 0) 71219820Sjeff return -e; 72219820Sjeff return e; 73219820Sjeff} 74219820Sjeff 75219820Sjeffint 76219820Sjeffsys_read_string(char *dir_name, char *file_name, char *str, int max_len) 77219820Sjeff{ 78219820Sjeff char path[256], *s; 79219820Sjeff size_t len; 80219820Sjeff 81219820Sjeff snprintf(path, sizeof(path), "%s/%s", dir_name, file_name); 82219820Sjeff 83219820Sjeff for (s = &path[0]; *s != '\0'; s++) 84219820Sjeff if (*s == '/') 85219820Sjeff *s = '.'; 86219820Sjeff 87219820Sjeff len = max_len; 88219820Sjeff if (sysctlbyname(&path[1], str, &len, NULL, 0) == -1) 89219820Sjeff return ret_code(); 90219820Sjeff 91219820Sjeff str[(len < max_len) ? len : max_len - 1] = 0; 92219820Sjeff 93219820Sjeff if ((s = strrchr(str, '\n'))) 94219820Sjeff *s = 0; 95219820Sjeff 96219820Sjeff return 0; 97219820Sjeff} 98219820Sjeff 99219820Sjeffint 100219820Sjeffsys_read_guid(char *dir_name, char *file_name, uint64_t *net_guid) 101219820Sjeff{ 102219820Sjeff char buf[32], *str, *s; 103219820Sjeff uint64_t guid; 104219820Sjeff int r, i; 105219820Sjeff 106219820Sjeff if ((r = sys_read_string(dir_name, file_name, buf, sizeof(buf))) < 0) 107219820Sjeff return r; 108219820Sjeff 109219820Sjeff guid = 0; 110219820Sjeff 111219820Sjeff for (s = buf, i = 0 ; i < 4; i++) { 112219820Sjeff if (!(str = strsep(&s, ": \t\n"))) 113219820Sjeff return -EINVAL; 114219820Sjeff guid = (guid << 16) | (strtoul(str, 0, 16) & 0xffff); 115219820Sjeff } 116219820Sjeff 117219820Sjeff *net_guid = htonll(guid); 118219820Sjeff 119219820Sjeff return 0; 120219820Sjeff} 121219820Sjeff 122219820Sjeffint 123219820Sjeffsys_read_gid(char *dir_name, char *file_name, uint8_t *gid) 124219820Sjeff{ 125219820Sjeff char buf[64], *str, *s; 126219820Sjeff uint16_t *ugid = (uint16_t *)gid; 127219820Sjeff int r, i; 128219820Sjeff 129219820Sjeff if ((r = sys_read_string(dir_name, file_name, buf, sizeof(buf))) < 0) 130219820Sjeff return r; 131219820Sjeff 132219820Sjeff for (s = buf, i = 0 ; i < 8; i++) { 133219820Sjeff if (!(str = strsep(&s, ": \t\n"))) 134219820Sjeff return -EINVAL; 135219820Sjeff ugid[i] = htons(strtoul(str, 0, 16) & 0xffff); 136219820Sjeff } 137219820Sjeff 138219820Sjeff return 0; 139219820Sjeff} 140219820Sjeff 141219820Sjeffint 142219820Sjeffsys_read_uint64(char *dir_name, char *file_name, uint64_t *u) 143219820Sjeff{ 144219820Sjeff char buf[32]; 145219820Sjeff int r; 146219820Sjeff 147219820Sjeff if ((r = sys_read_string(dir_name, file_name, buf, sizeof(buf))) < 0) 148219820Sjeff return r; 149219820Sjeff 150219820Sjeff *u = strtoull(buf, 0, 0); 151219820Sjeff 152219820Sjeff return 0; 153219820Sjeff} 154219820Sjeff 155219820Sjeffint 156219820Sjeffsys_read_uint(char *dir_name, char *file_name, unsigned *u) 157219820Sjeff{ 158219820Sjeff char buf[32]; 159219820Sjeff int r; 160219820Sjeff 161219820Sjeff if ((r = sys_read_string(dir_name, file_name, buf, sizeof(buf))) < 0) 162219820Sjeff return r; 163219820Sjeff 164219820Sjeff *u = strtoul(buf, 0, 0); 165219820Sjeff 166219820Sjeff return 0; 167219820Sjeff} 168219820Sjeff 169219820Sjeff#define DIRECTSIZ(namlen) \ 170219820Sjeff (((uintptr_t)&((struct dirent *)0)->d_name + \ 171219820Sjeff ((namlen)+1)*sizeof(((struct dirent *)0)->d_name[0]) + 3) & ~3) 172219820Sjeff 173219820Sjeffint 174219820Sjeffsys_scandir(const char *dirname, struct dirent ***namelist, 175219820Sjeff int (*select)(const struct dirent *), 176219820Sjeff int (*compar)(const struct dirent **, const struct dirent **)) 177219820Sjeff{ 178219820Sjeff struct dirent **names; 179219820Sjeff struct dirent **names2; 180219820Sjeff struct dirent *dp; 181219820Sjeff char name[1024]; 182219820Sjeff int lsname[22]; 183219820Sjeff int chname[22]; 184219820Sjeff int name2[22]; 185219820Sjeff int oid[22]; 186219820Sjeff char *s; 187219820Sjeff size_t n1, n2; 188219820Sjeff size_t len, oidlen, namlen; 189219820Sjeff int cnt, max; 190219820Sjeff int err; 191219820Sjeff int i; 192219820Sjeff 193219820Sjeff *namelist = NULL; 194219820Sjeff /* Skip the leading / */ 195219820Sjeff strncpy(name, &dirname[1], sizeof(name)); 196219820Sjeff for (s = &name[0]; *s != '\0'; s++) 197219820Sjeff if (*s == '/') 198219820Sjeff *s = '.'; 199219820Sjeff /* 200219820Sjeff * Resolve the path. 201219820Sjeff */ 202219820Sjeff len = sizeof(oid) / sizeof(int); 203219820Sjeff namlen = strlen(name) + 1; 204219820Sjeff if (sysctlnametomib(name, oid, &len) != 0) 205219820Sjeff return (-errno); 206219820Sjeff lsname[0] = 0; /* Root */ 207219820Sjeff lsname[1] = 2; /* Get next */ 208219820Sjeff memcpy(lsname+2, oid, len * sizeof(int)); 209219820Sjeff n1 = 2 + len; 210219820Sjeff oidlen = len; 211219820Sjeff /* 212219820Sjeff * Setup the return list of dirents. 213219820Sjeff */ 214219820Sjeff cnt = 0; 215219820Sjeff max = 64; 216219820Sjeff names = malloc(max * sizeof(void *)); 217219820Sjeff if (names == NULL) 218219820Sjeff return (-ENOMEM); 219219820Sjeff 220219820Sjeff for (;;) { 221219820Sjeff n2 = sizeof(name2); 222219820Sjeff if (sysctl(lsname, n1, name2, &n2, 0, 0) < 0) { 223219820Sjeff if (errno == ENOENT) 224219820Sjeff break; 225219820Sjeff goto errout; 226219820Sjeff } 227219820Sjeff n2 /= sizeof(int); 228219820Sjeff if (n2 < oidlen) 229219820Sjeff break; 230219820Sjeff for (i = 0; i < oidlen; i++) 231219820Sjeff if (name2[i] != oid[i]) 232219820Sjeff goto out; 233219820Sjeff chname[0] = 0; /* root */ 234219820Sjeff chname[1] = 1; /* oid name */ 235219820Sjeff memcpy(chname + 2, name2, n2 * sizeof(int)); 236219820Sjeff memcpy(lsname + 2, name2, n2 * sizeof(int)); 237219820Sjeff n1 = 2 + n2; 238219820Sjeff /* 239219820Sjeff * scandir() is not supposed to go deeper than the requested 240219820Sjeff * directory but sysctl also doesn't return a node for 241219820Sjeff * 'subdirectories' so we have to find a file in the subdir 242219820Sjeff * and then truncate the name to report it. 243219820Sjeff */ 244219820Sjeff if (n2 > oidlen + 1) { 245219820Sjeff /* Skip to the next name after this one. */ 246219820Sjeff n1 = 2 + oidlen + 1; 247219820Sjeff lsname[n1 - 1]++; 248219820Sjeff } 249219820Sjeff len = sizeof(name); 250219820Sjeff if (sysctl(chname, n2 + 2, name, &len, 0, 0) < 0) 251219820Sjeff goto errout; 252219820Sjeff if (len <= 0 || len < namlen) 253219820Sjeff goto out; 254219820Sjeff s = name + namlen; 255219820Sjeff /* Just keep the first level name. */ 256219820Sjeff if (strchr(s, '.')) 257219820Sjeff *strchr(s, '.') = '\0'; 258219820Sjeff len = strlen(s) + 1; 259219820Sjeff dp = malloc(DIRECTSIZ(len)); 260219820Sjeff dp->d_reclen = DIRECTSIZ(len); 261219820Sjeff dp->d_namlen = len; 262219820Sjeff memcpy(&dp->d_name, s, len); 263219820Sjeff if (select && !select(dp)) { 264219820Sjeff free(dp); 265219820Sjeff continue; 266219820Sjeff } 267219820Sjeff if (cnt == max) { 268219820Sjeff max *= 2; 269219820Sjeff names2 = realloc(names, max * sizeof(void *)); 270219820Sjeff if (names2 == NULL) { 271219820Sjeff errno = ENOMEM; 272219820Sjeff free(dp); 273219820Sjeff goto errout; 274219820Sjeff } 275219820Sjeff names = names2; 276219820Sjeff } 277219820Sjeff names[cnt++] = dp; 278219820Sjeff } 279219820Sjeffout: 280219820Sjeff if (cnt && compar) 281219820Sjeff qsort(names, cnt, sizeof(struct dirent *), 282219820Sjeff (int (*)(const void *, const void *))compar); 283219820Sjeff 284219820Sjeff *namelist = names; 285219820Sjeff 286219820Sjeff return (cnt); 287219820Sjeff 288219820Sjefferrout: 289219820Sjeff err = errno; 290219820Sjeff for (i = 0; i < cnt; i++) 291219820Sjeff free(names[i]); 292219820Sjeff free(names); 293219820Sjeff return (-err); 294219820Sjeff} 295