Blame lib/macros.c

Packit 8480eb
/* ----------------------------------------------------------------------- *
Packit 8480eb
 *   
Packit 8480eb
 *  macros.c - module to handle macro substitution variables for map
Packit 8480eb
 *		entries.
Packit 8480eb
 * 
Packit 8480eb
 *   Copyright 2006 Ian Kent <raven@themaw.net>
Packit 8480eb
 *
Packit 8480eb
 *   This program is free software; you can redistribute it and/or modify
Packit 8480eb
 *   it under the terms of the GNU General Public License as published by
Packit 8480eb
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
Packit 8480eb
 *   USA; either version 2 of the License, or (at your option) any later
Packit 8480eb
 *   version; incorporated herein by reference.
Packit 8480eb
 *
Packit 8480eb
 * ----------------------------------------------------------------------- */
Packit 8480eb
Packit 8480eb
#include <malloc.h>
Packit 8480eb
#include <stdlib.h>
Packit 8480eb
#include <string.h>
Packit 8480eb
#include <limits.h>
Packit 8480eb
#include <sys/utsname.h>
Packit 8480eb
#include <unistd.h>
Packit 8480eb
Packit 8480eb
#include "automount.h"
Packit 8480eb
Packit 8480eb
static struct utsname un;
Packit 8480eb
static char processor[65];		/* Not defined on Linux, so we make our own */
Packit 8480eb
static char hostname[HOST_NAME_MAX + 1];
Packit 8480eb
static char host[HOST_NAME_MAX];
Packit 8480eb
static char domain[HOST_NAME_MAX];
Packit 8480eb
static char hostd[HOST_NAME_MAX + 1];
Packit 8480eb
static char endian[] = "unknown";
Packit 8480eb
Packit 8480eb
/* Predefined variables: tail of link chain */
Packit 8480eb
static struct substvar
Packit 8480eb
	sv_arch   = {"ARCH",   un.machine,  1, NULL },
Packit 8480eb
	sv_cpu    = {"CPU",    processor,   1, &sv_arch},
Packit 8480eb
	sv_host   = {"HOST",   un.nodename, 1, &sv_cpu},
Packit 8480eb
	sv_osname = {"OSNAME", un.sysname,  1, &sv_host},
Packit 8480eb
	sv_osrel  = {"OSREL",  un.release,  1, &sv_osname},
Packit 8480eb
	sv_osvers = {"OSVERS", un.version,  1, &sv_osrel},
Packit 8480eb
	sv_dollar = {"dollar", "$",         1, &sv_osvers},
Packit 8480eb
	sv_true   = {"true",   "1",         1, &sv_dollar},
Packit 8480eb
	sv_false  = {"false",  "0",         1, &sv_true},
Packit 8480eb
	sv_byte	  = {"byte",   endian,	    1, &sv_false},
Packit 8480eb
	sv_host2  = {"host",   host,        1, &sv_byte},
Packit 8480eb
	sv_xhost  = {"xhost",  host,	    1, &sv_host2},
Packit 8480eb
	sv_domain = {"domain", domain,      1, &sv_xhost},
Packit 8480eb
	sv_hostd  = {"hostd",  hostd,       1, &sv_domain
Packit 8480eb
};
Packit 8480eb
Packit 8480eb
static struct substvar *system_table = &sv_hostd;
Packit 8480eb
static unsigned int macro_init_done = 0;
Packit 8480eb
Packit 8480eb
static pthread_mutex_t table_mutex = PTHREAD_MUTEX_INITIALIZER;
Packit 8480eb
static pthread_mutex_t macro_mutex = PTHREAD_MUTEX_INITIALIZER;
Packit 8480eb
Packit 8480eb
void dump_table(struct substvar *table)
Packit 8480eb
{
Packit 8480eb
	struct substvar *lv = table;
Packit 8480eb
	int status;
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_lock(&table_mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	while (lv) {
Packit 8480eb
		logmsg("lv->def %s lv->val %s lv->next %p",
Packit 8480eb
		      lv->def, lv->val, lv->next);
Packit 8480eb
		lv = lv->next;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_unlock(&table_mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/* Get processor information for predefined macro definitions */
Packit 8480eb
void macro_init(void)
Packit 8480eb
{
Packit 8480eb
	char *local_domain;
Packit 8480eb
Packit 8480eb
	memset(hostname, 0, HOST_NAME_MAX + 1);
Packit 8480eb
	memset(host, 0, HOST_NAME_MAX);
Packit 8480eb
	memset(domain, 0, HOST_NAME_MAX);
Packit 8480eb
	memset(hostd, 0, HOST_NAME_MAX + 1);
Packit 8480eb
Packit 8480eb
	macro_lock();
Packit 8480eb
	if (macro_init_done) {
Packit 8480eb
		macro_unlock();
Packit 8480eb
		return;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	uname(&un;;
Packit 8480eb
	/*
Packit 8480eb
	 * uname -p is not defined on Linux.  Make it the same as
Packit 8480eb
	 * uname -m, except make it return i386 on all x86 (x >= 3)
Packit 8480eb
	 */
Packit 8480eb
	strcpy(processor, un.machine);
Packit 8480eb
	if (processor[0] == 'i' && processor[1] >= '3' &&
Packit 8480eb
		!strcmp(processor + 2, "86"))
Packit 8480eb
		processor[1] = '3';
Packit 8480eb
Packit 8480eb
	local_domain = conf_amd_get_sub_domain();
Packit 8480eb
Packit 8480eb
	if (!gethostname(hostname, HOST_NAME_MAX)) {
Packit 8480eb
		char *dot;
Packit 8480eb
		dot = strchr(hostname, '.');
Packit 8480eb
		if (dot) {
Packit 8480eb
			*dot++ = '\0';
Packit 8480eb
			strcpy(domain, dot);
Packit 8480eb
		}
Packit 8480eb
		strcpy(host, hostname);
Packit 8480eb
		strcpy(hostd, host);
Packit 8480eb
		if (*domain || local_domain) {
Packit 8480eb
			strcat(hostd, ".");
Packit 8480eb
			if (!local_domain)
Packit 8480eb
				strcat(hostd, domain);
Packit 8480eb
			else {
Packit 8480eb
				strcat(hostd, local_domain);
Packit 8480eb
				strcpy(domain, local_domain);
Packit 8480eb
			}
Packit 8480eb
		}
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (sizeof(short) == 2) {
Packit 8480eb
		union { short s; char c[sizeof(short)]; } order;
Packit 8480eb
		order.s = 0x0102;
Packit 8480eb
		if (order.c[0] == 1 && order.c[1] == 2)
Packit 8480eb
			strcpy(endian, "big");
Packit 8480eb
		else if (order.c[0] == 2 && order.c[1] == 1)
Packit 8480eb
			strcpy(endian, "little");
Packit 8480eb
		else
Packit 8480eb
			strcpy(endian, "unknown");
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	add_std_amd_vars(system_table);
Packit 8480eb
Packit 8480eb
	macro_init_done = 1;
Packit 8480eb
	macro_unlock();
Packit Service 7419e0
	free(local_domain);
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int macro_is_systemvar(const char *str, int len)
Packit 8480eb
{
Packit 8480eb
	struct substvar *sv;
Packit 8480eb
	int found = 0;
Packit 8480eb
	int status;
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_lock(&table_mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	sv = system_table;
Packit 8480eb
Packit 8480eb
	while (sv) {
Packit 8480eb
		if (!strncmp(str, sv->def, len) && sv->def[len] == '\0') {
Packit 8480eb
			found = 1;
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
		sv = sv->next;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_unlock(&table_mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	return found;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int macro_global_addvar(const char *str, int len, const char *value)
Packit 8480eb
{
Packit 8480eb
	struct substvar *sv;
Packit 8480eb
	int status, ret = 0;
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_lock(&table_mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	sv = system_table;
Packit 8480eb
Packit 8480eb
	while (sv) {
Packit 8480eb
		if (!strncmp(str, sv->def, len) && sv->def[len] == '\0')
Packit 8480eb
			break;
Packit 8480eb
		sv = sv->next;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (sv && !sv->readonly) {
Packit 8480eb
		char *this = malloc(strlen(value) + 1);
Packit 8480eb
		if (!this)
Packit 8480eb
			goto done;
Packit 8480eb
		strcpy(this, value);
Packit 8480eb
		free(sv->val);
Packit 8480eb
		sv->val = this;
Packit 8480eb
		ret = 1;
Packit 8480eb
	} else {
Packit 8480eb
		struct substvar *new;
Packit 8480eb
		char *def, *val;
Packit 8480eb
Packit 8480eb
		def = strdup(str);
Packit 8480eb
		if (!def)
Packit 8480eb
			goto done;
Packit 8480eb
		def[len] = '\0';
Packit 8480eb
Packit 8480eb
		val = strdup(value);
Packit 8480eb
		if (!val) {
Packit 8480eb
			free(def);
Packit 8480eb
			goto done;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		new = malloc(sizeof(struct substvar));
Packit 8480eb
		if (!new) {
Packit 8480eb
			free(def);
Packit 8480eb
			free(val);
Packit 8480eb
			goto done;
Packit 8480eb
		}
Packit 8480eb
		new->def = def;
Packit 8480eb
		new->val = val;
Packit 8480eb
		new->readonly = 0;
Packit 8480eb
		new->next = system_table;
Packit 8480eb
		system_table = new;
Packit 8480eb
		ret =1;
Packit 8480eb
	}
Packit 8480eb
done:
Packit 8480eb
	status = pthread_mutex_unlock(&table_mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	return ret;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
int macro_parse_globalvar(const char *define)
Packit 8480eb
{
Packit 8480eb
	char buf[MAX_MACRO_STRING];
Packit 8480eb
	char *pbuf, *value;
Packit 8480eb
Packit 8480eb
	if (strlen(define) >= MAX_MACRO_STRING)
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	strcpy(buf, define);
Packit 8480eb
Packit 8480eb
	pbuf = buf;
Packit 8480eb
	while (pbuf) {
Packit 8480eb
		if (*pbuf == '=') {
Packit 8480eb
			*pbuf = '\0';
Packit 8480eb
			value = pbuf + 1;
Packit 8480eb
			break;
Packit 8480eb
		}
Packit 8480eb
		pbuf++;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* Macro must have value */
Packit 8480eb
	if (!pbuf)
Packit 8480eb
		return 0;
Packit 8480eb
Packit 8480eb
	return macro_global_addvar(buf, strlen(buf), value);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void macro_lock(void)
Packit 8480eb
{
Packit 8480eb
	int status = pthread_mutex_lock(&macro_mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void macro_unlock(void)
Packit 8480eb
{
Packit 8480eb
	int status = pthread_mutex_unlock(&macro_mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
struct substvar *
Packit 8480eb
macro_addvar(struct substvar *table, const char *str, int len, const char *value)
Packit 8480eb
{
Packit 8480eb
	struct substvar *lv = table;
Packit 8480eb
Packit 8480eb
	while (lv) {
Packit 8480eb
		if (!strncmp(str, lv->def, len) && lv->def[len] == '\0')
Packit 8480eb
			break;
Packit 8480eb
		lv = lv->next;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (lv) {
Packit 8480eb
		const char *val = value ? value : "";
Packit 8480eb
		char *this = malloc(strlen(val) + 1);
Packit 8480eb
		if (!this) {
Packit 8480eb
			lv = table;
Packit 8480eb
			goto done;
Packit 8480eb
		}
Packit 8480eb
		strcpy(this, val);
Packit 8480eb
		free(lv->val);
Packit 8480eb
		lv->val = this;
Packit 8480eb
		if (lv != table)
Packit 8480eb
			lv = table;
Packit 8480eb
	} else {
Packit 8480eb
		struct substvar *new;
Packit 8480eb
		const char *this = value ? value : "";
Packit 8480eb
		char *def, *val;
Packit 8480eb
Packit 8480eb
		def = strdup(str);
Packit 8480eb
		if (!def) {
Packit 8480eb
			lv = table;
Packit 8480eb
			goto done;
Packit 8480eb
		}
Packit 8480eb
		def[len] = '\0';
Packit 8480eb
Packit 8480eb
		val = strdup(this);
Packit 8480eb
		if (!val) {
Packit 8480eb
			lv = table;
Packit 8480eb
			free(def);
Packit 8480eb
			goto done;
Packit 8480eb
		}
Packit 8480eb
Packit 8480eb
		new = malloc(sizeof(struct substvar));
Packit 8480eb
		if (!new) {
Packit 8480eb
			lv = table;
Packit 8480eb
			free(def);
Packit 8480eb
			free(val);
Packit 8480eb
			goto done;
Packit 8480eb
		}
Packit 8480eb
		new->def = def;
Packit 8480eb
		new->val = val;
Packit 8480eb
		new->readonly = 0;
Packit 8480eb
		new->next = table;
Packit 8480eb
		lv = new;
Packit 8480eb
	}
Packit 8480eb
done:
Packit 8480eb
Packit 8480eb
	return lv;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void macro_global_removevar(const char *str, int len)
Packit 8480eb
{
Packit 8480eb
	struct substvar *sv;
Packit 8480eb
	struct substvar *last = NULL;
Packit 8480eb
	int status;
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_lock(&table_mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	sv = system_table;
Packit 8480eb
Packit 8480eb
	while (sv) {
Packit 8480eb
		if (!strncmp(str, sv->def, len) && sv->def[len] == '\0')
Packit 8480eb
			break;
Packit 8480eb
		last = sv;
Packit 8480eb
		sv = sv->next;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (sv && !sv->readonly) {
Packit 8480eb
		if (last)
Packit 8480eb
			last->next = sv->next;
Packit 8480eb
		else
Packit 8480eb
			system_table = sv->next;
Packit 8480eb
		if (sv->def)
Packit 8480eb
			free(sv->def);
Packit 8480eb
		if (sv->val)
Packit 8480eb
			free(sv->val);
Packit 8480eb
		free(sv);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_unlock(&table_mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
struct substvar *
Packit 8480eb
macro_removevar(struct substvar *table, const char *str, int len)
Packit 8480eb
{
Packit 8480eb
	struct substvar *list, *lv;
Packit 8480eb
	struct substvar *last = NULL;
Packit 8480eb
Packit 8480eb
	lv = list = table;
Packit 8480eb
Packit 8480eb
	while (lv) {
Packit 8480eb
		if (!strncmp(str, lv->def, len) && lv->def[len] == '\0')
Packit 8480eb
			break;
Packit 8480eb
		last = lv;
Packit 8480eb
		lv = lv->next;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	if (lv) {
Packit 8480eb
		if (last)
Packit 8480eb
			last->next = lv->next;
Packit 8480eb
		else
Packit 8480eb
			list = lv->next;
Packit 8480eb
		if (lv->def)
Packit 8480eb
			free(lv->def);
Packit 8480eb
		if (lv->val)
Packit 8480eb
			free(lv->val);
Packit 8480eb
		free(lv);
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return list;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void macro_free_global_table(void)
Packit 8480eb
{
Packit 8480eb
	struct substvar *sv;
Packit 8480eb
	struct substvar *next;
Packit 8480eb
	int status;
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_lock(&table_mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	sv = system_table;
Packit 8480eb
Packit 8480eb
	while (sv) {
Packit 8480eb
		if (sv->readonly) {
Packit 8480eb
			sv = sv->next;
Packit 8480eb
			continue;
Packit 8480eb
		}
Packit 8480eb
		next = sv->next;
Packit 8480eb
		if (sv->def)
Packit 8480eb
			free(sv->def);
Packit 8480eb
		if (sv->val)
Packit 8480eb
			free(sv->val);
Packit 8480eb
		free(sv);
Packit 8480eb
		sv = next;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	system_table = &sv_osvers;
Packit 8480eb
Packit 8480eb
	status = pthread_mutex_unlock(&table_mutex);
Packit 8480eb
	if (status)
Packit 8480eb
		fatal(status);
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
void macro_free_table(struct substvar *table)
Packit 8480eb
{
Packit 8480eb
	struct substvar *lv = table;
Packit 8480eb
	struct substvar *next;
Packit 8480eb
Packit 8480eb
	if (!lv)
Packit 8480eb
		return;
Packit 8480eb
Packit 8480eb
	while (lv) {
Packit 8480eb
		next = lv->next;
Packit 8480eb
		if (lv->def)
Packit 8480eb
			free(lv->def);
Packit 8480eb
		if (lv->val)
Packit 8480eb
			free(lv->val);
Packit 8480eb
		free(lv);
Packit 8480eb
		lv = next;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/* Find the $-variable matching a certain string fragment */
Packit 8480eb
const struct substvar *
Packit 8480eb
macro_findvar(const struct substvar *table, const char *str, int len)
Packit 8480eb
{
Packit 8480eb
	const struct substvar *sv = system_table;
Packit 8480eb
	const struct substvar *lv = table;
Packit 8480eb
#ifdef ENABLE_EXT_ENV
Packit 8480eb
	/* holds one env var */
Packit 8480eb
	static struct substvar *lv_var;
Packit 8480eb
	static char *value;
Packit 8480eb
	char etmp[512];
Packit 8480eb
#endif
Packit 8480eb
Packit 8480eb
	/* First try the passed in local table */
Packit 8480eb
	while (lv) {
Packit 8480eb
		if (!strncmp(str, lv->def, len) && lv->def[len] == '\0')
Packit 8480eb
			return lv;
Packit 8480eb
		lv = lv->next;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* Then look in the system wide table */
Packit 8480eb
	while (sv) {
Packit 8480eb
		if (!strncmp(str, sv->def, len) && sv->def[len] == '\0')
Packit 8480eb
			return sv;
Packit 8480eb
		sv = sv->next;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
#ifdef ENABLE_EXT_ENV
Packit 8480eb
	/* builtin and local map failed, try the $ENV */
Packit 8480eb
	memcpy(etmp, str, len);
Packit 8480eb
	etmp[len]='\0';
Packit 8480eb
Packit 8480eb
	if ((value=getenv(etmp)) != NULL) {
Packit 8480eb
		lv_var = macro_addvar((struct substvar *) table, str, len, value);
Packit 8480eb
		return(lv_var);
Packit 8480eb
	}
Packit 8480eb
#endif
Packit 8480eb
Packit 8480eb
	return NULL;
Packit 8480eb
}
Packit 8480eb
Packit 8480eb
/* Set environment from macro variable table */
Packit 8480eb
void macro_setenv(struct substvar *table)
Packit 8480eb
{
Packit 8480eb
	const struct substvar *sv = system_table;
Packit 8480eb
	const struct substvar *lv = table;
Packit 8480eb
Packit 8480eb
	/*
Packit 8480eb
	 * First set environment from global table, matching local
Packit 8480eb
	 * variables will overwrite these.
Packit 8480eb
	 */
Packit 8480eb
	while (sv) {
Packit 8480eb
		if (sv->def)
Packit 8480eb
			setenv(sv->def, sv->val, 1);
Packit 8480eb
		sv = sv->next;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	/* Next set environment from the local table */
Packit 8480eb
	while (lv) {
Packit 8480eb
		if (lv->def)
Packit 8480eb
			setenv(lv->def, lv->val, 1);
Packit 8480eb
		lv = lv->next;
Packit 8480eb
	}
Packit 8480eb
Packit 8480eb
	return;
Packit 8480eb
}