Blame utils.c

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
}