do not edit — generated by btf.
git.druid.rocksindexdruid520qsrc/conf.c

src/conf.c


#include "config.h"
 
#ifdef OS_NETBSD_C
#define _NETBSD_SOURCE 1
#endif
#define _POSIX_C_SOURCE 200809L
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
 
#include "q.h"
 
/* a key="value" line grammar (value must be double-quoted) -- the same
 * grammar q's recipes use for their name="..." / ver="..." header lines,
 * so one parser serves recipe metadata. */
long
parseconf(const char* buf, long n, struct kv* kv, long max)
{
	long i = 0;
	long nkv = 0;
	long ki;
	long vi;
 
	while(i < n && nkv < max)
	{
		ki = 0;
		while(i < n && buf[i] != '=' && buf[i] != '\n' && ki < MAXKEY - 1)
		{
			kv[nkv].key[ki] = buf[i];
			ki = ki + 1;
			i = i + 1;
		}
		kv[nkv].key[ki] = '\0';
		while(i < n && buf[i] != '\n' && buf[i] != '"')
		{
			i = i + 1;
		}
		if(i < n && buf[i] == '"')
		{
			i = i + 1;
			vi = 0;
			while(i < n && buf[i] != '"' && buf[i] != '\n' && vi < MAXVAL - 1)
			{
				kv[nkv].val[vi] = buf[i];
				vi = vi + 1;
				i = i + 1;
			}
			kv[nkv].val[vi] = '\0';
			if(kv[nkv].key[0] != '\0')
			{
				nkv = nkv + 1;
			}
		}
		while(i < n && buf[i] != '\n')
		{
			i = i + 1;
		}
		if(i < n)
		{
			i = i + 1;
		}
	}
	return nkv;
}
 
const char*
kvget(struct kv* kv, long nkv, const char* key)
{
	long i = 0;
 
	while(i < nkv)
	{
		if(strcmp(kv[i].key, key) == 0)
		{
			return kv[i].val;
		}
		i = i + 1;
	}
	return NULL;
}
 
/* strip trailing newlines (and a stray \r) off a line read from the
 * config dump. */
static void
chomp(char* s)
{
	size_t n = strlen(s);
 
	while(n > 0 && (s[n - 1] == '\n' || s[n - 1] == '\r'))
	{
		s[n - 1] = '\0';
		n = n - 1;
	}
}
 
/* resolve the effective prefix/db/shell/pkgs. /etc/q.cfg (or $Q_CONF) is
 * a posix shell script -- the "configure the package manager in general"
 * file, so it can hold functions, conditionals, or exports, not just a
 * fixed key=value grammar. it is sourced once here (via a shell) to read
 * the four values it may set, then sourced again into every recipe by
 * runrecipe. anything a config doesn't set falls back to the defaults;
 * the Q_PREFIX/Q_DB/Q_SHELL/Q_PKGS environment variables override both. */
void
loadcfg(struct qcfg* c)
{
	const char* confpath;
	const char* v;
	static const char qcmd[] =
	    ". \"$Q_CONF_PATH\"; printf '%s\\n' \"${prefix-}\" \"${db-}\" "
	    "\"${shell-}\" \"${pkgs-}\"";
 
	confpath = getenv("Q_CONF");
	if(confpath == NULL || confpath[0] == '\0')
	{
		confpath = "/etc/q.cfg";
	}
	c->prefix[0] = '\0';
	c->db[0] = '\0';
	c->shell[0] = '\0';
	c->pkgs[0] = '\0';
	if(copystr(c->conf, sizeof(c->conf), confpath) == 0)
	{
		die("config path too long");
		return;
	}
 
	/* a missing config is silently optional (plenty of setups run on
	 * pure defaults); a present one is sourced through the shell so its
	 * prefix/db/shell/pkgs -- each possibly empty if unset -- come back
	 * as four lines, and defaulting happens here in c rather than in the
	 * shell, so the defaults live in exactly one place. */
	if(access(confpath, F_OK) == 0)
	{
		FILE* f;
 
		setenv("Q_CONF_PATH", confpath, 1);
		f = popen(qcmd, "r");
		if(f != NULL)
		{
			char buf[MAXPATH];
 
			if(fgets(buf, sizeof(buf), f) != NULL)
			{
				chomp(buf);
				if(copystr(c->prefix, sizeof(c->prefix), buf) == 0)
				{
					die("prefix too long");
					return;
				}
			}
			if(fgets(buf, sizeof(buf), f) != NULL)
			{
				chomp(buf);
				if(copystr(c->db, sizeof(c->db), buf) == 0)
				{
					die("db path too long");
					return;
				}
			}
			if(fgets(buf, sizeof(buf), f) != NULL)
			{
				chomp(buf);
				if(copystr(c->shell, sizeof(c->shell), buf) == 0)
				{
					die("shell path too long");
					return;
				}
			}
			if(fgets(buf, sizeof(buf), f) != NULL)
			{
				chomp(buf);
				if(copystr(c->pkgs, sizeof(c->pkgs), buf) == 0)
				{
					die("pkgs path too long");
					return;
				}
			}
			pclose(f);
		}
	}
 
	/* the environment wins over the file, so a single invocation can
	 * point q at a scratch prefix without touching the config. */
	v = getenv("Q_PREFIX");
	if(v != NULL && v[0] != '\0')
	{
		if(copystr(c->prefix, sizeof(c->prefix), v) == 0)
		{
			die("prefix too long");
			return;
		}
	}
	v = getenv("Q_DB");
	if(v != NULL && v[0] != '\0')
	{
		if(copystr(c->db, sizeof(c->db), v) == 0)
		{
			die("db path too long");
			return;
		}
	}
	v = getenv("Q_SHELL");
	if(v != NULL && v[0] != '\0')
	{
		if(copystr(c->shell, sizeof(c->shell), v) == 0)
		{
			die("shell path too long");
			return;
		}
	}
	v = getenv("Q_PKGS");
	if(v != NULL && v[0] != '\0')
	{
		if(copystr(c->pkgs, sizeof(c->pkgs), v) == 0)
		{
			die("pkgs path too long");
			return;
		}
	}
 
	if(c->prefix[0] == '\0')
	{
		copystr(c->prefix, sizeof(c->prefix), "/usr/local");
	}
	if(c->db[0] == '\0')
	{
		pathjoin(c->db, sizeof(c->db), c->prefix, "var/db/q");
	}
	if(c->shell[0] == '\0')
	{
		copystr(c->shell, sizeof(c->shell), "/bin/sh");
	}
	if(c->pkgs[0] == '\0')
	{
		pathjoin(c->pkgs, sizeof(c->pkgs), c->prefix, "pkgs");
	}
}
powered by btf.