|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Copyright (c) 2008, Intel Corporation.
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* This program is free software; you can redistribute it and/or modify it
|
|
Packit Service |
35c908 |
* under the terms and conditions of the GNU Lesser General Public License,
|
|
Packit Service |
35c908 |
* version 2.1, as published by the Free Software Foundation.
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
Packit Service |
35c908 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
Packit Service |
35c908 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
|
Packit Service |
35c908 |
* for more details.
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit Service |
35c908 |
* along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
Packit Service |
35c908 |
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
#include "utils.h"
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Read a line from the specified file in the specified directory
|
|
Packit Service |
35c908 |
* into the buffer. The file is opened and closed.
|
|
Packit Service |
35c908 |
* Any trailing white space is trimmed off.
|
|
Packit Service |
35c908 |
* This is useful for accessing /sys files.
|
|
Packit Service |
35c908 |
* Returns 0 or an error number.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
int
|
|
Packit Service |
35c908 |
sa_sys_read_line(const char *dir, const char *file, char *buf, size_t len)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
FILE *fp;
|
|
Packit Service |
35c908 |
char file_name[256];
|
|
Packit Service |
35c908 |
char *cp;
|
|
Packit Service |
35c908 |
int rc = 0;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
snprintf(file_name, sizeof(file_name), "%s/%s", dir, file);
|
|
Packit Service |
35c908 |
fp = fopen(file_name, "r");
|
|
Packit Service |
35c908 |
if (fp == NULL)
|
|
Packit Service |
35c908 |
rc = -1;
|
|
Packit Service |
35c908 |
else {
|
|
Packit Service |
35c908 |
cp = fgets(buf, len, fp);
|
|
Packit Service |
35c908 |
if (cp == NULL) {
|
|
Packit Service |
35c908 |
fprintf(stderr,
|
|
Packit Service |
35c908 |
"%s: read error or empty file %s,"
|
|
Packit Service |
35c908 |
" errno=0x%x\n", __func__,
|
|
Packit Service |
35c908 |
file_name, errno);
|
|
Packit Service |
35c908 |
rc = -1;
|
|
Packit Service |
35c908 |
} else {
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Trim off trailing newline or other white space.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
cp = buf + strlen(buf);
|
|
Packit Service |
35c908 |
while (--cp >= buf && isspace(*cp))
|
|
Packit Service |
35c908 |
*cp = '\0';
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
fclose(fp);
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
return rc;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Write a string to the specified file in the specified directory.
|
|
Packit Service |
35c908 |
* The file is opened and closed.
|
|
Packit Service |
35c908 |
* The string has a new-line appended to it.
|
|
Packit Service |
35c908 |
* This is useful for accessing /sys files.
|
|
Packit Service |
35c908 |
* Returns 0 or an error number.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
int
|
|
Packit Service |
35c908 |
sa_sys_write_line(const char *dir, const char *file, const char *string)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
FILE *fp;
|
|
Packit Service |
35c908 |
char file_name[256];
|
|
Packit Service |
35c908 |
int rc = 0;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
snprintf(file_name, sizeof(file_name), "%s/%s", dir, file);
|
|
Packit Service |
35c908 |
fp = fopen(file_name, "w");
|
|
Packit Service |
35c908 |
if (fp == NULL) {
|
|
Packit Service |
35c908 |
fprintf(stderr, "%s: fopen of %s failed, errno=0x%x\n",
|
|
Packit Service |
35c908 |
__func__, file_name, errno);
|
|
Packit Service |
35c908 |
rc = -1;
|
|
Packit Service |
35c908 |
} else {
|
|
Packit Service |
35c908 |
rc = fprintf(fp, "%s\n", string);
|
|
Packit Service |
35c908 |
if (rc < 0)
|
|
Packit Service |
35c908 |
fprintf(stderr,
|
|
Packit Service |
35c908 |
"%s: write to %s of %s failed, errno=0x%x\n",
|
|
Packit Service |
35c908 |
__func__, file_name, string, errno);
|
|
Packit Service |
35c908 |
fclose(fp);
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
return rc;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
int
|
|
Packit Service |
35c908 |
sa_sys_read_u32(const char *dir, const char *file, u_int32_t *vp)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
char buf[256];
|
|
Packit Service |
35c908 |
int rc;
|
|
Packit Service |
35c908 |
u_int32_t val;
|
|
Packit Service |
35c908 |
char *endptr;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
rc = sa_sys_read_line(dir, file, buf, sizeof(buf));
|
|
Packit Service |
35c908 |
if (rc == 0) {
|
|
Packit Service |
35c908 |
val = strtoul(buf, &endptr, 0);
|
|
Packit Service |
35c908 |
if (*endptr != '\0') {
|
|
Packit Service |
35c908 |
fprintf(stderr,
|
|
Packit Service |
35c908 |
"%s: parse error. file %s/%s line '%s'\n",
|
|
Packit Service |
35c908 |
__func__, dir, file, buf);
|
|
Packit Service |
35c908 |
rc = -1;
|
|
Packit Service |
35c908 |
} else
|
|
Packit Service |
35c908 |
*vp = val;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
return rc;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
int
|
|
Packit Service |
35c908 |
sa_sys_read_u64(const char *dir, const char *file, u_int64_t *vp)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
char buf[256];
|
|
Packit Service |
35c908 |
int rc;
|
|
Packit Service |
35c908 |
u_int64_t val;
|
|
Packit Service |
35c908 |
char *endptr;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
rc = sa_sys_read_line(dir, file, buf, sizeof(buf));
|
|
Packit Service |
35c908 |
if (rc == 0) {
|
|
Packit Service |
35c908 |
val = strtoull(buf, &endptr, 0);
|
|
Packit Service |
35c908 |
if (*endptr != '\0') {
|
|
Packit Service |
35c908 |
fprintf(stderr,
|
|
Packit Service |
35c908 |
"%s: parse error. file %s/%s line '%s'\n",
|
|
Packit Service |
35c908 |
__func__, dir, file, buf);
|
|
Packit Service |
35c908 |
rc = -1;
|
|
Packit Service |
35c908 |
} else
|
|
Packit Service |
35c908 |
*vp = val;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
return rc;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Make a printable NUL-terminated copy of the string.
|
|
Packit Service |
35c908 |
* The source buffer might not be NUL-terminated.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
char *
|
|
Packit Service |
35c908 |
sa_strncpy_safe(char *dest, size_t len, const char *src, size_t src_len)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
char *dp = dest;
|
|
Packit Service |
35c908 |
const char *sp = src;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
while (len-- > 1 && src_len-- > 0 && *sp != '\0') {
|
|
Packit Service |
35c908 |
*dp++ = isprint(*sp) ? *sp : (isspace(*sp) ? ' ' : '.');
|
|
Packit Service |
35c908 |
sp++;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
*dp = '\0';
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Take off trailing blanks.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
while (--dp >= dest && isspace(*dp))
|
|
Packit Service |
35c908 |
*dp = '\0';
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
return dest;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/** sa_enum_encode(tp, name, valp)
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* @param tp pointer to table of names and values, struct sa_nameval.
|
|
Packit Service |
35c908 |
* @param name string to be encoded into a value
|
|
Packit Service |
35c908 |
* @returns zero on success, non-zero if no matching string found.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
int
|
|
Packit Service |
35c908 |
sa_enum_encode(const struct sa_nameval *tp, const char *name, u_int32_t *valp)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
for (; tp->nv_name != NULL; tp++) {
|
|
Packit Service |
35c908 |
if (strcasecmp(tp->nv_name, name) == 0) {
|
|
Packit Service |
35c908 |
*valp = tp->nv_val;
|
|
Packit Service |
35c908 |
return 0;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
return -1;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/** sa_enum_decode(buf, len, tp, val)
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* @param buf buffer for result (may be used or not).
|
|
Packit Service |
35c908 |
* @param len size of buffer (at least 32 bytes recommended).
|
|
Packit Service |
35c908 |
* @param tp pointer to table of names and values, struct sa_nameval.
|
|
Packit Service |
35c908 |
* @param val value to be decoded into a name.
|
|
Packit Service |
35c908 |
* @returns pointer to name string. Unknown values are put into buffer in hex.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
const char *
|
|
Packit Service |
35c908 |
sa_enum_decode(char *buf, size_t len,
|
|
Packit Service |
35c908 |
const struct sa_nameval *tp, u_int32_t val)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
for (; tp->nv_name != NULL; tp++) {
|
|
Packit Service |
35c908 |
if (tp->nv_val == val)
|
|
Packit Service |
35c908 |
return tp->nv_name;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
snprintf(buf, len, "Unknown (code 0x%X)", val);
|
|
Packit Service |
35c908 |
return buf;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Read through a directory and call a function for each entry.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
int
|
|
Packit Service |
35c908 |
sa_dir_read(char *dir_name, int (*func)(struct dirent *dp, void *), void *arg)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
DIR *dir;
|
|
Packit Service |
35c908 |
struct dirent *dp;
|
|
Packit Service |
35c908 |
int error = 0;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
dir = opendir(dir_name);
|
|
Packit Service |
35c908 |
if (dir == NULL)
|
|
Packit Service |
35c908 |
error = errno;
|
|
Packit Service |
35c908 |
else {
|
|
Packit Service |
35c908 |
while ((dp = readdir(dir)) != NULL && error == 0) {
|
|
Packit Service |
35c908 |
if (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' ||
|
|
Packit Service |
35c908 |
(dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
|
|
Packit Service |
35c908 |
continue;
|
|
Packit Service |
35c908 |
error = (*func)(dp, arg);
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
closedir(dir);
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
return error;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/*
|
|
Packit Service |
35c908 |
* Size of on-stack line buffers.
|
|
Packit Service |
35c908 |
* These shouldn't be to large for a kernel stack frame.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
#define SA_LOG_BUF_LEN 200 /* on-stack line buffer size */
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
static const u_int32_t sa_table_growth = 16; /* entries to grow by */
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/** sa_table_grow(tp, index) - add space to a table for index.
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* @param tp pointer to sa_table structure.
|
|
Packit Service |
35c908 |
* @param index - new index past the end of the current table.
|
|
Packit Service |
35c908 |
* @returns new index, or -1 if table couldn't be grown.
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* Note: if the table has never been used, and is still all zero, this works.
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* Note: perhaps not safe for multithreading. Caller can lock the table
|
|
Packit Service |
35c908 |
* externally, but reallocation can take a while, during which time the
|
|
Packit Service |
35c908 |
* caller may not wish to hold the lock.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
int
|
|
Packit Service |
35c908 |
sa_table_grow(struct sa_table *tp, u_int32_t index)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
u_int32_t new_size;
|
|
Packit Service |
35c908 |
void **ap;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
if (index >= tp->st_size) {
|
|
Packit Service |
35c908 |
new_size = index + sa_table_growth;
|
|
Packit Service |
35c908 |
ap = realloc(tp->st_table, new_size * sizeof(*ap));
|
|
Packit Service |
35c908 |
if (ap == NULL)
|
|
Packit Service |
35c908 |
return -1;
|
|
Packit Service |
35c908 |
memset(ap + tp->st_size, 0,
|
|
Packit Service |
35c908 |
(new_size - tp->st_size) * sizeof(*ap));
|
|
Packit Service |
35c908 |
tp->st_table = ap;
|
|
Packit Service |
35c908 |
tp->st_size = new_size;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
tp->st_limit = index + 1;
|
|
Packit Service |
35c908 |
return index;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/** sa_table_destroy(tp) - free memory used by table.
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* @param tp pointer to sa_table structure.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
void
|
|
Packit Service |
35c908 |
sa_table_destroy(struct sa_table *tp)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
if (tp->st_table) {
|
|
Packit Service |
35c908 |
free(tp->st_table);
|
|
Packit Service |
35c908 |
tp->st_table = NULL;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
tp->st_limit = 0;
|
|
Packit Service |
35c908 |
tp->st_size = 0;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/** sa_table_destroy_all(tp) - free memory used by table, including entries.
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* @param tp pointer to sa_table structure.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
void
|
|
Packit Service |
35c908 |
sa_table_destroy_all(struct sa_table *tp)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
int i;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
if (tp->st_table) {
|
|
Packit Service |
35c908 |
for (i = 0; i < tp->st_limit; i++) {
|
|
Packit Service |
35c908 |
if (tp->st_table[i]) {
|
|
Packit Service |
35c908 |
free(tp->st_table[i]);
|
|
Packit Service |
35c908 |
tp->st_table[i] = NULL;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
sa_table_destroy(tp);
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/** sa_table_iterate(tp, handler, arg)
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* @param tp pointer to sa_table structure.
|
|
Packit Service |
35c908 |
* @param handler function to be called for each non-NULL entry.
|
|
Packit Service |
35c908 |
* @param arg argument for function.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
void
|
|
Packit Service |
35c908 |
sa_table_iterate(struct sa_table *tp,
|
|
Packit Service |
35c908 |
void (*handler)(void *ep, void *arg),
|
|
Packit Service |
35c908 |
void *arg)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
int i;
|
|
Packit Service |
35c908 |
void *ep;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
for (i = 0; i < tp->st_limit; i++) {
|
|
Packit Service |
35c908 |
ep = tp->st_table[i];
|
|
Packit Service |
35c908 |
if (ep != NULL)
|
|
Packit Service |
35c908 |
(*handler)(ep, arg);
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
/** sa_table_search(tp, match, arg)
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* @param tp pointer to sa_table structure.
|
|
Packit Service |
35c908 |
* @param match function to compare entries with arg and
|
|
Packit Service |
35c908 |
* return non-NULL if match.
|
|
Packit Service |
35c908 |
* @param arg argument for match function.
|
|
Packit Service |
35c908 |
*
|
|
Packit Service |
35c908 |
* Note that the value found could actually be something not in the table
|
|
Packit Service |
35c908 |
* if the match function is doing something clever, like returning a
|
|
Packit Service |
35c908 |
* sub-structure of the table entry.
|
|
Packit Service |
35c908 |
*/
|
|
Packit Service |
35c908 |
void *
|
|
Packit Service |
35c908 |
sa_table_search(struct sa_table *tp, void *(*match)(void *ep, void *arg),
|
|
Packit Service |
35c908 |
void *arg)
|
|
Packit Service |
35c908 |
{
|
|
Packit Service |
35c908 |
int i;
|
|
Packit Service |
35c908 |
void *found = NULL;
|
|
Packit Service |
35c908 |
void *ep;
|
|
Packit Service |
35c908 |
|
|
Packit Service |
35c908 |
for (i = 0; i < tp->st_limit; i++) {
|
|
Packit Service |
35c908 |
ep = tp->st_table[i];
|
|
Packit Service |
35c908 |
if (ep != NULL) {
|
|
Packit Service |
35c908 |
found = (*match)(ep, arg);
|
|
Packit Service |
35c908 |
if (found != NULL)
|
|
Packit Service |
35c908 |
break;
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
}
|
|
Packit Service |
35c908 |
return found;
|
|
Packit Service |
35c908 |
}
|