comparison lib/lib.c @ 694:786841fdb1e0

Reindent to two spaces per level. Remove vi: directives that haven't worked right in years (ubuntu broke its' vim implementation). Remove trailing spaces. Add/remove blank lines. Re-wordwrap in places. Update documentation with new coding style. The actual code should be the same afterward, this is just cosmetic refactoring.
author Rob Landley <rob@landley.net>
date Tue, 13 Nov 2012 17:14:08 -0600
parents e4b96507688a
children 99ca30ad3d2b
comparison
equal deleted inserted replaced
693:4a5a250e0633 694:786841fdb1e0
1 /* vi: set sw=4 ts=4 :*/
2 /* lib.c - reusable stuff. 1 /* lib.c - reusable stuff.
3 * 2 *
4 * Functions with the x prefix are wrappers for library functions. They either 3 * Functions with the x prefix are wrappers for library functions. They either
5 * succeed or kill the program with an error message, but never return failure. 4 * succeed or kill the program with an error message, but never return failure.
6 * They usually have the same arguments and return value as the function they 5 * They usually have the same arguments and return value as the function they
12 #include "toys.h" 11 #include "toys.h"
13 12
14 // Strcpy with size checking: exit if there's not enough space for the string. 13 // Strcpy with size checking: exit if there's not enough space for the string.
15 void xstrcpy(char *dest, char *src, size_t size) 14 void xstrcpy(char *dest, char *src, size_t size)
16 { 15 {
17 if (strlen(src)+1 > size) error_exit("xstrcpy"); 16 if (strlen(src)+1 > size) error_exit("xstrcpy");
18 strcpy(dest, src); 17 strcpy(dest, src);
19 } 18 }
20 19
21 void verror_msg(char *msg, int err, va_list va) 20 void verror_msg(char *msg, int err, va_list va)
22 { 21 {
23 char *s = ": %s"; 22 char *s = ": %s";
24 23
25 fprintf(stderr, "%s: ", toys.which->name); 24 fprintf(stderr, "%s: ", toys.which->name);
26 if (msg) vfprintf(stderr, msg, va); 25 if (msg) vfprintf(stderr, msg, va);
27 else s+=2; 26 else s+=2;
28 if (err) fprintf(stderr, s, strerror(err)); 27 if (err) fprintf(stderr, s, strerror(err));
29 putc('\n', stderr); 28 putc('\n', stderr);
30 } 29 }
31 30
32 void error_msg(char *msg, ...) 31 void error_msg(char *msg, ...)
33 { 32 {
34 va_list va; 33 va_list va;
35 34
36 va_start(va, msg); 35 va_start(va, msg);
37 verror_msg(msg, 0, va); 36 verror_msg(msg, 0, va);
38 va_end(va); 37 va_end(va);
39 } 38 }
40 39
41 void perror_msg(char *msg, ...) 40 void perror_msg(char *msg, ...)
42 { 41 {
43 va_list va; 42 va_list va;
44 43
45 va_start(va, msg); 44 va_start(va, msg);
46 verror_msg(msg, errno, va); 45 verror_msg(msg, errno, va);
47 va_end(va); 46 va_end(va);
48 } 47 }
49 48
50 // Die with an error message. 49 // Die with an error message.
51 void error_exit(char *msg, ...) 50 void error_exit(char *msg, ...)
52 { 51 {
53 va_list va; 52 va_list va;
54 53
55 if (CFG_HELP && toys.exithelp) { 54 if (CFG_HELP && toys.exithelp) {
56 *toys.optargs=*toys.argv; 55 *toys.optargs=*toys.argv;
57 USE_HELP(help_main();) // dear gcc: shut up. 56 USE_HELP(help_main();) // dear gcc: shut up.
58 fprintf(stderr,"\n"); 57 fprintf(stderr,"\n");
59 } 58 }
60 59
61 va_start(va, msg); 60 va_start(va, msg);
62 verror_msg(msg, 0, va); 61 verror_msg(msg, 0, va);
63 va_end(va); 62 va_end(va);
64 63
65 exit(!toys.exitval ? 1 : toys.exitval); 64 exit(!toys.exitval ? 1 : toys.exitval);
66 } 65 }
67 66
68 67
69 // Die with an error message and strerror(errno) 68 // Die with an error message and strerror(errno)
70 void perror_exit(char *msg, ...) 69 void perror_exit(char *msg, ...)
71 { 70 {
72 va_list va; 71 va_list va;
73 72
74 va_start(va, msg); 73 va_start(va, msg);
75 verror_msg(msg, errno, va); 74 verror_msg(msg, errno, va);
76 va_end(va); 75 va_end(va);
77 76
78 exit(!toys.exitval ? 1 : toys.exitval); 77 exit(!toys.exitval ? 1 : toys.exitval);
79 } 78 }
80 79
81 // Die unless we can allocate memory. 80 // Die unless we can allocate memory.
82 void *xmalloc(size_t size) 81 void *xmalloc(size_t size)
83 { 82 {
84 void *ret = malloc(size); 83 void *ret = malloc(size);
85 if (!ret) error_exit("xmalloc"); 84 if (!ret) error_exit("xmalloc");
86 85
87 return ret; 86 return ret;
88 } 87 }
89 88
90 // Die unless we can allocate prezeroed memory. 89 // Die unless we can allocate prezeroed memory.
91 void *xzalloc(size_t size) 90 void *xzalloc(size_t size)
92 { 91 {
93 void *ret = xmalloc(size); 92 void *ret = xmalloc(size);
94 memset(ret, 0, size); 93 memset(ret, 0, size);
95 return ret; 94 return ret;
96 } 95 }
97 96
98 // Die unless we can change the size of an existing allocation, possibly 97 // Die unless we can change the size of an existing allocation, possibly
99 // moving it. (Notice different arguments from libc function.) 98 // moving it. (Notice different arguments from libc function.)
100 void *xrealloc(void *ptr, size_t size) 99 void *xrealloc(void *ptr, size_t size)
101 { 100 {
102 ptr = realloc(ptr, size); 101 ptr = realloc(ptr, size);
103 if (!ptr) error_exit("xrealloc"); 102 if (!ptr) error_exit("xrealloc");
104 103
105 return ptr; 104 return ptr;
106 } 105 }
107 106
108 // Die unless we can allocate a copy of this many bytes of string. 107 // Die unless we can allocate a copy of this many bytes of string.
109 char *xstrndup(char *s, size_t n) 108 char *xstrndup(char *s, size_t n)
110 { 109 {
111 char *ret = xmalloc(++n); 110 char *ret = xmalloc(++n);
112 strncpy(ret, s, n); 111 strncpy(ret, s, n);
113 ret[--n]=0; 112 ret[--n]=0;
114 113
115 return ret; 114 return ret;
116 } 115 }
117 116
118 // Die unless we can allocate a copy of this string. 117 // Die unless we can allocate a copy of this string.
119 char *xstrdup(char *s) 118 char *xstrdup(char *s)
120 { 119 {
121 return xstrndup(s, strlen(s)); 120 return xstrndup(s, strlen(s));
122 } 121 }
123 122
124 // Die unless we can allocate enough space to sprintf() into. 123 // Die unless we can allocate enough space to sprintf() into.
125 char *xmsprintf(char *format, ...) 124 char *xmsprintf(char *format, ...)
126 { 125 {
127 va_list va, va2; 126 va_list va, va2;
128 int len; 127 int len;
129 char *ret; 128 char *ret;
130 129
131 va_start(va, format); 130 va_start(va, format);
132 va_copy(va2, va); 131 va_copy(va2, va);
133 132
134 // How long is it? 133 // How long is it?
135 len = vsnprintf(0, 0, format, va); 134 len = vsnprintf(0, 0, format, va);
136 len++; 135 len++;
137 va_end(va); 136 va_end(va);
138 137
139 // Allocate and do the sprintf() 138 // Allocate and do the sprintf()
140 ret = xmalloc(len); 139 ret = xmalloc(len);
141 vsnprintf(ret, len, format, va2); 140 vsnprintf(ret, len, format, va2);
142 va_end(va2); 141 va_end(va2);
143 142
144 return ret; 143 return ret;
145 } 144 }
146 145
147 void xprintf(char *format, ...) 146 void xprintf(char *format, ...)
148 { 147 {
149 va_list va; 148 va_list va;
150 va_start(va, format); 149 va_start(va, format);
151 150
152 vprintf(format, va); 151 vprintf(format, va);
153 if (ferror(stdout)) perror_exit("write"); 152 if (ferror(stdout)) perror_exit("write");
154 } 153 }
155 154
156 void xputs(char *s) 155 void xputs(char *s)
157 { 156 {
158 if (EOF == puts(s)) perror_exit("write"); 157 if (EOF == puts(s)) perror_exit("write");
159 } 158 }
160 159
161 void xputc(char c) 160 void xputc(char c)
162 { 161 {
163 if (EOF == fputc(c, stdout) || fflush(stdout)) perror_exit("write"); 162 if (EOF == fputc(c, stdout) || fflush(stdout)) perror_exit("write");
164 } 163 }
165 164
166 void xflush(void) 165 void xflush(void)
167 { 166 {
168 if (fflush(stdout)) perror_exit("write");; 167 if (fflush(stdout)) perror_exit("write");;
169 } 168 }
170 169
171 // Die unless we can exec argv[] (or run builtin command). Note that anything 170 // Die unless we can exec argv[] (or run builtin command). Note that anything
172 // with a path isn't a builtin, so /bin/sh won't match the builtin sh. 171 // with a path isn't a builtin, so /bin/sh won't match the builtin sh.
173 void xexec(char **argv) 172 void xexec(char **argv)
174 { 173 {
175 toy_exec(argv); 174 toy_exec(argv);
176 execvp(argv[0], argv); 175 execvp(argv[0], argv);
177 176
178 perror_exit("exec %s", argv[0]); 177 perror_exit("exec %s", argv[0]);
179 } 178 }
180 179
181 void xaccess(char *path, int flags) 180 void xaccess(char *path, int flags)
182 { 181 {
183 if (access(path, flags)) perror_exit("Can't access '%s'", path); 182 if (access(path, flags)) perror_exit("Can't access '%s'", path);
184 } 183 }
185 184
186 // Die unless we can delete a file. (File must exist to be deleted.) 185 // Die unless we can delete a file. (File must exist to be deleted.)
187 void xunlink(char *path) 186 void xunlink(char *path)
188 { 187 {
189 if (unlink(path)) perror_exit("unlink '%s'", path); 188 if (unlink(path)) perror_exit("unlink '%s'", path);
190 } 189 }
191 190
192 // Die unless we can open/create a file, returning file descriptor. 191 // Die unless we can open/create a file, returning file descriptor.
193 int xcreate(char *path, int flags, int mode) 192 int xcreate(char *path, int flags, int mode)
194 { 193 {
195 int fd = open(path, flags, mode); 194 int fd = open(path, flags, mode);
196 if (fd == -1) perror_exit("%s", path); 195 if (fd == -1) perror_exit("%s", path);
197 return fd; 196 return fd;
198 } 197 }
199 198
200 // Die unless we can open a file, returning file descriptor. 199 // Die unless we can open a file, returning file descriptor.
201 int xopen(char *path, int flags) 200 int xopen(char *path, int flags)
202 { 201 {
203 return xcreate(path, flags, 0); 202 return xcreate(path, flags, 0);
204 } 203 }
205 204
206 void xclose(int fd) 205 void xclose(int fd)
207 { 206 {
208 if (close(fd)) perror_exit("xclose"); 207 if (close(fd)) perror_exit("xclose");
209 } 208 }
210 209
211 int xdup(int fd) 210 int xdup(int fd)
212 { 211 {
213 if (fd != -1) { 212 if (fd != -1) {
214 fd = dup(fd); 213 fd = dup(fd);
215 if (fd == -1) perror_exit("xdup"); 214 if (fd == -1) perror_exit("xdup");
216 } 215 }
217 return fd; 216 return fd;
218 } 217 }
219 218
220 // Die unless we can open/create a file, returning FILE *. 219 // Die unless we can open/create a file, returning FILE *.
221 FILE *xfopen(char *path, char *mode) 220 FILE *xfopen(char *path, char *mode)
222 { 221 {
223 FILE *f = fopen(path, mode); 222 FILE *f = fopen(path, mode);
224 if (!f) perror_exit("No file %s", path); 223 if (!f) perror_exit("No file %s", path);
225 return f; 224 return f;
226 } 225 }
227 226
228 // Keep reading until full or EOF 227 // Keep reading until full or EOF
229 ssize_t readall(int fd, void *buf, size_t len) 228 ssize_t readall(int fd, void *buf, size_t len)
230 { 229 {
231 size_t count = 0; 230 size_t count = 0;
232 231
233 while (count<len) { 232 while (count<len) {
234 int i = read(fd, buf+count, len-count); 233 int i = read(fd, buf+count, len-count);
235 if (!i) break; 234 if (!i) break;
236 if (i<0) return i; 235 if (i<0) return i;
237 count += i; 236 count += i;
238 } 237 }
239 238
240 return count; 239 return count;
241 } 240 }
242 241
243 // Keep writing until done or EOF 242 // Keep writing until done or EOF
244 ssize_t writeall(int fd, void *buf, size_t len) 243 ssize_t writeall(int fd, void *buf, size_t len)
245 { 244 {
246 size_t count = 0; 245 size_t count = 0;
247 while (count<len) { 246 while (count<len) {
248 int i = write(fd, buf+count, len-count); 247 int i = write(fd, buf+count, len-count);
249 if (i<1) return i; 248 if (i<1) return i;
250 count += i; 249 count += i;
251 } 250 }
252 251
253 return count; 252 return count;
254 } 253 }
255 254
256 // Die if there's an error other than EOF. 255 // Die if there's an error other than EOF.
257 size_t xread(int fd, void *buf, size_t len) 256 size_t xread(int fd, void *buf, size_t len)
258 { 257 {
259 ssize_t ret = read(fd, buf, len); 258 ssize_t ret = read(fd, buf, len);
260 if (ret < 0) perror_exit("xread"); 259 if (ret < 0) perror_exit("xread");
261 260
262 return ret; 261 return ret;
263 } 262 }
264 263
265 void xreadall(int fd, void *buf, size_t len) 264 void xreadall(int fd, void *buf, size_t len)
266 { 265 {
267 if (len != readall(fd, buf, len)) perror_exit("xreadall"); 266 if (len != readall(fd, buf, len)) perror_exit("xreadall");
268 } 267 }
269 268
270 // There's no xwriteall(), just xwrite(). When we read, there may or may not 269 // There's no xwriteall(), just xwrite(). When we read, there may or may not
271 // be more data waiting. When we write, there is data and it had better go 270 // be more data waiting. When we write, there is data and it had better go
272 // somewhere. 271 // somewhere.
273 272
274 void xwrite(int fd, void *buf, size_t len) 273 void xwrite(int fd, void *buf, size_t len)
275 { 274 {
276 if (len != writeall(fd, buf, len)) perror_exit("xwrite"); 275 if (len != writeall(fd, buf, len)) perror_exit("xwrite");
277 } 276 }
278 277
279 // Die if lseek fails, probably due to being called on a pipe. 278 // Die if lseek fails, probably due to being called on a pipe.
280 279
281 off_t xlseek(int fd, off_t offset, int whence) 280 off_t xlseek(int fd, off_t offset, int whence)
282 { 281 {
283 offset = lseek(fd, offset, whence); 282 offset = lseek(fd, offset, whence);
284 if (offset<0) perror_exit("lseek"); 283 if (offset<0) perror_exit("lseek");
285 284
286 return offset; 285 return offset;
287 } 286 }
288 287
289 off_t lskip(int fd, off_t offset) 288 off_t lskip(int fd, off_t offset)
290 { 289 {
291 off_t and = lseek(fd, offset, SEEK_CUR); 290 off_t and = lseek(fd, offset, SEEK_CUR);
292 291
293 if (and != -1 && offset >= lseek(fd, offset, SEEK_END) 292 if (and != -1 && offset >= lseek(fd, offset, SEEK_END)
294 && offset+and == lseek(fd, offset+and, SEEK_SET)) return 0; 293 && offset+and == lseek(fd, offset+and, SEEK_SET)) return 0;
295 else { 294 else {
296 char buf[4096]; 295 char buf[4096];
297 while (offset>0) { 296 while (offset>0) {
298 int try = offset>sizeof(buf) ? sizeof(buf) : offset, or; 297 int try = offset>sizeof(buf) ? sizeof(buf) : offset, or;
299 298
300 or = readall(fd, buf, try); 299 or = readall(fd, buf, try);
301 if (or < 0) perror_msg("lskip to %lld", (long long)offset); 300 if (or < 0) perror_msg("lskip to %lld", (long long)offset);
302 else offset -= try; 301 else offset -= try;
303 if (or < try) break; 302 if (or < try) break;
304 } 303 }
305 304
306 return offset; 305 return offset;
307 } 306 }
308 } 307 }
309 308
310 char *xgetcwd(void) 309 char *xgetcwd(void)
311 { 310 {
312 char *buf = getcwd(NULL, 0); 311 char *buf = getcwd(NULL, 0);
313 if (!buf) perror_exit("xgetcwd"); 312 if (!buf) perror_exit("xgetcwd");
314 313
315 return buf; 314 return buf;
316 } 315 }
317 316
318 void xstat(char *path, struct stat *st) 317 void xstat(char *path, struct stat *st)
319 { 318 {
320 if(stat(path, st)) perror_exit("Can't stat %s", path); 319 if(stat(path, st)) perror_exit("Can't stat %s", path);
321 } 320 }
322 321
323 // Cannonicalizes path by removing ".", "..", and "//" elements. This is not 322 // Cannonicalizes path by removing ".", "..", and "//" elements. This is not
324 // the same as realpath(), where "dir/.." could wind up somewhere else by 323 // the same as realpath(), where "dir/.." could wind up somewhere else by
325 // following symlinks. 324 // following symlinks.
326 char *xabspath(char *path) 325 char *xabspath(char *path)
327 { 326 {
328 char *from, *to; 327 char *from, *to;
329 328
330 // If this isn't an absolute path, make it one with cwd. 329 // If this isn't an absolute path, make it one with cwd.
331 if (path[0]!='/') { 330 if (path[0]!='/') {
332 char *cwd=xgetcwd(); 331 char *cwd=xgetcwd();
333 path = xmsprintf("%s/%s", cwd, path); 332 path = xmsprintf("%s/%s", cwd, path);
334 free(cwd); 333 free(cwd);
335 } else path = xstrdup(path); 334 } else path = xstrdup(path);
336 335
337 // Loop through path elements 336 // Loop through path elements
338 from = to = path; 337 from = to = path;
339 while (*from) { 338 while (*from) {
340 339
341 // Continue any current path component. 340 // Continue any current path component.
342 if (*from!='/') { 341 if (*from!='/') {
343 *(to++) = *(from++); 342 *(to++) = *(from++);
344 continue; 343 continue;
345 } 344 }
346 345
347 // Skip duplicate slashes. 346 // Skip duplicate slashes.
348 while (*from=='/') from++; 347 while (*from=='/') from++;
349 348
350 // Start of a new filename. Handle . and .. 349 // Start of a new filename. Handle . and ..
351 while (*from=='.') { 350 while (*from=='.') {
352 // Skip . 351 // Skip .
353 if (from[1]=='/') from += 2; 352 if (from[1]=='/') from += 2;
354 else if (!from[1]) from++; 353 else if (!from[1]) from++;
355 // Back up for .. 354 // Back up for ..
356 else if (from[1]=='.') { 355 else if (from[1]=='.') {
357 if (from[2]=='/') from +=3; 356 if (from[2]=='/') from +=3;
358 else if(!from[2]) from+=2; 357 else if(!from[2]) from+=2;
359 else break; 358 else break;
360 while (to>path && *(--to)!='/'); 359 while (to>path && *(--to)!='/');
361 } else break; 360 } else break;
362 } 361 }
363 // Add directory separator slash. 362 // Add directory separator slash.
364 *(to++) = '/'; 363 *(to++) = '/';
365 } 364 }
366 *to = 0; 365 *to = 0;
367 366
368 return path; 367 return path;
369 } 368 }
370 369
371 // Resolve all symlinks, returning malloc() memory. 370 // Resolve all symlinks, returning malloc() memory.
372 char *xrealpath(char *path) 371 char *xrealpath(char *path)
373 { 372 {
374 char *new = realpath(path, NULL); 373 char *new = realpath(path, NULL);
375 if (!new) perror_exit("realpath '%s'", path); 374 if (!new) perror_exit("realpath '%s'", path);
376 return new; 375 return new;
377 } 376 }
378 377
379 void xchdir(char *path) 378 void xchdir(char *path)
380 { 379 {
381 if (chdir(path)) error_exit("chdir '%s'", path); 380 if (chdir(path)) error_exit("chdir '%s'", path);
382 } 381 }
383 382
384 // Ensure entire path exists. 383 // Ensure entire path exists.
385 // If mode != -1 set permissions on newly created dirs. 384 // If mode != -1 set permissions on newly created dirs.
386 // Requires that path string be writable (for temporary null terminators). 385 // Requires that path string be writable (for temporary null terminators).
387 void xmkpath(char *path, int mode) 386 void xmkpath(char *path, int mode)
388 { 387 {
389 char *p, old; 388 char *p, old;
390 mode_t mask; 389 mode_t mask;
391 int rc; 390 int rc;
392 struct stat st; 391 struct stat st;
393 392
394 for (p = path; ; p++) { 393 for (p = path; ; p++) {
395 if (!*p || *p == '/') { 394 if (!*p || *p == '/') {
396 old = *p; 395 old = *p;
397 *p = rc = 0; 396 *p = rc = 0;
398 if (stat(path, &st) || !S_ISDIR(st.st_mode)) { 397 if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
399 if (mode != -1) { 398 if (mode != -1) {
400 mask=umask(0); 399 mask=umask(0);
401 rc = mkdir(path, mode); 400 rc = mkdir(path, mode);
402 umask(mask); 401 umask(mask);
403 } else rc = mkdir(path, 0777); 402 } else rc = mkdir(path, 0777);
404 } 403 }
405 *p = old; 404 *p = old;
406 if(rc) perror_exit("mkpath '%s'", path); 405 if(rc) perror_exit("mkpath '%s'", path);
407 } 406 }
408 if (!*p) break; 407 if (!*p) break;
409 } 408 }
410 } 409 }
411 410
412 // setuid() can fail (for example, too many processes belonging to that user), 411 // setuid() can fail (for example, too many processes belonging to that user),
413 // which opens a security hole if the process continues as the original user. 412 // which opens a security hole if the process continues as the original user.
414 413
415 void xsetuid(uid_t uid) 414 void xsetuid(uid_t uid)
416 { 415 {
417 if (setuid(uid)) perror_exit("xsetuid"); 416 if (setuid(uid)) perror_exit("xsetuid");
418 } 417 }
419 418
420 419
421 // Find all file in a colon-separated path with access type "type" (generally 420 // Find all file in a colon-separated path with access type "type" (generally
422 // X_OK or R_OK). Returns a list of absolute paths to each file found, in 421 // X_OK or R_OK). Returns a list of absolute paths to each file found, in
423 // order. 422 // order.
424 423
425 struct string_list *find_in_path(char *path, char *filename) 424 struct string_list *find_in_path(char *path, char *filename)
426 { 425 {
427 struct string_list *rlist = NULL, **prlist=&rlist; 426 struct string_list *rlist = NULL, **prlist=&rlist;
428 char *cwd = xgetcwd(); 427 char *cwd = xgetcwd();
429 428
430 for (;;) { 429 for (;;) {
431 char *next = path ? strchr(path, ':') : NULL; 430 char *next = path ? strchr(path, ':') : NULL;
432 int len = next ? next-path : strlen(path); 431 int len = next ? next-path : strlen(path);
433 struct string_list *rnext; 432 struct string_list *rnext;
434 struct stat st; 433 struct stat st;
435 434
436 rnext = xmalloc(sizeof(void *) + strlen(filename) 435 rnext = xmalloc(sizeof(void *) + strlen(filename)
437 + (len ? len : strlen(cwd)) + 2); 436 + (len ? len : strlen(cwd)) + 2);
438 if (!len) sprintf(rnext->str, "%s/%s", cwd, filename); 437 if (!len) sprintf(rnext->str, "%s/%s", cwd, filename);
439 else { 438 else {
440 char *res = rnext->str; 439 char *res = rnext->str;
441 strncpy(res, path, len); 440 strncpy(res, path, len);
442 res += len; 441 res += len;
443 *(res++) = '/'; 442 *(res++) = '/';
444 strcpy(res, filename); 443 strcpy(res, filename);
445 } 444 }
446 445
447 // Confirm it's not a directory. 446 // Confirm it's not a directory.
448 if (!stat(rnext->str, &st) && S_ISREG(st.st_mode)) { 447 if (!stat(rnext->str, &st) && S_ISREG(st.st_mode)) {
449 *prlist = rnext; 448 *prlist = rnext;
450 rnext->next = NULL; 449 rnext->next = NULL;
451 prlist = &(rnext->next); 450 prlist = &(rnext->next);
452 } else free(rnext); 451 } else free(rnext);
453 452
454 if (!next) break; 453 if (!next) break;
455 path += len; 454 path += len;
456 path++; 455 path++;
457 } 456 }
458 free(cwd); 457 free(cwd);
459 458
460 return rlist; 459 return rlist;
461 } 460 }
462 461
463 // Convert unsigned int to ascii, writing into supplied buffer. A truncated 462 // Convert unsigned int to ascii, writing into supplied buffer. A truncated
464 // result contains the first few digits of the result ala strncpy, and is 463 // result contains the first few digits of the result ala strncpy, and is
465 // always null terminated (unless buflen is 0). 464 // always null terminated (unless buflen is 0).
466 void utoa_to_buf(unsigned n, char *buf, unsigned buflen) 465 void utoa_to_buf(unsigned n, char *buf, unsigned buflen)
467 { 466 {
468 int i, out = 0; 467 int i, out = 0;
469 468
470 if (buflen) { 469 if (buflen) {
471 for (i=1000000000; i; i/=10) { 470 for (i=1000000000; i; i/=10) {
472 int res = n/i; 471 int res = n/i;
473 472
474 if ((res || out || i == 1) && --buflen>0) { 473 if ((res || out || i == 1) && --buflen>0) {
475 out++; 474 out++;
476 n -= res*i; 475 n -= res*i;
477 *buf++ = '0' + res; 476 *buf++ = '0' + res;
478 } 477 }
479 } 478 }
480 *buf = 0; 479 *buf = 0;
481 } 480 }
482 } 481 }
483 482
484 // Convert signed integer to ascii, using utoa_to_buf() 483 // Convert signed integer to ascii, using utoa_to_buf()
485 void itoa_to_buf(int n, char *buf, unsigned buflen) 484 void itoa_to_buf(int n, char *buf, unsigned buflen)
486 { 485 {
487 if (buflen && n<0) { 486 if (buflen && n<0) {
488 n = -n; 487 n = -n;
489 *buf++ = '-'; 488 *buf++ = '-';
490 buflen--; 489 buflen--;
491 } 490 }
492 utoa_to_buf((unsigned)n, buf, buflen); 491 utoa_to_buf((unsigned)n, buf, buflen);
493 } 492 }
494 493
495 // This static buffer is used by both utoa() and itoa(), calling either one a 494 // This static buffer is used by both utoa() and itoa(), calling either one a
496 // second time will overwrite the previous results. 495 // second time will overwrite the previous results.
497 // 496 //
502 static char itoa_buf[12]; 501 static char itoa_buf[12];
503 502
504 // Convert unsigned integer to ascii, returning a static buffer. 503 // Convert unsigned integer to ascii, returning a static buffer.
505 char *utoa(unsigned n) 504 char *utoa(unsigned n)
506 { 505 {
507 utoa_to_buf(n, itoa_buf, sizeof(itoa_buf)); 506 utoa_to_buf(n, itoa_buf, sizeof(itoa_buf));
508 507
509 return itoa_buf; 508 return itoa_buf;
510 } 509 }
511 510
512 char *itoa(int n) 511 char *itoa(int n)
513 { 512 {
514 itoa_to_buf(n, itoa_buf, sizeof(itoa_buf)); 513 itoa_to_buf(n, itoa_buf, sizeof(itoa_buf));
515 514
516 return itoa_buf; 515 return itoa_buf;
517 } 516 }
518 517
519 // atol() with the kilo/mega/giga/tera/peta/exa extensions. 518 // atol() with the kilo/mega/giga/tera/peta/exa extensions.
520 // (zetta and yotta don't fit in 64 bits.) 519 // (zetta and yotta don't fit in 64 bits.)
521 long atolx(char *numstr) 520 long atolx(char *numstr)
522 { 521 {
523 char *c, *suffixes="bkmgtpe", *end; 522 char *c, *suffixes="bkmgtpe", *end;
524 long val = strtol(numstr, &c, 0); 523 long val = strtol(numstr, &c, 0);
525 524
526 if (*c) { 525 if (*c) {
527 if (c != numstr && (end = strchr(suffixes, tolower(*c)))) { 526 if (c != numstr && (end = strchr(suffixes, tolower(*c)))) {
528 int shift = end-suffixes; 527 int shift = end-suffixes;
529 if (shift--) val *= 1024L<<(shift*10); 528 if (shift--) val *= 1024L<<(shift*10);
530 } else { 529 } else {
531 while (isspace(*c)) c++; 530 while (isspace(*c)) c++;
532 if (*c) error_exit("not integer: %s", numstr); 531 if (*c) error_exit("not integer: %s", numstr);
533 } 532 }
534 } 533 }
535 534
536 return val; 535 return val;
537 } 536 }
538 537
539 int numlen(long l) 538 int numlen(long l)
540 { 539 {
541 int len = 0; 540 int len = 0;
542 while (l) { 541 while (l) {
543 l /= 10; 542 l /= 10;
544 len++; 543 len++;
545 } 544 }
546 return len; 545 return len;
547 } 546 }
548 547
549 int stridx(char *haystack, char needle) 548 int stridx(char *haystack, char needle)
550 { 549 {
551 char *off; 550 char *off;
552 551
553 if (!needle) return -1; 552 if (!needle) return -1;
554 off = strchr(haystack, needle); 553 off = strchr(haystack, needle);
555 if (!off) return -1; 554 if (!off) return -1;
556 555
557 return off-haystack; 556 return off-haystack;
558 } 557 }
559 558
560 // Return how long the file at fd is, if there's any way to determine it. 559 // Return how long the file at fd is, if there's any way to determine it.
561 off_t fdlength(int fd) 560 off_t fdlength(int fd)
562 { 561 {
563 off_t bottom = 0, top = 0, pos, old; 562 off_t bottom = 0, top = 0, pos, old;
564 int size; 563 int size;
565 564
566 // If the ioctl works for this, return it. 565 // If the ioctl works for this, return it.
567 566
568 if (ioctl(fd, BLKGETSIZE, &size) >= 0) return size*512L; 567 if (ioctl(fd, BLKGETSIZE, &size) >= 0) return size*512L;
569 568
570 // If not, do a binary search for the last location we can read. (Some 569 // If not, do a binary search for the last location we can read. (Some
571 // block devices don't do BLKGETSIZE right.) This should probably have 570 // block devices don't do BLKGETSIZE right.) This should probably have
572 // a CONFIG option... 571 // a CONFIG option...
573 572
574 old = lseek(fd, 0, SEEK_CUR); 573 old = lseek(fd, 0, SEEK_CUR);
575 do { 574 do {
576 char temp; 575 char temp;
577 576
578 pos = bottom + (top - bottom) / 2; 577 pos = bottom + (top - bottom) / 2;
579 578
580 // If we can read from the current location, it's bigger. 579 // If we can read from the current location, it's bigger.
581 580
582 if (lseek(fd, pos, 0)>=0 && read(fd, &temp, 1)==1) { 581 if (lseek(fd, pos, 0)>=0 && read(fd, &temp, 1)==1) {
583 if (bottom == top) bottom = top = (top+1) * 2; 582 if (bottom == top) bottom = top = (top+1) * 2;
584 else bottom = pos; 583 else bottom = pos;
585 584
586 // If we can't, it's smaller. 585 // If we can't, it's smaller.
587 586
588 } else { 587 } else {
589 if (bottom == top) { 588 if (bottom == top) {
590 if (!top) return 0; 589 if (!top) return 0;
591 bottom = top/2; 590 bottom = top/2;
592 } else top = pos; 591 } else top = pos;
593 } 592 }
594 } while (bottom + 1 != top); 593 } while (bottom + 1 != top);
595 594
596 lseek(fd, old, SEEK_SET); 595 lseek(fd, old, SEEK_SET);
597 596
598 return pos + 1; 597 return pos + 1;
599 } 598 }
600 599
601 // This can return null (meaning file not found). It just won't return null 600 // This can return null (meaning file not found). It just won't return null
602 // for memory allocation reasons. 601 // for memory allocation reasons.
603 char *xreadlink(char *name) 602 char *xreadlink(char *name)
604 { 603 {
605 int len, size = 0; 604 int len, size = 0;
606 char *buf = 0; 605 char *buf = 0;
607 606
608 // Grow by 64 byte chunks until it's big enough. 607 // Grow by 64 byte chunks until it's big enough.
609 for(;;) { 608 for(;;) {
610 size +=64; 609 size +=64;
611 buf = xrealloc(buf, size); 610 buf = xrealloc(buf, size);
612 len = readlink(name, buf, size); 611 len = readlink(name, buf, size);
613 612
614 if (len<0) { 613 if (len<0) {
615 free(buf); 614 free(buf);
616 return 0; 615 return 0;
617 } 616 }
618 if (len<size) { 617 if (len<size) {
619 buf[len]=0; 618 buf[len]=0;
620 return buf; 619 return buf;
621 } 620 }
622 } 621 }
623 } 622 }
624 623
625 /* 624 /*
626 This might be of use or might not. Unknown yet... 625 This might be of use or might not. Unknown yet...
627 626
628 // Read contents of file as a single freshly allocated nul-terminated string. 627 // Read contents of file as a single freshly allocated nul-terminated string.
629 char *readfile(char *name) 628 char *readfile(char *name)
630 { 629 {
631 off_t len; 630 off_t len;
632 int fd; 631 int fd;
633 char *buf; 632 char *buf;
634 633
635 fd = open(name, O_RDONLY); 634 fd = open(name, O_RDONLY);
636 if (fd == -1) return 0; 635 if (fd == -1) return 0;
637 len = fdlength(fd); 636 len = fdlength(fd);
638 buf = xmalloc(len+1); 637 buf = xmalloc(len+1);
639 buf[readall(fd, buf, len)] = 0; 638 buf[readall(fd, buf, len)] = 0;
640 639
641 return buf; 640 return buf;
642 } 641 }
643 642
644 char *xreadfile(char *name) 643 char *xreadfile(char *name)
645 { 644 {
646 char *buf = readfile(name); 645 char *buf = readfile(name);
647 if (!buf) perror_exit("xreadfile %s", name); 646 if (!buf) perror_exit("xreadfile %s", name);
648 return buf; 647 return buf;
649 } 648 }
650 649
651 */ 650 */
652 651
653 // Open a /var/run/NAME.pid file, dying if we can't write it or if it currently 652 // Open a /var/run/NAME.pid file, dying if we can't write it or if it currently
654 // exists and is this executable. 653 // exists and is this executable.
655 void xpidfile(char *name) 654 void xpidfile(char *name)
656 { 655 {
657 char pidfile[256], spid[32]; 656 char pidfile[256], spid[32];
658 int i, fd; 657 int i, fd;
659 pid_t pid; 658 pid_t pid;
660 659
661 sprintf(pidfile, "/var/run/%s.pid", name); 660 sprintf(pidfile, "/var/run/%s.pid", name);
662 // Try three times to open the sucker. 661 // Try three times to open the sucker.
663 for (i=0; i<3; i++) { 662 for (i=0; i<3; i++) {
664 fd = open(pidfile, O_CREAT|O_EXCL, 0644); 663 fd = open(pidfile, O_CREAT|O_EXCL, 0644);
665 if (fd != -1) break; 664 if (fd != -1) break;
666 665
667 // If it already existed, read it. Loop for race condition. 666 // If it already existed, read it. Loop for race condition.
668 fd = open(pidfile, O_RDONLY); 667 fd = open(pidfile, O_RDONLY);
669 if (fd == -1) continue; 668 if (fd == -1) continue;
670 669
671 // Is the old program still there? 670 // Is the old program still there?
672 spid[xread(fd, spid, sizeof(spid)-1)] = 0; 671 spid[xread(fd, spid, sizeof(spid)-1)] = 0;
673 close(fd); 672 close(fd);
674 pid = atoi(spid); 673 pid = atoi(spid);
675 if (pid < 1 || kill(pid, 0) == ESRCH) unlink(pidfile); 674 if (pid < 1 || kill(pid, 0) == ESRCH) unlink(pidfile);
676 675
677 // An else with more sanity checking might be nice here. 676 // An else with more sanity checking might be nice here.
678 } 677 }
679 678
680 if (i == 3) error_exit("xpidfile %s", name); 679 if (i == 3) error_exit("xpidfile %s", name);
681 680
682 xwrite(fd, spid, sprintf(spid, "%ld\n", (long)getpid())); 681 xwrite(fd, spid, sprintf(spid, "%ld\n", (long)getpid()));
683 close(fd); 682 close(fd);
684 } 683 }
685 684
686 // Iterate through an array of files, opening each one and calling a function 685 // Iterate through an array of files, opening each one and calling a function
687 // on that filehandle and name. The special filename "-" means stdin if 686 // on that filehandle and name. The special filename "-" means stdin if
688 // flags is O_RDONLY, stdout otherwise. An empty argument list calls 687 // flags is O_RDONLY, stdout otherwise. An empty argument list calls
689 // function() on just stdin/stdout. 688 // function() on just stdin/stdout.
690 // 689 //
691 // Note: read only filehandles are automatically closed when function() 690 // Note: read only filehandles are automatically closed when function()
692 // returns, but writeable filehandles must be close by function() 691 // returns, but writeable filehandles must be close by function()
693 void loopfiles_rw(char **argv, int flags, int permissions, int failok, 692 void loopfiles_rw(char **argv, int flags, int permissions, int failok,
694 void (*function)(int fd, char *name)) 693 void (*function)(int fd, char *name))
695 { 694 {
696 int fd; 695 int fd;
697 696
698 // If no arguments, read from stdin. 697 // If no arguments, read from stdin.
699 if (!*argv) function(flags ? 1 : 0, "-"); 698 if (!*argv) function(flags ? 1 : 0, "-");
700 else do { 699 else do {
701 // Filename "-" means read from stdin. 700 // Filename "-" means read from stdin.
702 // Inability to open a file prints a warning, but doesn't exit. 701 // Inability to open a file prints a warning, but doesn't exit.
703 702
704 if (!strcmp(*argv,"-")) fd=0; 703 if (!strcmp(*argv,"-")) fd=0;
705 else if (0>(fd = open(*argv, flags, permissions)) && !failok) { 704 else if (0>(fd = open(*argv, flags, permissions)) && !failok) {
706 perror_msg("%s", *argv); 705 perror_msg("%s", *argv);
707 toys.exitval = 1; 706 toys.exitval = 1;
708 continue; 707 continue;
709 } 708 }
710 function(fd, *argv); 709 function(fd, *argv);
711 if (flags == O_RDONLY) close(fd); 710 if (flags == O_RDONLY) close(fd);
712 } while (*++argv); 711 } while (*++argv);
713 } 712 }
714 713
715 // Call loopfiles_rw with O_RDONLY and !failok (common case). 714 // Call loopfiles_rw with O_RDONLY and !failok (common case).
716 void loopfiles(char **argv, void (*function)(int fd, char *name)) 715 void loopfiles(char **argv, void (*function)(int fd, char *name))
717 { 716 {
718 loopfiles_rw(argv, O_RDONLY, 0, 0, function); 717 loopfiles_rw(argv, O_RDONLY, 0, 0, function);
719 } 718 }
720 719
721 // Slow, but small. 720 // Slow, but small.
722 721
723 char *get_rawline(int fd, long *plen, char end) 722 char *get_rawline(int fd, long *plen, char end)
724 { 723 {
725 char c, *buf = NULL; 724 char c, *buf = NULL;
726 long len = 0; 725 long len = 0;
727 726
728 for (;;) { 727 for (;;) {
729 if (1>read(fd, &c, 1)) break; 728 if (1>read(fd, &c, 1)) break;
730 if (!(len & 63)) buf=xrealloc(buf, len+65); 729 if (!(len & 63)) buf=xrealloc(buf, len+65);
731 if ((buf[len++]=c) == end) break; 730 if ((buf[len++]=c) == end) break;
732 } 731 }
733 if (buf) buf[len]=0; 732 if (buf) buf[len]=0;
734 if (plen) *plen = len; 733 if (plen) *plen = len;
735 734
736 return buf; 735 return buf;
737 } 736 }
738 737
739 char *get_line(int fd) 738 char *get_line(int fd)
740 { 739 {
741 long len; 740 long len;
742 char *buf = get_rawline(fd, &len, '\n'); 741 char *buf = get_rawline(fd, &len, '\n');
743 742
744 if (buf && buf[--len]=='\n') buf[len]=0; 743 if (buf && buf[--len]=='\n') buf[len]=0;
745 744
746 return buf; 745 return buf;
747 } 746 }
748 747
749 // Copy the rest of in to out and close both files. 748 // Copy the rest of in to out and close both files.
750 749
751 void xsendfile(int in, int out) 750 void xsendfile(int in, int out)
752 { 751 {
753 long len; 752 long len;
754 char buf[4096]; 753 char buf[4096];
755 754
756 if (in<0) return; 755 if (in<0) return;
757 for (;;) { 756 for (;;) {
758 len = xread(in, buf, 4096); 757 len = xread(in, buf, 4096);
759 if (len<1) break; 758 if (len<1) break;
760 xwrite(out, buf, len); 759 xwrite(out, buf, len);
761 } 760 }
762 } 761 }
763 762
764 int wfchmodat(int fd, char *name, mode_t mode) 763 int wfchmodat(int fd, char *name, mode_t mode)
765 { 764 {
766 int rc = fchmodat(fd, name, mode, 0); 765 int rc = fchmodat(fd, name, mode, 0);
767 766
768 if (rc) { 767 if (rc) {
769 perror_msg("chmod '%s' to %04o", name, mode); 768 perror_msg("chmod '%s' to %04o", name, mode);
770 toys.exitval=1; 769 toys.exitval=1;
771 } 770 }
772 return rc; 771 return rc;
773 } 772 }
774 773
775 static char *tempfile2zap; 774 static char *tempfile2zap;
776 static void tempfile_handler(int i) 775 static void tempfile_handler(int i)
777 { 776 {
778 if (1 < (long)tempfile2zap) unlink(tempfile2zap); 777 if (1 < (long)tempfile2zap) unlink(tempfile2zap);
779 _exit(1); 778 _exit(1);
780 } 779 }
781 780
782 // Open a temporary file to copy an existing file into. 781 // Open a temporary file to copy an existing file into.
783 int copy_tempfile(int fdin, char *name, char **tempname) 782 int copy_tempfile(int fdin, char *name, char **tempname)
784 { 783 {
785 struct stat statbuf; 784 struct stat statbuf;
786 int fd; 785 int fd;
787 786
788 *tempname = xstrndup(name, strlen(name)+6); 787 *tempname = xstrndup(name, strlen(name)+6);
789 strcat(*tempname,"XXXXXX"); 788 strcat(*tempname,"XXXXXX");
790 if(-1 == (fd = mkstemp(*tempname))) error_exit("no temp file"); 789 if(-1 == (fd = mkstemp(*tempname))) error_exit("no temp file");
791 if (!tempfile2zap) sigatexit(tempfile_handler); 790 if (!tempfile2zap) sigatexit(tempfile_handler);
792 tempfile2zap = *tempname; 791 tempfile2zap = *tempname;
793 792
794 // Set permissions of output file 793 // Set permissions of output file
795 794
796 fstat(fdin, &statbuf); 795 fstat(fdin, &statbuf);
797 fchmod(fd, statbuf.st_mode); 796 fchmod(fd, statbuf.st_mode);
798 797
799 return fd; 798 return fd;
800 } 799 }
801 800
802 // Abort the copy and delete the temporary file. 801 // Abort the copy and delete the temporary file.
803 void delete_tempfile(int fdin, int fdout, char **tempname) 802 void delete_tempfile(int fdin, int fdout, char **tempname)
804 { 803 {
805 close(fdin); 804 close(fdin);
806 close(fdout); 805 close(fdout);
807 unlink(*tempname); 806 unlink(*tempname);
808 tempfile2zap = (char *)1; 807 tempfile2zap = (char *)1;
809 free(*tempname); 808 free(*tempname);
810 *tempname = NULL; 809 *tempname = NULL;
811 } 810 }
812 811
813 // Copy the rest of the data and replace the original with the copy. 812 // Copy the rest of the data and replace the original with the copy.
814 void replace_tempfile(int fdin, int fdout, char **tempname) 813 void replace_tempfile(int fdin, int fdout, char **tempname)
815 { 814 {
816 char *temp = xstrdup(*tempname); 815 char *temp = xstrdup(*tempname);
817 816
818 temp[strlen(temp)-6]=0; 817 temp[strlen(temp)-6]=0;
819 if (fdin != -1) { 818 if (fdin != -1) {
820 xsendfile(fdin, fdout); 819 xsendfile(fdin, fdout);
821 xclose(fdin); 820 xclose(fdin);
822 } 821 }
823 xclose(fdout); 822 xclose(fdout);
824 rename(*tempname, temp); 823 rename(*tempname, temp);
825 tempfile2zap = (char *)1; 824 tempfile2zap = (char *)1;
826 free(*tempname); 825 free(*tempname);
827 free(temp); 826 free(temp);
828 *tempname = NULL; 827 *tempname = NULL;
829 } 828 }
830 829
831 // Create a 256 entry CRC32 lookup table. 830 // Create a 256 entry CRC32 lookup table.
832 831
833 void crc_init(unsigned int *crc_table, int little_endian) 832 void crc_init(unsigned int *crc_table, int little_endian)
834 { 833 {
835 unsigned int i; 834 unsigned int i;
836 835
837 // Init the CRC32 table (big endian) 836 // Init the CRC32 table (big endian)
838 for (i=0; i<256; i++) { 837 for (i=0; i<256; i++) {
839 unsigned int j, c = little_endian ? i : i<<24; 838 unsigned int j, c = little_endian ? i : i<<24;
840 for (j=8; j; j--) 839 for (j=8; j; j--)
841 if (little_endian) c = (c&1) ? (c>>1)^0xEDB88320 : c>>1; 840 if (little_endian) c = (c&1) ? (c>>1)^0xEDB88320 : c>>1;
842 else c=c&0x80000000 ? (c<<1)^0x04c11db7 : (c<<1); 841 else c=c&0x80000000 ? (c<<1)^0x04c11db7 : (c<<1);
843 crc_table[i] = c; 842 crc_table[i] = c;
844 } 843 }
845 } 844 }
846 845
847 // Quick and dirty query size of terminal, doesn't do ANSI probe fallback. 846 // Quick and dirty query size of terminal, doesn't do ANSI probe fallback.
848 // set *x=0 and *y=0 before calling to detect failure to set either, or 847 // set *x=0 and *y=0 before calling to detect failure to set either, or
849 // x=80 y=25 to provide defaults 848 // x=80 y=25 to provide defaults
850 849
851 void terminal_size(unsigned *x, unsigned *y) 850 void terminal_size(unsigned *x, unsigned *y)
852 { 851 {
853 struct winsize ws; 852 struct winsize ws;
854 int i; 853 int i;
855 854
856 //memset(&ws, 0, sizeof(ws)); 855 //memset(&ws, 0, sizeof(ws));
857 for (i=0; i<3; i++) { 856 for (i=0; i<3; i++) {
858 if (ioctl(i, TIOCGWINSZ, &ws)) continue; 857 if (ioctl(i, TIOCGWINSZ, &ws)) continue;
859 if (x) *x = ws.ws_col; 858 if (x) *x = ws.ws_col;
860 if (y) *y = ws.ws_row; 859 if (y) *y = ws.ws_row;
861 } 860 }
862 if (x) { 861 if (x) {
863 char *s = getenv("COLUMNS"); 862 char *s = getenv("COLUMNS");
864 863
865 i = s ? atoi(s) : 0; 864 i = s ? atoi(s) : 0;
866 if (i>0) *x = i; 865 if (i>0) *x = i;
867 } 866 }
868 if (y) { 867 if (y) {
869 char *s = getenv("ROWS"); 868 char *s = getenv("ROWS");
870 869
871 i = s ? atoi(s) : 0; 870 i = s ? atoi(s) : 0;
872 if (i>0) *y = i; 871 if (i>0) *y = i;
873 } 872 }
874 } 873 }
875 874
876 // This should use a raw tty, fixit later. 875 // This should use a raw tty, fixit later.
877 int yesno(char *prompt, int def) 876 int yesno(char *prompt, int def)
878 { 877 {
879 FILE *fps[] = {stdin, stdout, stderr}; 878 FILE *fps[] = {stdin, stdout, stderr};
880 int i; 879 int i;
881 char buf; 880 char buf;
882 881
883 for (i=0; i<3; i++) if (isatty(i)) break; 882 for (i=0; i<3; i++) if (isatty(i)) break;
884 if (i == 3) return 1; 883 if (i == 3) return 1;
885 884
886 fprintf(fps[i], "%s (%c/%c):", prompt, def ? 'Y' : 'y', def ? 'n' : 'N'); 885 fprintf(fps[i], "%s (%c/%c):", prompt, def ? 'Y' : 'y', def ? 'n' : 'N');
887 fflush(fps[i]); 886 fflush(fps[i]);
888 while (fread(&buf, 1, 1, fps[i])) { 887 while (fread(&buf, 1, 1, fps[i])) {
889 if (tolower(buf) == 'y') def = 1; 888 if (tolower(buf) == 'y') def = 1;
890 if (tolower(buf) == 'n') def = 0; 889 if (tolower(buf) == 'n') def = 0;
891 else if (!isspace(buf)) continue; 890 else if (!isspace(buf)) continue;
892 891
893 break; 892 break;
894 } 893 }
895 894
896 return def; 895 return def;
897 } 896 }
898 897
899 // Execute a callback for each PID that matches a process name from a list. 898 // Execute a callback for each PID that matches a process name from a list.
900 void for_each_pid_with_name_in(char **names, void (*callback)(pid_t pid)) 899 void for_each_pid_with_name_in(char **names, void (*callback)(pid_t pid))
901 { 900 {
902 DIR *dp; 901 DIR *dp;
903 struct dirent *entry; 902 struct dirent *entry;
904 char cmd[sizeof(toybuf)], path[64]; 903 char cmd[sizeof(toybuf)], path[64];
905 char **curname; 904 char **curname;
906 905
907 if (!(dp = opendir("/proc"))) perror_exit("opendir"); 906 if (!(dp = opendir("/proc"))) perror_exit("opendir");
908 907
909 while ((entry = readdir(dp))) { 908 while ((entry = readdir(dp))) {
910 int fd, n; 909 int fd, n;
911 910
912 if (!isdigit(*entry->d_name)) continue; 911 if (!isdigit(*entry->d_name)) continue;
913 912
914 if (sizeof(path) <= snprintf(path, sizeof(path), "/proc/%s/cmdline", 913 if (sizeof(path) <= snprintf(path, sizeof(path), "/proc/%s/cmdline",
915 entry->d_name)) continue; 914 entry->d_name)) continue;
916 915
917 if (-1 == (fd=open(path, O_RDONLY))) continue; 916 if (-1 == (fd=open(path, O_RDONLY))) continue;
918 n = read(fd, cmd, sizeof(cmd)); 917 n = read(fd, cmd, sizeof(cmd));
919 close(fd); 918 close(fd);
920 if (n<1) continue; 919 if (n<1) continue;
921 920
922 for (curname = names; *curname; curname++) 921 for (curname = names; *curname; curname++)
923 if (!strcmp(basename(cmd), *curname)) 922 if (!strcmp(basename(cmd), *curname)) callback(atol(entry->d_name));
924 callback(atol(entry->d_name)); 923 }
925 } 924
926 925 closedir(dp);
927 closedir(dp);
928 } 926 }
929 927
930 struct signame { 928 struct signame {
931 int num; 929 int num;
932 char *name; 930 char *name;
933 }; 931 };
934 932
935 // Signals required by POSIX 2008: 933 // Signals required by POSIX 2008:
936 // http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html 934 // http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html
937 935
938 #define SIGNIFY(x) {SIG##x, #x} 936 #define SIGNIFY(x) {SIG##x, #x}
939 937
940 static struct signame signames[] = { 938 static struct signame signames[] = {
941 SIGNIFY(ABRT), SIGNIFY(ALRM), SIGNIFY(BUS), 939 SIGNIFY(ABRT), SIGNIFY(ALRM), SIGNIFY(BUS),
942 SIGNIFY(FPE), SIGNIFY(HUP), SIGNIFY(ILL), SIGNIFY(INT), SIGNIFY(KILL), 940 SIGNIFY(FPE), SIGNIFY(HUP), SIGNIFY(ILL), SIGNIFY(INT), SIGNIFY(KILL),
943 SIGNIFY(PIPE), SIGNIFY(QUIT), SIGNIFY(SEGV), SIGNIFY(TERM), 941 SIGNIFY(PIPE), SIGNIFY(QUIT), SIGNIFY(SEGV), SIGNIFY(TERM),
944 SIGNIFY(USR1), SIGNIFY(USR2), SIGNIFY(SYS), SIGNIFY(TRAP), 942 SIGNIFY(USR1), SIGNIFY(USR2), SIGNIFY(SYS), SIGNIFY(TRAP),
945 SIGNIFY(VTALRM), SIGNIFY(XCPU), SIGNIFY(XFSZ), 943 SIGNIFY(VTALRM), SIGNIFY(XCPU), SIGNIFY(XFSZ),
946 944
947 // Start of non-terminal signals 945 // Start of non-terminal signals
948 946
949 SIGNIFY(CHLD), SIGNIFY(CONT), SIGNIFY(STOP), SIGNIFY(TSTP), 947 SIGNIFY(CHLD), SIGNIFY(CONT), SIGNIFY(STOP), SIGNIFY(TSTP),
950 SIGNIFY(TTIN), SIGNIFY(TTOU), SIGNIFY(URG) 948 SIGNIFY(TTIN), SIGNIFY(TTOU), SIGNIFY(URG)
951 }; 949 };
952 950
953 // not in posix: SIGNIFY(STKFLT), SIGNIFY(WINCH), SIGNIFY(IO), SIGNIFY(PWR) 951 // not in posix: SIGNIFY(STKFLT), SIGNIFY(WINCH), SIGNIFY(IO), SIGNIFY(PWR)
954 // obsolete: SIGNIFY(PROF) SIGNIFY(POLL) 952 // obsolete: SIGNIFY(PROF) SIGNIFY(POLL)
955 953
956 // Install the same handler on every signal that defaults to killing the process 954 // Install the same handler on every signal that defaults to killing the process
957 void sigatexit(void *handler) 955 void sigatexit(void *handler)
958 { 956 {
959 int i; 957 int i;
960 for (i=0; signames[i].num != SIGCHLD; i++) 958 for (i=0; signames[i].num != SIGCHLD; i++) signal(signames[i].num, handler);
961 signal(signames[i].num, handler);
962 } 959 }
963 // Convert name to signal number. If name == NULL print names. 960 // Convert name to signal number. If name == NULL print names.
964 int sig_to_num(char *pidstr) 961 int sig_to_num(char *pidstr)
965 { 962 {
966 int i; 963 int i;
967 964
968 if (pidstr) { 965 if (pidstr) {
969 char *s; 966 char *s;
970 i = strtol(pidstr, &s, 10); 967 i = strtol(pidstr, &s, 10);
971 if (!*s) return i; 968 if (!*s) return i;
972 969
973 if (!strncasecmp(pidstr, "sig", 3)) pidstr+=3; 970 if (!strncasecmp(pidstr, "sig", 3)) pidstr+=3;
974 } 971 }
975 for (i = 0; i < sizeof(signames)/sizeof(struct signame); i++) 972 for (i = 0; i < sizeof(signames)/sizeof(struct signame); i++)
976 if (!pidstr) xputs(signames[i].name); 973 if (!pidstr) xputs(signames[i].name);
977 else if (!strcasecmp(pidstr, signames[i].name)) 974 else if (!strcasecmp(pidstr, signames[i].name)) return signames[i].num;
978 return signames[i].num; 975
979 976 return -1;
980 return -1;
981 } 977 }
982 978
983 char *num_to_sig(int sig) 979 char *num_to_sig(int sig)
984 { 980 {
985 int i; 981 int i;
986 982
987 for (i=0; i<sizeof(signames)/sizeof(struct signame); i++) 983 for (i=0; i<sizeof(signames)/sizeof(struct signame); i++)
988 if (signames[i].num == sig) return signames[i].name; 984 if (signames[i].num == sig) return signames[i].name;
989 return NULL; 985 return NULL;
990 } 986 }
991 987
992 // premute mode bits based on posix mode strings. 988 // premute mode bits based on posix mode strings.
993 mode_t string_to_mode(char *modestr, mode_t mode) 989 mode_t string_to_mode(char *modestr, mode_t mode)
994 { 990 {
995 char *whos = "ogua", *hows = "=+-", *whats = "xwrstX", *whys = "ogu"; 991 char *whos = "ogua", *hows = "=+-", *whats = "xwrstX", *whys = "ogu";
996 char *s, *str = modestr; 992 char *s, *str = modestr;
997 993
998 // Handle octal mode 994 // Handle octal mode
999 if (isdigit(*str)) { 995 if (isdigit(*str)) {
1000 mode = strtol(str, &s, 8); 996 mode = strtol(str, &s, 8);
1001 if (*s || (mode & ~(07777))) goto barf; 997 if (*s || (mode & ~(07777))) goto barf;
1002 998
1003 return mode; 999 return mode;
1004 } 1000 }
1005 1001
1006 // Gaze into the bin of permission... 1002 // Gaze into the bin of permission...
1007 for (;;) { 1003 for (;;) {
1008 int i, j, dowho, dohow, dowhat, amask; 1004 int i, j, dowho, dohow, dowhat, amask;
1009 1005
1010 dowho = dohow = dowhat = amask = 0; 1006 dowho = dohow = dowhat = amask = 0;
1011 1007
1012 // Find the who, how, and what stanzas, in that order 1008 // Find the who, how, and what stanzas, in that order
1013 while (*str && (s = strchr(whos, *str))) { 1009 while (*str && (s = strchr(whos, *str))) {
1014 dowho |= 1<<(s-whos); 1010 dowho |= 1<<(s-whos);
1015 str++; 1011 str++;
1016 } 1012 }
1017 // If who isn't specified, like "a" but honoring umask. 1013 // If who isn't specified, like "a" but honoring umask.
1018 if (!dowho) { 1014 if (!dowho) {
1019 dowho = 8; 1015 dowho = 8;
1020 umask(amask=umask(0)); 1016 umask(amask=umask(0));
1021 } 1017 }
1022 if (!*str || !(s = strchr(hows, *str))) goto barf; 1018 if (!*str || !(s = strchr(hows, *str))) goto barf;
1023 dohow = *(str++); 1019 dohow = *(str++);
1024 1020
1025 if (!dohow) goto barf; 1021 if (!dohow) goto barf;
1026 while (*str && (s = strchr(whats, *str))) { 1022 while (*str && (s = strchr(whats, *str))) {
1027 dowhat |= 1<<(s-whats); 1023 dowhat |= 1<<(s-whats);
1028 str++; 1024 str++;
1029 } 1025 }
1030 1026
1031 // Convert X to x for directory or if already executable somewhere 1027 // Convert X to x for directory or if already executable somewhere
1032 if ((dowhat&32) && (S_ISDIR(mode) || (mode&0111))) dowhat |= 1; 1028 if ((dowhat&32) && (S_ISDIR(mode) || (mode&0111))) dowhat |= 1;
1033 1029
1034 // Copy mode from another category? 1030 // Copy mode from another category?
1035 if (!dowhat && *str && (s = strchr(whys, *str))) { 1031 if (!dowhat && *str && (s = strchr(whys, *str))) {
1036 dowhat = (mode>>(3*(s-whys)))&7; 1032 dowhat = (mode>>(3*(s-whys)))&7;
1037 str++; 1033 str++;
1038 } 1034 }
1039 1035
1040 // Are we ready to do a thing yet? 1036 // Are we ready to do a thing yet?
1041 if (*str && *(str++) != ',') goto barf; 1037 if (*str && *(str++) != ',') goto barf;
1042 1038
1043 // Ok, apply the bits to the mode. 1039 // Ok, apply the bits to the mode.
1044 for (i=0; i<4; i++) { 1040 for (i=0; i<4; i++) {
1045 for (j=0; j<3; j++) { 1041 for (j=0; j<3; j++) {
1046 mode_t bit = 0; 1042 mode_t bit = 0;
1047 int where = 1<<((3*i)+j); 1043 int where = 1<<((3*i)+j);
1048 1044
1049 if (amask & where) continue; 1045 if (amask & where) continue;
1050 1046
1051 // Figure out new value at this location 1047 // Figure out new value at this location
1052 if (i == 3) { 1048 if (i == 3) {
1053 // suid/sticky bit. 1049 // suid/sticky bit.
1054 if (j) { 1050 if (j) {
1055 if ((dowhat & 8) && (dowho&(8|(1<<i)))) bit++; 1051 if ((dowhat & 8) && (dowho&(8|(1<<i)))) bit++;
1056 } else if (dowhat & 16) bit++; 1052 } else if (dowhat & 16) bit++;
1057 } else { 1053 } else {
1058 if (!(dowho&(8|(1<<i)))) continue; 1054 if (!(dowho&(8|(1<<i)))) continue;
1059 if (dowhat&(1<<j)) bit++; 1055 if (dowhat&(1<<j)) bit++;
1060 } 1056 }
1061 1057
1062 // When selection active, modify bit 1058 // When selection active, modify bit
1063 1059
1064 if (dohow == '=' || (bit && dohow == '-')) 1060 if (dohow == '=' || (bit && dohow == '-')) mode &= ~where;
1065 mode &= ~where; 1061 if (bit && dohow != '-') mode |= where;
1066 if (bit && dohow != '-') mode |= where; 1062 }
1067 } 1063 }
1068 } 1064
1069 1065 if (!*str) break;
1070 if (!*str) break; 1066 }
1071 } 1067 return mode;
1072 return mode;
1073 barf: 1068 barf:
1074 error_exit("bad mode '%s'", modestr); 1069 error_exit("bad mode '%s'", modestr);
1075 } 1070 }
1076 1071
1077 1072
1078 char* make_human_readable(unsigned long long size, unsigned long unit) 1073 char* make_human_readable(unsigned long long size, unsigned long unit)
1079 { 1074 {
1080 unsigned int frac = 0; 1075 unsigned int frac = 0;
1081 if(unit) { 1076 if(unit) {
1082 size = (size/(unit)) + (size%(unit)?1:0); 1077 size = (size/(unit)) + (size%(unit)?1:0);
1083 return xmsprintf("%llu", size); 1078 return xmsprintf("%llu", size);
1084 } 1079 }
1085 else { 1080 else {
1086 static char units[] = {'\0', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'}; 1081 static char units[] = {'\0', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'};
1087 int index = 0; 1082 int index = 0;
1088 while(size >= 1024) { 1083 while(size >= 1024) {
1089 frac = size%1024; 1084 frac = size%1024;
1090 size /= 1024; 1085 size /= 1024;
1091 index++; 1086 index++;
1092 } 1087 }
1093 frac = (frac/102) + ((frac%102)?1:0); 1088 frac = (frac/102) + ((frac%102)?1:0);
1094 if(frac >= 10) { 1089 if(frac >= 10) {
1095 size += 1; 1090 size += 1;
1096 frac = 0; 1091 frac = 0;
1097 } 1092 }
1098 if(frac) return xmsprintf("%llu.%u%c", size, frac, units[index]); 1093 if(frac) return xmsprintf("%llu.%u%c", size, frac, units[index]);
1099 else return xmsprintf("%llu%c", size, units[index]); 1094 else return xmsprintf("%llu%c", size, units[index]);
1100 } 1095 }
1101 return NULL; //not reached 1096 return NULL; //not reached
1102 } 1097 }