util.c (5434B)
1 /* See LICENSE file for copyright and license details. */ 2 #include "common.h" 3 4 char *argv0; 5 6 void 7 weprintf(const char *fmt, ...) 8 { 9 char end; 10 va_list ap; 11 va_start(ap, fmt); 12 13 if (argv0 && strncmp(fmt, "usage", strlen("usage"))) 14 fprintf(stderr, "%s: ", argv0); 15 16 vfprintf(stderr, fmt, ap); 17 18 end = *fmt ? strchr(fmt, '\0')[-1] : '\n'; 19 if (end == ':') { 20 fputc(' ', stderr); 21 perror(NULL); 22 } else if (end != '\n') { 23 fputc('\n', stderr); 24 } 25 26 va_end(ap); 27 } 28 29 30 int 31 tollu(const char *s, unsigned long long int min, unsigned long long int max, unsigned long long int *out) 32 { 33 char *end; 34 errno = 0; 35 if (*s == '-') { 36 errno = ERANGE; 37 return -1; 38 } 39 if (!isdigit(s[*s == 'x' || *s == 'X' || *s == '#']) || 40 (*s == '0' && s[1] && !isdigit(s[1 + (*s == 'x' || *s == 'o' || *s == 'b')]))) { 41 errno = EINVAL; 42 return -1; 43 } 44 if (tolower(*s) == 'x' || *s == '#') 45 *out = strtoull(s + 1, &end, 16); 46 else if (*s == '0' && tolower(s[1]) == 'x') 47 *out = strtoull(s + 2, &end, 16); 48 else if (*s == '0' && tolower(s[1]) == 'o') 49 *out = strtoull(s + 2, &end, 8); 50 else if (*s == '0' && tolower(s[1]) == 'b') 51 *out = strtoull(s + 2, &end, 2); 52 else 53 *out = strtoull(s, &end, 10); 54 if (errno) 55 return -1; 56 if (*end) { 57 errno = EINVAL; 58 return -1; 59 } 60 if (*out < min || *out > max) { 61 errno = ERANGE; 62 return -1; 63 } 64 return 0; 65 } 66 67 int 68 tolli(const char *s, long long int min, long long int max, long long int *out) 69 { 70 int sign = 1; 71 unsigned long long int inter; 72 errno = 0; 73 if (*s == '-') { 74 s++; 75 sign = -1; 76 } 77 if (tollu(s, 0, ULLONG_MAX, &inter)) 78 return -1; 79 if (sign > 0) { 80 if (max < 0 || inter > (unsigned long long int)max) 81 goto erange; 82 *out = (long long int)inter; 83 if (*out < min) 84 goto erange; 85 } else { 86 #if LLONG_MIN == -LLONG_MAX 87 if (inter > -LLONG_MIN) 88 goto erange; 89 #else 90 if (inter > (unsigned long long int)LLONG_MAX + 1ULL) 91 goto erange; 92 #endif 93 *out = -(long long int)inter; 94 if (*out < min || *out > max) 95 goto erange; 96 } 97 return 0; 98 99 erange: 100 errno = ERANGE; 101 return -1; 102 } 103 104 105 int 106 writeall(int fd, const void *buf, size_t n) 107 { 108 const char *buffer = buf; 109 ssize_t r; 110 while (n) { 111 r = write(fd, buffer, n); 112 if (r < 0) 113 return -1; 114 buffer += (size_t)r; 115 n -= (size_t)r; 116 } 117 return 0; 118 } 119 120 ssize_t 121 readall(int fd, void *buf, size_t n) 122 { 123 char *buffer = buf; 124 size_t ptr = 0; 125 ssize_t r; 126 for (;;) { 127 r = read(fd, buffer + ptr, n - ptr); 128 if (r < 0) 129 return -1; 130 if (r == 0) 131 break; 132 ptr += (size_t)r; 133 } 134 return (ssize_t)ptr; 135 } 136 137 int 138 pwriteall(int fd, const void *buf, size_t n, off_t ptr) 139 { 140 const char *buffer = buf; 141 ssize_t r; 142 while (n) { 143 r = pwrite(fd, buffer, n, (off_t)ptr); 144 if (r < 0) 145 return -1; 146 buffer += (size_t)r; 147 n -= (size_t)r; 148 ptr += (off_t)r; 149 } 150 return 0; 151 } 152 153 int 154 writezeroes(int fd, const void *buf, size_t bufsize, size_t n) 155 { 156 size_t p, m; 157 for (p = 0; p < n; p += m) { 158 m = MIN(bufsize, n - p); 159 if (writeall(fd, buf, m)) 160 return -1; 161 } 162 return 0; 163 } 164 165 int 166 getfile(int fd, void *buffer, size_t *restrict ptr, size_t *restrict size) 167 { 168 char *restrict *restrict buf = buffer; 169 void *new; 170 size_t new_size; 171 ssize_t r; 172 173 for (;;) { 174 if (*ptr == *size) { 175 new_size = *size ? *size << 1 : BUFSIZ; 176 if (!(new = realloc(*buf, new_size))) { 177 errno = ENOMEM; 178 return -1; 179 } 180 *buf = new; 181 *size = new_size; 182 } 183 r = read(fd, *buf + *ptr, *size - *ptr); 184 if (r <= 0) { 185 if (r) 186 return -1; 187 break; 188 } 189 *ptr += (size_t)r; 190 } 191 192 return 0; 193 } 194 195 196 static inline pid_t 197 enfork(int status) 198 { 199 pid_t pid = fork(); 200 if (pid == -1) 201 enprintf(status, "fork:"); 202 return pid; 203 } 204 205 206 /* If <() is used in Bash (possibily other shells), that process becomes 207 * child of the process for each <() is used. Therefore, we cannot simply 208 * wait until the last child has been reaped, or even the expected number 209 * of children has been reaped, we must instead remember the PID of each 210 * child we created and wait for all of them to be reaped. { */ 211 212 int 213 enfork_jobs(int status, size_t *start, size_t *end, size_t jobs, pid_t **pids) 214 { 215 size_t j, s = *start, n = *end - *start; 216 pid_t pid; 217 if (jobs < 2) { 218 *pids = NULL; 219 return 1; 220 } 221 *end = n / jobs + s; 222 *pids = enmalloc2(status, jobs, sizeof(**pids)); 223 for (j = 1; j < jobs; j++) { 224 pid = enfork(status); 225 if (!pid) { 226 pdeath(SIGKILL); 227 *start = n * (j + 0) / jobs + s; 228 *end = n * (j + 1) / jobs + s; 229 return 0; 230 } else { 231 (*pids)[j - 1] = pid; 232 } 233 } 234 (*pids)[jobs - 1] = -1; 235 return 1; 236 } 237 238 void 239 enjoin_jobs(int status, int is_master, pid_t *pids) 240 { 241 int stat; 242 size_t i; 243 if (!is_master) 244 free(pids), exit(0); 245 if (!pids) 246 return; 247 for (i = 0; pids[i] != -1; i++) { 248 if (waitpid(pids[i], &stat, 0) == -1) 249 enprintf(status, "waitpid:"); 250 if (stat) 251 exit(WIFEXITED(stat) ? WEXITSTATUS(stat) : WTERMSIG(stat)); 252 } 253 free(pids); 254 } 255 256 /* } */ 257 258 259 int 260 xenopen(int status, const char *path, int flags, int mode, ...) 261 { 262 int fd; 263 if (!strncmp(path, "/dev/fd/", STRLEN("/dev/fd/"))) { 264 if (!toi(path + STRLEN("/dev/fd/"), 0, INT_MAX, &fd)) 265 return fd; 266 } else if (!strcmp(path, "/dev/stdin")) { 267 return STDIN_FILENO; 268 } else if (!strcmp(path, "/dev/stdout")) { 269 return STDOUT_FILENO; 270 } else if (!strcmp(path, "/dev/stderr")) { 271 return STDERR_FILENO; 272 } else if (!strcmp(path, "-")) { 273 if ((flags & O_ACCMODE) == O_WRONLY) 274 return STDOUT_FILENO; 275 else 276 return STDIN_FILENO; 277 } 278 fd = open(path, flags, mode); 279 if (fd < 0) 280 enprintf(status, "open %s:", path); 281 return fd; 282 }