/* $Header: /cvsroot/watchdog/watchdog/src/sundries.c,v 1.2 2006/07/31 09:39:23 meskes Exp $ */

/*
 * Support functions.  Exported functions are prototyped in sundries.h.
 * sundries.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
 *
 * added fcntl locking by Kjetil T. (kjetilho@math.uio.no) - aeb, 950927
 */
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <mntent.h>		/* for MNTTYPE_SWAP */
#include "fstab.h"
#include "sundries.h"

/* String list constructor.  (car() and cdr() are defined in "sundries.h").  */
string_list cons(char *a, const string_list b)
{
	string_list p;

	p = xmalloc(sizeof *p);
	car(p) = a;
	cdr(p) = b;
	return p;
}

char *xstrconcat2(const char *s, const char *t)
{
	char *res;

	if (!s)
		s = "";
	if (!t)
		t = "";
	res = xmalloc(strlen(s) + strlen(t) + 1);
	strcpy(res, s);
	strcat(res, t);
	return res;
}

char *xstrconcat3(const char *s, const char *t, const char *u)
{
	char *res;

	if (!s)
		s = "";
	if (!t)
		t = "";
	if (!u)
		u = "";
	res = xmalloc(strlen(s) + strlen(t) + strlen(u) + 1);
	strcpy(res, s);
	strcat(res, t);
	strcat(res, u);
	return res;
}

char *xstrconcat4(const char *s, const char *t, const char *u, const char *v)
{
	char *res;

	if (!s)
		s = "";
	if (!t)
		t = "";
	if (!u)
		u = "";
	if (!v)
		v = "";
	res = xmalloc(strlen(s) + strlen(t) + strlen(u) + strlen(v) + 1);
	strcpy(res, s);
	strcat(res, t);
	strcat(res, u);
	strcat(res, v);
	return res;
}

/* Call this with SIG_BLOCK to block and SIG_UNBLOCK to unblock.  */
void block_signals(int how)
{
	sigset_t sigs;

	sigfillset(&sigs);
	sigdelset(&sigs, SIGTRAP);
	sigdelset(&sigs, SIGSEGV);
	sigprocmask(how, &sigs, (sigset_t *) 0);
}

/* Non-fatal error.  Print message and return.  */
/* (print the message in a single printf, in an attempt
    to avoid mixing output of several threads) */
void error(const char *fmt, ...)
{
	va_list args;
	char *fmt2;

	if (mount_mount_quiet)
		return;
	fmt2 = xstrconcat2(fmt, "\n");
	va_start(args, fmt);
	vfprintf(stderr, fmt2, args);
	va_end(args);
	free(fmt2);
}

/* Fatal error.  Print message and exit.  */
void die(int err, const char *fmt, ...)
{
	va_list args;

	va_start(args, fmt);
	vfprintf(stderr, fmt, args);
	fprintf(stderr, "\n");
	va_end(args);

	unlock_mtab();
	exit(err);
}

/* Parse a list of strings like str[,str]... into a string list.  */
string_list parse_list(char *strings)
{
	string_list list;
	char *t;

	if (strings == NULL)
		return NULL;

	list = cons(strtok(strings, ","), NULL);

	while ((t = strtok(NULL, ",")) != NULL)
		list = cons(t, list);

	return list;
}

/* True if fstypes match.  Null *TYPES means match anything,
   except that swap types always return false.
   This routine has some ugliness to deal with ``no'' types.
   Fixed bug: the `no' part comes at the end - aeb, 970216  */
int matching_type(const char *type, string_list types)
{
	char *notype;
	int foundyes, foundno;
	int no;			/* true if a "no" type match, eg -t nominix */

	if (streq(type, MNTTYPE_SWAP))
		return 0;
	if (types == NULL)
		return 1;

	if ((notype = alloca(strlen(type) + 3)) == NULL)
		die(EX_SYSERR, "mount: out of memory");
	sprintf(notype, "no%s", type);

	foundyes = foundno = no = 0;
	while (types != NULL) {
		if (cdr(types) == NULL)
			no = (car(types)[0] == 'n') && (car(types)[1] == 'o');
		if (streq(type, car(types)))
			foundyes = 1;
		else if (streq(notype, car(types)))
			foundno = 1;
		types = cdr(types);
	}

	return (foundno ? 0 : (no ^ foundyes));
}

/* Make a canonical pathname from PATH.  Returns a freshly malloced string.
   It is up the *caller* to ensure that the PATH is sensible.  i.e.
   canonicalize ("/dev/fd0/.") returns "/dev/fd0" even though ``/dev/fd0/.''
   is not a legal pathname for ``/dev/fd0''.  Anything we cannot parse
   we return unmodified.   */
char *canonicalize(const char *path)
{
	char *canonical;

	if (path == NULL)
		return NULL;

	if (streq(path, "none") || streq(path, "proc"))
		return xstrdup(path);

	canonical = xmalloc(PATH_MAX + 1);

	if (realpath(path, canonical))
		return canonical;

	free(canonical);
	return xstrdup(path);
}
