utils.c (3640B)
1 #include "utils.h" 2 3 #include <ctype.h> 4 #include <errno.h> 5 #include <stdarg.h> 6 #include <string.h> 7 #include <stdlib.h> 8 #include <unistd.h> 9 #include <sys/wait.h> 10 11 const int BLEN = 4 * 1024; 12 13 void quit(int code, char *fmt, ...) { 14 va_list v; 15 va_start(v, fmt); 16 vfprintf(stderr, fmt, v); 17 exit(code); 18 va_end(v); 19 } 20 21 void die(int code, char *fmt, ...) { 22 va_list v; 23 va_start(v, fmt); 24 char msg[BLEN]; 25 vsnprintf(msg, BLEN, fmt, v); 26 perror(msg); 27 exit(code); 28 va_end(v); 29 } 30 31 void rtrim(char *s) { 32 if(!s) die(1, "rtrim(): nothing to trim"); 33 char *e = s + strlen(s) - 1; 34 while(s < e && isspace(*e)) *e-- = '\0'; 35 } 36 37 void in(void *udata, in_cb cb, char *cmd, ...) { 38 va_list v; 39 va_start(v, cmd); 40 char buf[BLEN]; 41 vsnprintf(buf, BLEN, cmd, v); 42 FILE *pipe = popen(buf, "r"); 43 if(!pipe) die(1, "in(): cannot open pipe to '%s'", buf); 44 cb(udata, pipe); 45 pclose(pipe); 46 va_end(v); 47 } 48 49 void out(void *udata, out_cb cb, char *cmd, ...) { 50 va_list v; 51 va_start(v, cmd); 52 char buf[BLEN]; 53 vsnprintf(buf, BLEN, cmd, v); 54 FILE *pipe = popen(buf, "w"); 55 if(!pipe) die(1, "out(): cannot open pipe to '%s'", buf); 56 cb(udata, pipe); 57 pclose(pipe); 58 va_end(v); 59 } 60 61 void tmpf(void *udata, tmpf_cb cb, char *fname, ...) { 62 va_list v; 63 va_start(v, fname); 64 char buf[BLEN]; 65 vsnprintf(buf, BLEN, fname, v); 66 int fd = mkstemp(buf); 67 if(fd == -1) die(errno, "tmpf(): cannot create temporary file '%s'", buf); 68 close(fd); 69 cb(udata, buf); 70 unlink(buf); 71 va_end(v); 72 } 73 74 void dir(void *udata, dir_cb cb, char *path, ...) { 75 va_list v; 76 va_start(v, path); 77 char buf[BLEN]; 78 vsnprintf(buf, BLEN, path, v); 79 DIR *d = opendir(buf); 80 if(!d) die(1, "dir(): cannot open dir '%s'", buf); 81 struct dirent *e; 82 while((e = readdir(d))) { 83 char fname[BLEN]; 84 snprintf(fname, BLEN, "%s/%s", buf, e->d_name); 85 struct stat s; 86 if(lstat(fname, &s) < 0) 87 die(1, "stat_cb(): lstat('%s') failed", fname); 88 if(!cb(udata, buf, fname, e, &s)) break; 89 } 90 closedir(d); 91 va_end(v); 92 } 93 94 int systemf(char *cmd, ...) { 95 va_list v; 96 va_start(v, cmd); 97 char buf[BLEN]; 98 vsnprintf(buf, BLEN, cmd, v); 99 va_end(v); 100 fprintf(stderr, "sh: %s\n", buf); // TODO remove 101 int x = system(buf); 102 return 0 <= x && WIFEXITED(x) ? WEXITSTATUS(x) : -1; 103 } 104 105 void wget(char *url, char *fname) { 106 // http://www.gnu.org/software/wget/manual/html_node/Exit-Status.html 107 static char *wgetmsg[] = { 108 "No problems occurred", 109 "Generic error code", 110 "Parse error, e.g. when parsing command-line options, .wgetrc or .netrc", 111 "File I/O error", 112 "Network failure", 113 "SSL verification failure", 114 "Username/password authentication failure", 115 "Protocol errors", 116 "Server issued an error response" 117 }; 118 int pid = fork(); 119 if(pid < 0) die(pid, "wget(): fork failed"); 120 else if(pid == 0) execlp("wget", "wget", "-q", "-O", fname, "--", url, NULL); 121 else { 122 int x; 123 do { 124 pid_t w = waitpid(pid, &x, WUNTRACED | WCONTINUED); 125 if(w == -1) die(1, "wget(): waitpid failed on wget '%s'", url); 126 if(WIFEXITED(x)) { 127 int n = WEXITSTATUS(x); 128 if(n) 129 fprintf(stderr, "wget '%s' failed with status %d: %s\n", url, 130 n, (0 <= n && n <= 8) ? wgetmsg[n] : "unexpected status"); 131 } 132 else if(WIFSIGNALED(x)) 133 fprintf(stderr, "wget '%s' killed by signal %d\n", url, 134 WTERMSIG(x)); 135 else if(WIFSTOPPED(x)) 136 fprintf(stderr, "wget '%s' stopped by signal %d\n", url, 137 WSTOPSIG(x)); 138 else if(WIFCONTINUED(x)) 139 fprintf(stderr, "wget '%s' continued\n", url); 140 } while(!WIFEXITED(x) && !WIFSIGNALED(x)); 141 } 142 }