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