libixp

git clone git://oldgit.suckless.org/libixp/
Log | Files | Refs | LICENSE

util.c (5076B)


      1 /* Written by Kris Maglione <maglione.k at Gmail> */
      2 /* Public domain */
      3 #include <errno.h>
      4 #include <stdarg.h>
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include <string.h>
      8 #include <unistd.h>
      9 #include <sys/types.h>
     10 #include <sys/stat.h>
     11 #include <pwd.h>
     12 #include "ixp_local.h"
     13 
     14 /**
     15  * Function: ixp_smprint
     16  *
     17  * This function formats its arguments as F<printf> and returns
     18  * a F<malloc> allocated string containing the result.
     19  */
     20 char*
     21 ixp_smprint(const char *fmt, ...) {
     22 	va_list ap;
     23 	char *s;
     24 
     25 	va_start(ap, fmt);
     26 	s = ixp_vsmprint(fmt, ap);
     27 	va_end(ap);
     28 	if(s == nil)
     29 		ixp_werrstr("no memory");
     30 	return s;
     31 }
     32 
     33 static char*
     34 _user(void) {
     35 	static char *user;
     36 	struct passwd *pw;
     37 
     38 	if(user == nil) {
     39 		pw = getpwuid(getuid());
     40 		if(pw)
     41 			user = strdup(pw->pw_name);
     42 	}
     43 	if(user == nil)
     44 		user = "none";
     45 	return user;
     46 }
     47 
     48 static int
     49 rmkdir(char *path, int mode) {
     50 	char *p;
     51 	int ret;
     52 	char c;
     53 
     54 	for(p = path+1; ; p++) {
     55 		c = *p;
     56 		if((c == '/') || (c == '\0')) {
     57 			*p = '\0';
     58 			ret = mkdir(path, mode);
     59 			if((ret == -1) && (errno != EEXIST)) {
     60 				ixp_werrstr("Can't create path '%s': %s", path, ixp_errbuf());
     61 				return 0;
     62 			}
     63 			*p = c;
     64 		}
     65 		if(c == '\0')
     66 			break;
     67 	}
     68 	return 1;
     69 }
     70 
     71 static char*
     72 ns_display(void) {
     73 	char *path, *disp;
     74 	struct stat st;
     75 
     76 	disp = getenv("DISPLAY");
     77 	if(disp == nil || disp[0] == '\0') {
     78 		ixp_werrstr("$DISPLAY is unset");
     79 		return nil;
     80 	}
     81 
     82 	disp = estrdup(disp);
     83 	path = &disp[strlen(disp) - 2];
     84 	if(path > disp && !strcmp(path, ".0"))
     85 		*path = '\0';
     86 
     87 	path = ixp_smprint("/tmp/ns.%s.%s", _user(), disp);
     88 	free(disp);
     89 
     90 	if(!rmkdir(path, 0700))
     91 		;
     92 	else if(stat(path, &st))
     93 		ixp_werrstr("Can't stat Namespace path '%s': %s", path, ixp_errbuf());
     94 	else if(getuid() != st.st_uid)
     95 		ixp_werrstr("Namespace path '%s' exists but is not owned by you", path);
     96 	else if((st.st_mode & 077) && chmod(path, st.st_mode & ~077))
     97 		ixp_werrstr("Namespace path '%s' exists, but has wrong permissions: %s", path, ixp_errbuf());
     98 	else
     99 		return path;
    100 	free(path);
    101 	return nil;
    102 }
    103 
    104 /**
    105  * Function: ixp_namespace
    106  *
    107  * Returns the path of the canonical 9p namespace directory.
    108  * Either the value of $NAMESPACE, if it's set, or, roughly,
    109  * /tmp/ns.${USER}.${DISPLAY:%.0=%}. In the latter case, the
    110  * directory is created if it doesn't exist, and it is
    111  * ensured to be owned by the current user, with no group or
    112  * other permissions.
    113  *
    114  * Returns:
    115  *	A statically allocated string which must not be freed
    116  *	or altered by the caller. The same value is returned
    117  *	upon successive calls.
    118  * Bugs:
    119  *	This function is not thread safe until after its first
    120  *	call.
    121  */
    122 /* Not especially threadsafe. */
    123 char*
    124 ixp_namespace(void) {
    125 	static char *namespace;
    126 
    127 	if(namespace == nil)
    128 		namespace = getenv("NAMESPACE");
    129 	if(namespace == nil)
    130 		namespace = ns_display();
    131 	return namespace;
    132 }
    133 
    134 /**
    135  * Function: ixp_eprint
    136  *
    137  * libixp calls this function on error. It formats its arguments
    138  * as F<printf> and exits the program.
    139  */
    140 void
    141 ixp_eprint(const char *fmt, ...) {
    142 	va_list ap;
    143 	int err;
    144 
    145 	err = errno;
    146 	fprintf(stderr, "libixp: fatal: ");
    147 
    148 	va_start(ap, fmt);
    149 	vfprintf(stderr, fmt, ap);
    150 	va_end(ap);
    151 
    152 	if(fmt[strlen(fmt)-1] == ':')
    153 		fprintf(stderr, " %s\n", strerror(err));
    154 	else
    155 		fprintf(stderr, "\n");
    156 
    157 	exit(1);
    158 }
    159 
    160 /* Can't malloc */
    161 static void
    162 mfatal(char *name, uint size) {
    163 	const char
    164 		couldnot[] = "libixp: fatal: Could not ",
    165 		paren[] = "() ",
    166 		bytes[] = " bytes\n";
    167 	char sizestr[8];
    168 	int i;
    169 	
    170 	i = sizeof sizestr;
    171 	do {
    172 		sizestr[--i] = '0' + (size%10);
    173 		size /= 10;
    174 	} while(size > 0);
    175 
    176 	write(1, couldnot, sizeof(couldnot)-1);
    177 	write(1, name, strlen(name));
    178 	write(1, paren, sizeof(paren)-1);
    179 	write(1, sizestr+i, sizeof(sizestr)-i);
    180 	write(1, bytes, sizeof(bytes)-1);
    181 
    182 	exit(1);
    183 }
    184 
    185 /**
    186  * Function: ixp_emalloc
    187  * Function: ixp_emallocz
    188  * Function: ixp_erealloc
    189  * Function: ixp_estrdup
    190  *
    191  * These functions act like their stdlib counterparts, but print
    192  * an error message and exit the program if allocation fails.
    193  * ixp_emallocz acts like ixp_emalloc but additionally zeros the
    194  * result of the allocation.
    195  */
    196 void*
    197 ixp_emalloc(uint size) {
    198 	void *ret = malloc(size);
    199 	if(!ret)
    200 		mfatal("malloc", size);
    201 	return ret;
    202 }
    203 
    204 void*
    205 ixp_emallocz(uint size) {
    206 	void *ret = emalloc(size);
    207 	memset(ret, 0, size);
    208 	return ret;
    209 }
    210 
    211 void*
    212 ixp_erealloc(void *ptr, uint size) {
    213 	void *ret = realloc(ptr, size);
    214 	if(!ret)
    215 		mfatal("realloc", size);
    216 	return ret;
    217 }
    218 
    219 char*
    220 ixp_estrdup(const char *str) {
    221 	void *ret = strdup(str);
    222 	if(!ret)
    223 		mfatal("strdup", strlen(str));
    224 	return ret;
    225 }
    226 
    227 uint
    228 ixp_tokenize(char *res[], uint reslen, char *str, char delim) {
    229 	char *s;
    230 	uint i;
    231 
    232 	i = 0;
    233 	s = str;
    234 	while(i < reslen && *s) {
    235 		while(*s == delim)
    236 			*(s++) = '\0';
    237 		if(*s)
    238 			res[i++] = s;
    239 		while(*s && *s != delim)
    240 			s++;
    241 	}
    242 	return i;
    243 }
    244 
    245 uint
    246 ixp_strlcat(char *dst, const char *src, uint size) {
    247 	const char *s;
    248 	char *d;
    249 	int n, len;
    250 
    251 	d = dst;
    252 	s = src;
    253 	n = size;
    254 	while(n-- > 0 && *d != '\0')
    255 		d++;
    256 	len = n;
    257 
    258 	while(*s != '\0' && n-- > 0)
    259 		*d++ = *s++;
    260 	while(*s++ != '\0')
    261 		n--;
    262 	if(len > 0)
    263 		*d = '\0';
    264 	return size - n - 1;
    265 }
    266