blob: 06828a402bd5eff986da8d5082d9b46ea1dca08c [file] [log] [blame]
Charlie Shepherd54524c92008-01-25 12:36:24 +00001/* lib.c - reusable stuff.
landley4f344e32006-10-05 16:18:03 -04002 *
landleycd9dfc32006-10-18 18:38:16 -04003 * Functions with the x prefix are wrappers for library functions. They either
4 * succeed or kill the program with an error message, but never return failure.
5 * They usually have the same arguments and return value as the function they
6 * wrap.
landley09ea7ac2006-10-30 01:38:00 -05007 *
8 * Copyright 2006 Rob Landley <rob@landley.net>
landley4f344e32006-10-05 16:18:03 -04009 */
10
11#include "toys.h"
12
Rob Landleye15850a2007-11-19 01:51:00 -060013// Strcpy with size checking: exit if there's not enough space for the string.
14void xstrcpy(char *dest, char *src, size_t size)
Rob Landley18d43ff2007-06-07 15:19:44 -040015{
Rob Landley7aa651a2012-11-13 17:14:08 -060016 if (strlen(src)+1 > size) error_exit("xstrcpy");
17 strcpy(dest, src);
Rob Landley18d43ff2007-06-07 15:19:44 -040018}
Rob Landley18d43ff2007-06-07 15:19:44 -040019
landley09ea7ac2006-10-30 01:38:00 -050020void verror_msg(char *msg, int err, va_list va)
21{
Rob Landley7aa651a2012-11-13 17:14:08 -060022 char *s = ": %s";
Rob Landley12138e42008-01-27 15:26:08 -060023
Rob Landley7aa651a2012-11-13 17:14:08 -060024 fprintf(stderr, "%s: ", toys.which->name);
25 if (msg) vfprintf(stderr, msg, va);
26 else s+=2;
27 if (err) fprintf(stderr, s, strerror(err));
28 putc('\n', stderr);
landley09ea7ac2006-10-30 01:38:00 -050029}
30
31void error_msg(char *msg, ...)
32{
Rob Landley7aa651a2012-11-13 17:14:08 -060033 va_list va;
landley09ea7ac2006-10-30 01:38:00 -050034
Rob Landley7aa651a2012-11-13 17:14:08 -060035 va_start(va, msg);
36 verror_msg(msg, 0, va);
37 va_end(va);
landley09ea7ac2006-10-30 01:38:00 -050038}
39
40void perror_msg(char *msg, ...)
41{
Rob Landley7aa651a2012-11-13 17:14:08 -060042 va_list va;
landley09ea7ac2006-10-30 01:38:00 -050043
Rob Landley7aa651a2012-11-13 17:14:08 -060044 va_start(va, msg);
45 verror_msg(msg, errno, va);
46 va_end(va);
landley09ea7ac2006-10-30 01:38:00 -050047}
48
landley4f344e32006-10-05 16:18:03 -040049// Die with an error message.
50void error_exit(char *msg, ...)
51{
Rob Landley7aa651a2012-11-13 17:14:08 -060052 va_list va;
landley4f344e32006-10-05 16:18:03 -040053
Rob Landley7aa651a2012-11-13 17:14:08 -060054 if (CFG_HELP && toys.exithelp) {
55 *toys.optargs=*toys.argv;
56 USE_HELP(help_main();) // dear gcc: shut up.
57 fprintf(stderr,"\n");
58 }
Rob Landleyd06c58d2007-10-11 15:36:36 -050059
Rob Landley7aa651a2012-11-13 17:14:08 -060060 va_start(va, msg);
61 verror_msg(msg, 0, va);
62 va_end(va);
landley09ea7ac2006-10-30 01:38:00 -050063
Rob Landley7aa651a2012-11-13 17:14:08 -060064 exit(!toys.exitval ? 1 : toys.exitval);
landley09ea7ac2006-10-30 01:38:00 -050065}
66
Rob Landley055cfcb2007-01-14 20:20:06 -050067
landley09ea7ac2006-10-30 01:38:00 -050068// Die with an error message and strerror(errno)
69void perror_exit(char *msg, ...)
70{
Rob Landley7aa651a2012-11-13 17:14:08 -060071 va_list va;
landley09ea7ac2006-10-30 01:38:00 -050072
Rob Landley7aa651a2012-11-13 17:14:08 -060073 va_start(va, msg);
74 verror_msg(msg, errno, va);
75 va_end(va);
landley09ea7ac2006-10-30 01:38:00 -050076
Rob Landley7aa651a2012-11-13 17:14:08 -060077 exit(!toys.exitval ? 1 : toys.exitval);
landley4f344e32006-10-05 16:18:03 -040078}
79
landley4f344e32006-10-05 16:18:03 -040080// Die unless we can allocate memory.
81void *xmalloc(size_t size)
82{
Rob Landley7aa651a2012-11-13 17:14:08 -060083 void *ret = malloc(size);
84 if (!ret) error_exit("xmalloc");
landleycd9dfc32006-10-18 18:38:16 -040085
Rob Landley7aa651a2012-11-13 17:14:08 -060086 return ret;
landley4f344e32006-10-05 16:18:03 -040087}
88
landleycd9dfc32006-10-18 18:38:16 -040089// Die unless we can allocate prezeroed memory.
90void *xzalloc(size_t size)
91{
Rob Landley7aa651a2012-11-13 17:14:08 -060092 void *ret = xmalloc(size);
93 memset(ret, 0, size);
94 return ret;
landleycd9dfc32006-10-18 18:38:16 -040095}
96
97// Die unless we can change the size of an existing allocation, possibly
98// moving it. (Notice different arguments from libc function.)
Rob Landley0c93f6c2007-04-29 19:55:21 -040099void *xrealloc(void *ptr, size_t size)
landleycd9dfc32006-10-18 18:38:16 -0400100{
Rob Landley7aa651a2012-11-13 17:14:08 -0600101 ptr = realloc(ptr, size);
102 if (!ptr) error_exit("xrealloc");
Rob Landley0c93f6c2007-04-29 19:55:21 -0400103
Rob Landley7aa651a2012-11-13 17:14:08 -0600104 return ptr;
landleycd9dfc32006-10-18 18:38:16 -0400105}
106
Rob Landleyfa98d012006-11-02 02:57:27 -0500107// Die unless we can allocate a copy of this many bytes of string.
Rob Landley1e01cd12010-01-05 10:48:32 -0600108char *xstrndup(char *s, size_t n)
landley4f344e32006-10-05 16:18:03 -0400109{
Rob Landley7aa651a2012-11-13 17:14:08 -0600110 char *ret = xmalloc(++n);
111 strncpy(ret, s, n);
112 ret[--n]=0;
Rob Landley2c226852007-11-15 18:30:30 -0600113
Rob Landley7aa651a2012-11-13 17:14:08 -0600114 return ret;
landley4f344e32006-10-05 16:18:03 -0400115}
116
Rob Landleyfa98d012006-11-02 02:57:27 -0500117// Die unless we can allocate a copy of this string.
Rob Landley1e01cd12010-01-05 10:48:32 -0600118char *xstrdup(char *s)
Rob Landleyfa98d012006-11-02 02:57:27 -0500119{
Rob Landley7aa651a2012-11-13 17:14:08 -0600120 return xstrndup(s, strlen(s));
Rob Landleyfa98d012006-11-02 02:57:27 -0500121}
122
landley00f87f12006-10-25 18:38:37 -0400123// Die unless we can allocate enough space to sprintf() into.
124char *xmsprintf(char *format, ...)
125{
Rob Landley7aa651a2012-11-13 17:14:08 -0600126 va_list va, va2;
127 int len;
128 char *ret;
Rob Landley2c226852007-11-15 18:30:30 -0600129
Rob Landley7aa651a2012-11-13 17:14:08 -0600130 va_start(va, format);
131 va_copy(va2, va);
Rob Landley0d8dfb22007-06-15 15:16:46 -0400132
Rob Landley7aa651a2012-11-13 17:14:08 -0600133 // How long is it?
134 len = vsnprintf(0, 0, format, va);
135 len++;
136 va_end(va);
landley00f87f12006-10-25 18:38:37 -0400137
Rob Landley7aa651a2012-11-13 17:14:08 -0600138 // Allocate and do the sprintf()
139 ret = xmalloc(len);
140 vsnprintf(ret, len, format, va2);
141 va_end(va2);
landley00f87f12006-10-25 18:38:37 -0400142
Rob Landley7aa651a2012-11-13 17:14:08 -0600143 return ret;
landley00f87f12006-10-25 18:38:37 -0400144}
145
Rob Landley24d1d452007-01-20 18:04:20 -0500146void xprintf(char *format, ...)
147{
Rob Landley7aa651a2012-11-13 17:14:08 -0600148 va_list va;
149 va_start(va, format);
Rob Landley24d1d452007-01-20 18:04:20 -0500150
Rob Landley7aa651a2012-11-13 17:14:08 -0600151 vprintf(format, va);
152 if (ferror(stdout)) perror_exit("write");
Rob Landley24d1d452007-01-20 18:04:20 -0500153}
154
Rob Landley5084fea2007-06-18 00:14:03 -0400155void xputs(char *s)
156{
Rob Landley7aa651a2012-11-13 17:14:08 -0600157 if (EOF == puts(s)) perror_exit("write");
Rob Landley5084fea2007-06-18 00:14:03 -0400158}
159
Rob Landley24d1d452007-01-20 18:04:20 -0500160void xputc(char c)
161{
Rob Landley7aa651a2012-11-13 17:14:08 -0600162 if (EOF == fputc(c, stdout) || fflush(stdout)) perror_exit("write");
Rob Landley24d1d452007-01-20 18:04:20 -0500163}
164
165void xflush(void)
166{
Rob Landley7aa651a2012-11-13 17:14:08 -0600167 if (fflush(stdout)) perror_exit("write");;
Rob Landley24d1d452007-01-20 18:04:20 -0500168}
169
landleycd9dfc32006-10-18 18:38:16 -0400170// Die unless we can exec argv[] (or run builtin command). Note that anything
171// with a path isn't a builtin, so /bin/sh won't match the builtin sh.
landley09ea7ac2006-10-30 01:38:00 -0500172void xexec(char **argv)
landley4f344e32006-10-05 16:18:03 -0400173{
Rob Landley7aa651a2012-11-13 17:14:08 -0600174 toy_exec(argv);
175 execvp(argv[0], argv);
Rob Landley26e7b5e2012-02-02 07:27:35 -0600176
Rob Landley7aa651a2012-11-13 17:14:08 -0600177 perror_exit("exec %s", argv[0]);
landley4f344e32006-10-05 16:18:03 -0400178}
179
Rob Landleyd3e9d642007-01-08 03:25:47 -0500180void xaccess(char *path, int flags)
181{
Rob Landley7aa651a2012-11-13 17:14:08 -0600182 if (access(path, flags)) perror_exit("Can't access '%s'", path);
Rob Landleyd3e9d642007-01-08 03:25:47 -0500183}
184
Rob Landleye745d8e2007-12-20 06:30:19 -0600185// Die unless we can delete a file. (File must exist to be deleted.)
186void xunlink(char *path)
187{
Rob Landley7aa651a2012-11-13 17:14:08 -0600188 if (unlink(path)) perror_exit("unlink '%s'", path);
Rob Landleye745d8e2007-12-20 06:30:19 -0600189}
190
landley4f344e32006-10-05 16:18:03 -0400191// Die unless we can open/create a file, returning file descriptor.
Rob Landley1322beb2007-01-07 22:51:12 -0500192int xcreate(char *path, int flags, int mode)
landley4f344e32006-10-05 16:18:03 -0400193{
Rob Landley7aa651a2012-11-13 17:14:08 -0600194 int fd = open(path, flags, mode);
195 if (fd == -1) perror_exit("%s", path);
196 return fd;
landley4f344e32006-10-05 16:18:03 -0400197}
198
Rob Landley1322beb2007-01-07 22:51:12 -0500199// Die unless we can open a file, returning file descriptor.
200int xopen(char *path, int flags)
201{
Rob Landley7aa651a2012-11-13 17:14:08 -0600202 return xcreate(path, flags, 0);
Rob Landley1322beb2007-01-07 22:51:12 -0500203}
204
Rob Landleybc078652007-12-15 21:47:25 -0600205void xclose(int fd)
206{
Rob Landley7aa651a2012-11-13 17:14:08 -0600207 if (close(fd)) perror_exit("xclose");
Rob Landleybc078652007-12-15 21:47:25 -0600208}
209
Rob Landleyeb7ea222012-04-14 22:30:41 -0500210int xdup(int fd)
211{
Rob Landley7aa651a2012-11-13 17:14:08 -0600212 if (fd != -1) {
213 fd = dup(fd);
214 if (fd == -1) perror_exit("xdup");
215 }
216 return fd;
Rob Landleyeb7ea222012-04-14 22:30:41 -0500217}
218
landley4f344e32006-10-05 16:18:03 -0400219// Die unless we can open/create a file, returning FILE *.
220FILE *xfopen(char *path, char *mode)
221{
Rob Landley7aa651a2012-11-13 17:14:08 -0600222 FILE *f = fopen(path, mode);
223 if (!f) perror_exit("No file %s", path);
224 return f;
landley4f344e32006-10-05 16:18:03 -0400225}
landley00f87f12006-10-25 18:38:37 -0400226
landley64b2e232006-10-30 10:01:19 -0500227// Keep reading until full or EOF
Rob Landley90163772007-01-18 21:54:08 -0500228ssize_t readall(int fd, void *buf, size_t len)
landley64b2e232006-10-30 10:01:19 -0500229{
Rob Landley7aa651a2012-11-13 17:14:08 -0600230 size_t count = 0;
Rob Landley15b23152008-07-18 04:15:59 -0500231
Rob Landley7aa651a2012-11-13 17:14:08 -0600232 while (count<len) {
233 int i = read(fd, buf+count, len-count);
234 if (!i) break;
235 if (i<0) return i;
236 count += i;
237 }
landley64b2e232006-10-30 10:01:19 -0500238
Rob Landley7aa651a2012-11-13 17:14:08 -0600239 return count;
landley64b2e232006-10-30 10:01:19 -0500240}
241
Rob Landleyf3e452a2007-01-08 02:49:39 -0500242// Keep writing until done or EOF
Rob Landley90163772007-01-18 21:54:08 -0500243ssize_t writeall(int fd, void *buf, size_t len)
Rob Landleyf3e452a2007-01-08 02:49:39 -0500244{
Rob Landley7aa651a2012-11-13 17:14:08 -0600245 size_t count = 0;
246 while (count<len) {
247 int i = write(fd, buf+count, len-count);
248 if (i<1) return i;
249 count += i;
250 }
Rob Landleyf3e452a2007-01-08 02:49:39 -0500251
Rob Landley7aa651a2012-11-13 17:14:08 -0600252 return count;
Rob Landleyf3e452a2007-01-08 02:49:39 -0500253}
254
Rob Landley055cfcb2007-01-14 20:20:06 -0500255// Die if there's an error other than EOF.
Rob Landley90163772007-01-18 21:54:08 -0500256size_t xread(int fd, void *buf, size_t len)
landley64b2e232006-10-30 10:01:19 -0500257{
Rob Landley7aa651a2012-11-13 17:14:08 -0600258 ssize_t ret = read(fd, buf, len);
259 if (ret < 0) perror_exit("xread");
Rob Landley055cfcb2007-01-14 20:20:06 -0500260
Rob Landley7aa651a2012-11-13 17:14:08 -0600261 return ret;
Rob Landley055cfcb2007-01-14 20:20:06 -0500262}
263
Rob Landley90163772007-01-18 21:54:08 -0500264void xreadall(int fd, void *buf, size_t len)
Rob Landley055cfcb2007-01-14 20:20:06 -0500265{
Rob Landley7aa651a2012-11-13 17:14:08 -0600266 if (len != readall(fd, buf, len)) perror_exit("xreadall");
Rob Landley055cfcb2007-01-14 20:20:06 -0500267}
landley00f87f12006-10-25 18:38:37 -0400268
Rob Landley90163772007-01-18 21:54:08 -0500269// There's no xwriteall(), just xwrite(). When we read, there may or may not
270// be more data waiting. When we write, there is data and it had better go
271// somewhere.
272
273void xwrite(int fd, void *buf, size_t len)
Rob Landleyf3e452a2007-01-08 02:49:39 -0500274{
Rob Landley7aa651a2012-11-13 17:14:08 -0600275 if (len != writeall(fd, buf, len)) perror_exit("xwrite");
Rob Landleyf3e452a2007-01-08 02:49:39 -0500276}
277
Rob Landley52476712009-01-18 16:19:25 -0600278// Die if lseek fails, probably due to being called on a pipe.
279
280off_t xlseek(int fd, off_t offset, int whence)
281{
Rob Landley7aa651a2012-11-13 17:14:08 -0600282 offset = lseek(fd, offset, whence);
283 if (offset<0) perror_exit("lseek");
Rob Landley52476712009-01-18 16:19:25 -0600284
Rob Landley7aa651a2012-11-13 17:14:08 -0600285 return offset;
Rob Landley52476712009-01-18 16:19:25 -0600286}
287
Rob Landley2037b832012-07-15 16:56:20 -0500288off_t lskip(int fd, off_t offset)
289{
Rob Landley7aa651a2012-11-13 17:14:08 -0600290 off_t and = lseek(fd, offset, SEEK_CUR);
Rob Landley2037b832012-07-15 16:56:20 -0500291
Rob Landley7aa651a2012-11-13 17:14:08 -0600292 if (and != -1 && offset >= lseek(fd, offset, SEEK_END)
293 && offset+and == lseek(fd, offset+and, SEEK_SET)) return 0;
294 else {
295 char buf[4096];
296 while (offset>0) {
297 int try = offset>sizeof(buf) ? sizeof(buf) : offset, or;
Rob Landley2037b832012-07-15 16:56:20 -0500298
Rob Landley7aa651a2012-11-13 17:14:08 -0600299 or = readall(fd, buf, try);
300 if (or < 0) perror_msg("lskip to %lld", (long long)offset);
301 else offset -= try;
302 if (or < try) break;
303 }
Rob Landley2037b832012-07-15 16:56:20 -0500304
Rob Landley7aa651a2012-11-13 17:14:08 -0600305 return offset;
306 }
Rob Landley2037b832012-07-15 16:56:20 -0500307}
308
landley00f87f12006-10-25 18:38:37 -0400309char *xgetcwd(void)
310{
Rob Landley7aa651a2012-11-13 17:14:08 -0600311 char *buf = getcwd(NULL, 0);
312 if (!buf) perror_exit("xgetcwd");
landley09ea7ac2006-10-30 01:38:00 -0500313
Rob Landley7aa651a2012-11-13 17:14:08 -0600314 return buf;
landley00f87f12006-10-25 18:38:37 -0400315}
316
Rob Landleyd25f7e42007-02-03 14:11:26 -0500317void xstat(char *path, struct stat *st)
318{
Rob Landley7aa651a2012-11-13 17:14:08 -0600319 if(stat(path, st)) perror_exit("Can't stat %s", path);
Rob Landleyd25f7e42007-02-03 14:11:26 -0500320}
321
Rob Landleyfa98d012006-11-02 02:57:27 -0500322// Cannonicalizes path by removing ".", "..", and "//" elements. This is not
Rob Landleyc6f481c2006-12-30 22:01:47 -0500323// the same as realpath(), where "dir/.." could wind up somewhere else by
324// following symlinks.
Rob Landleyfa98d012006-11-02 02:57:27 -0500325char *xabspath(char *path)
landley00f87f12006-10-25 18:38:37 -0400326{
Rob Landley7aa651a2012-11-13 17:14:08 -0600327 char *from, *to;
landley00f87f12006-10-25 18:38:37 -0400328
Rob Landley7aa651a2012-11-13 17:14:08 -0600329 // If this isn't an absolute path, make it one with cwd.
330 if (path[0]!='/') {
331 char *cwd=xgetcwd();
332 path = xmsprintf("%s/%s", cwd, path);
333 free(cwd);
334 } else path = xstrdup(path);
landley00f87f12006-10-25 18:38:37 -0400335
Rob Landley7aa651a2012-11-13 17:14:08 -0600336 // Loop through path elements
337 from = to = path;
338 while (*from) {
Rob Landleyfa98d012006-11-02 02:57:27 -0500339
Rob Landley7aa651a2012-11-13 17:14:08 -0600340 // Continue any current path component.
341 if (*from!='/') {
342 *(to++) = *(from++);
343 continue;
344 }
Rob Landleyfa98d012006-11-02 02:57:27 -0500345
Rob Landley7aa651a2012-11-13 17:14:08 -0600346 // Skip duplicate slashes.
347 while (*from=='/') from++;
Rob Landley2c226852007-11-15 18:30:30 -0600348
Rob Landley7aa651a2012-11-13 17:14:08 -0600349 // Start of a new filename. Handle . and ..
350 while (*from=='.') {
351 // Skip .
352 if (from[1]=='/') from += 2;
353 else if (!from[1]) from++;
354 // Back up for ..
355 else if (from[1]=='.') {
356 if (from[2]=='/') from +=3;
357 else if(!from[2]) from+=2;
358 else break;
359 while (to>path && *(--to)!='/');
360 } else break;
361 }
362 // Add directory separator slash.
363 *(to++) = '/';
364 }
365 *to = 0;
Rob Landleyfa98d012006-11-02 02:57:27 -0500366
Rob Landley7aa651a2012-11-13 17:14:08 -0600367 return path;
Rob Landleyfa98d012006-11-02 02:57:27 -0500368}
369
Rob Landleyeec46372012-06-01 13:50:41 -0500370// Resolve all symlinks, returning malloc() memory.
371char *xrealpath(char *path)
372{
Rob Landley7aa651a2012-11-13 17:14:08 -0600373 char *new = realpath(path, NULL);
374 if (!new) perror_exit("realpath '%s'", path);
375 return new;
Rob Landleyeec46372012-06-01 13:50:41 -0500376}
377
Rob Landley988abb32008-05-12 00:52:27 -0500378void xchdir(char *path)
379{
Rob Landley7aa651a2012-11-13 17:14:08 -0600380 if (chdir(path)) error_exit("chdir '%s'", path);
Rob Landley988abb32008-05-12 00:52:27 -0500381}
382
Rob Landley35483412007-12-27 21:36:33 -0600383// Ensure entire path exists.
384// If mode != -1 set permissions on newly created dirs.
385// Requires that path string be writable (for temporary null terminators).
386void xmkpath(char *path, int mode)
387{
Rob Landley7aa651a2012-11-13 17:14:08 -0600388 char *p, old;
389 mode_t mask;
390 int rc;
391 struct stat st;
Rob Landley35483412007-12-27 21:36:33 -0600392
Rob Landley7aa651a2012-11-13 17:14:08 -0600393 for (p = path; ; p++) {
394 if (!*p || *p == '/') {
395 old = *p;
396 *p = rc = 0;
397 if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
398 if (mode != -1) {
399 mask=umask(0);
400 rc = mkdir(path, mode);
401 umask(mask);
402 } else rc = mkdir(path, 0777);
403 }
404 *p = old;
405 if(rc) perror_exit("mkpath '%s'", path);
406 }
407 if (!*p) break;
408 }
Rob Landley35483412007-12-27 21:36:33 -0600409}
Rob Landleye0377fb2010-01-05 12:17:05 -0600410
411// setuid() can fail (for example, too many processes belonging to that user),
412// which opens a security hole if the process continues as the original user.
413
414void xsetuid(uid_t uid)
415{
Rob Landley7aa651a2012-11-13 17:14:08 -0600416 if (setuid(uid)) perror_exit("xsetuid");
Rob Landleye0377fb2010-01-05 12:17:05 -0600417}
418
419
Rob Landley0a04b3e2006-11-03 00:05:52 -0500420// Find all file in a colon-separated path with access type "type" (generally
421// X_OK or R_OK). Returns a list of absolute paths to each file found, in
422// order.
423
424struct string_list *find_in_path(char *path, char *filename)
Rob Landleyfa98d012006-11-02 02:57:27 -0500425{
Rob Landley7aa651a2012-11-13 17:14:08 -0600426 struct string_list *rlist = NULL, **prlist=&rlist;
427 char *cwd = xgetcwd();
Rob Landleyfa98d012006-11-02 02:57:27 -0500428
Rob Landley7aa651a2012-11-13 17:14:08 -0600429 for (;;) {
430 char *next = path ? strchr(path, ':') : NULL;
431 int len = next ? next-path : strlen(path);
432 struct string_list *rnext;
433 struct stat st;
Rob Landleyfa98d012006-11-02 02:57:27 -0500434
Rob Landley7aa651a2012-11-13 17:14:08 -0600435 rnext = xmalloc(sizeof(void *) + strlen(filename)
436 + (len ? len : strlen(cwd)) + 2);
437 if (!len) sprintf(rnext->str, "%s/%s", cwd, filename);
438 else {
439 char *res = rnext->str;
440 strncpy(res, path, len);
441 res += len;
442 *(res++) = '/';
443 strcpy(res, filename);
444 }
Rob Landleyfa98d012006-11-02 02:57:27 -0500445
Rob Landley7aa651a2012-11-13 17:14:08 -0600446 // Confirm it's not a directory.
447 if (!stat(rnext->str, &st) && S_ISREG(st.st_mode)) {
448 *prlist = rnext;
449 rnext->next = NULL;
450 prlist = &(rnext->next);
451 } else free(rnext);
Rob Landleyfa98d012006-11-02 02:57:27 -0500452
Rob Landley7aa651a2012-11-13 17:14:08 -0600453 if (!next) break;
454 path += len;
455 path++;
456 }
457 free(cwd);
landley00f87f12006-10-25 18:38:37 -0400458
Rob Landley7aa651a2012-11-13 17:14:08 -0600459 return rlist;
landley00f87f12006-10-25 18:38:37 -0400460}
landley09ea7ac2006-10-30 01:38:00 -0500461
462// Convert unsigned int to ascii, writing into supplied buffer. A truncated
463// result contains the first few digits of the result ala strncpy, and is
464// always null terminated (unless buflen is 0).
465void utoa_to_buf(unsigned n, char *buf, unsigned buflen)
466{
Rob Landley7aa651a2012-11-13 17:14:08 -0600467 int i, out = 0;
landley09ea7ac2006-10-30 01:38:00 -0500468
Rob Landley7aa651a2012-11-13 17:14:08 -0600469 if (buflen) {
470 for (i=1000000000; i; i/=10) {
471 int res = n/i;
landley09ea7ac2006-10-30 01:38:00 -0500472
Rob Landley7aa651a2012-11-13 17:14:08 -0600473 if ((res || out || i == 1) && --buflen>0) {
474 out++;
475 n -= res*i;
476 *buf++ = '0' + res;
477 }
478 }
479 *buf = 0;
480 }
landley09ea7ac2006-10-30 01:38:00 -0500481}
482
483// Convert signed integer to ascii, using utoa_to_buf()
484void itoa_to_buf(int n, char *buf, unsigned buflen)
485{
Rob Landley7aa651a2012-11-13 17:14:08 -0600486 if (buflen && n<0) {
487 n = -n;
488 *buf++ = '-';
489 buflen--;
490 }
491 utoa_to_buf((unsigned)n, buf, buflen);
landley09ea7ac2006-10-30 01:38:00 -0500492}
493
494// This static buffer is used by both utoa() and itoa(), calling either one a
495// second time will overwrite the previous results.
496//
497// The longest 32 bit integer is -2 billion plus a null terminator: 12 bytes.
498// Note that int is always 32 bits on any remotely unix-like system, see
499// http://www.unix.org/whitepapers/64bit.html for details.
500
501static char itoa_buf[12];
502
503// Convert unsigned integer to ascii, returning a static buffer.
504char *utoa(unsigned n)
505{
Rob Landley7aa651a2012-11-13 17:14:08 -0600506 utoa_to_buf(n, itoa_buf, sizeof(itoa_buf));
landley09ea7ac2006-10-30 01:38:00 -0500507
Rob Landley7aa651a2012-11-13 17:14:08 -0600508 return itoa_buf;
landley09ea7ac2006-10-30 01:38:00 -0500509}
510
511char *itoa(int n)
512{
Rob Landley7aa651a2012-11-13 17:14:08 -0600513 itoa_to_buf(n, itoa_buf, sizeof(itoa_buf));
landley09ea7ac2006-10-30 01:38:00 -0500514
Rob Landley7aa651a2012-11-13 17:14:08 -0600515 return itoa_buf;
landley09ea7ac2006-10-30 01:38:00 -0500516}
Rob Landley055cfcb2007-01-14 20:20:06 -0500517
Rob Landleyf5757162007-02-16 21:08:22 -0500518// atol() with the kilo/mega/giga/tera/peta/exa extensions.
519// (zetta and yotta don't fit in 64 bits.)
Rob Landley5e6dca62012-02-09 06:09:27 -0600520long atolx(char *numstr)
Rob Landleyf5757162007-02-16 21:08:22 -0500521{
Rob Landley7aa651a2012-11-13 17:14:08 -0600522 char *c, *suffixes="bkmgtpe", *end;
523 long val = strtol(numstr, &c, 0);
Rob Landleyf5757162007-02-16 21:08:22 -0500524
Rob Landley7aa651a2012-11-13 17:14:08 -0600525 if (*c) {
526 if (c != numstr && (end = strchr(suffixes, tolower(*c)))) {
527 int shift = end-suffixes;
528 if (shift--) val *= 1024L<<(shift*10);
529 } else {
530 while (isspace(*c)) c++;
531 if (*c) error_exit("not integer: %s", numstr);
532 }
533 }
Rob Landleyad63f4b2011-12-12 15:19:52 -0600534
Rob Landley7aa651a2012-11-13 17:14:08 -0600535 return val;
Rob Landleyf5757162007-02-16 21:08:22 -0500536}
537
Rob Landleyeb7ea222012-04-14 22:30:41 -0500538int numlen(long l)
539{
Rob Landley7aa651a2012-11-13 17:14:08 -0600540 int len = 0;
541 while (l) {
542 l /= 10;
543 len++;
544 }
545 return len;
Rob Landleyeb7ea222012-04-14 22:30:41 -0500546}
547
Rob Landley2037b832012-07-15 16:56:20 -0500548int stridx(char *haystack, char needle)
549{
Rob Landley7aa651a2012-11-13 17:14:08 -0600550 char *off;
Rob Landley2037b832012-07-15 16:56:20 -0500551
Rob Landley7aa651a2012-11-13 17:14:08 -0600552 if (!needle) return -1;
553 off = strchr(haystack, needle);
554 if (!off) return -1;
Rob Landley2037b832012-07-15 16:56:20 -0500555
Rob Landley7aa651a2012-11-13 17:14:08 -0600556 return off-haystack;
Rob Landley2037b832012-07-15 16:56:20 -0500557}
558
Rob Landley055cfcb2007-01-14 20:20:06 -0500559// Return how long the file at fd is, if there's any way to determine it.
560off_t fdlength(int fd)
561{
Rob Landley7aa651a2012-11-13 17:14:08 -0600562 off_t bottom = 0, top = 0, pos, old;
563 int size;
Rob Landley055cfcb2007-01-14 20:20:06 -0500564
Rob Landley7aa651a2012-11-13 17:14:08 -0600565 // If the ioctl works for this, return it.
Rob Landley055cfcb2007-01-14 20:20:06 -0500566
Rob Landley7aa651a2012-11-13 17:14:08 -0600567 if (ioctl(fd, BLKGETSIZE, &size) >= 0) return size*512L;
Rob Landley055cfcb2007-01-14 20:20:06 -0500568
Rob Landley7aa651a2012-11-13 17:14:08 -0600569 // If not, do a binary search for the last location we can read. (Some
570 // block devices don't do BLKGETSIZE right.) This should probably have
571 // a CONFIG option...
Rob Landley055cfcb2007-01-14 20:20:06 -0500572
Rob Landley7aa651a2012-11-13 17:14:08 -0600573 old = lseek(fd, 0, SEEK_CUR);
574 do {
575 char temp;
Rob Landley055cfcb2007-01-14 20:20:06 -0500576
Rob Landley7aa651a2012-11-13 17:14:08 -0600577 pos = bottom + (top - bottom) / 2;
Rob Landley055cfcb2007-01-14 20:20:06 -0500578
Rob Landley7aa651a2012-11-13 17:14:08 -0600579 // If we can read from the current location, it's bigger.
Rob Landley055cfcb2007-01-14 20:20:06 -0500580
Rob Landley7aa651a2012-11-13 17:14:08 -0600581 if (lseek(fd, pos, 0)>=0 && read(fd, &temp, 1)==1) {
582 if (bottom == top) bottom = top = (top+1) * 2;
583 else bottom = pos;
Rob Landley055cfcb2007-01-14 20:20:06 -0500584
Rob Landley7aa651a2012-11-13 17:14:08 -0600585 // If we can't, it's smaller.
Rob Landley055cfcb2007-01-14 20:20:06 -0500586
Rob Landley7aa651a2012-11-13 17:14:08 -0600587 } else {
588 if (bottom == top) {
589 if (!top) return 0;
590 bottom = top/2;
591 } else top = pos;
592 }
593 } while (bottom + 1 != top);
Rob Landley055cfcb2007-01-14 20:20:06 -0500594
Rob Landley7aa651a2012-11-13 17:14:08 -0600595 lseek(fd, old, SEEK_SET);
Rob Landleyf15387d2008-07-18 05:43:44 -0500596
Rob Landley7aa651a2012-11-13 17:14:08 -0600597 return pos + 1;
Rob Landley055cfcb2007-01-14 20:20:06 -0500598}
599
Rob Landley0c93f6c2007-04-29 19:55:21 -0400600// This can return null (meaning file not found). It just won't return null
601// for memory allocation reasons.
602char *xreadlink(char *name)
603{
Rob Landley7aa651a2012-11-13 17:14:08 -0600604 int len, size = 0;
605 char *buf = 0;
Rob Landley0c93f6c2007-04-29 19:55:21 -0400606
Rob Landley7aa651a2012-11-13 17:14:08 -0600607 // Grow by 64 byte chunks until it's big enough.
608 for(;;) {
609 size +=64;
610 buf = xrealloc(buf, size);
611 len = readlink(name, buf, size);
Rob Landley0c93f6c2007-04-29 19:55:21 -0400612
Rob Landley7aa651a2012-11-13 17:14:08 -0600613 if (len<0) {
614 free(buf);
615 return 0;
616 }
617 if (len<size) {
618 buf[len]=0;
619 return buf;
620 }
621 }
Rob Landley0c93f6c2007-04-29 19:55:21 -0400622}
623
Rob Landleyb3a33822007-01-25 16:10:37 -0500624/*
625 This might be of use or might not. Unknown yet...
626
Rob Landley055cfcb2007-01-14 20:20:06 -0500627// Read contents of file as a single freshly allocated nul-terminated string.
628char *readfile(char *name)
629{
Rob Landley7aa651a2012-11-13 17:14:08 -0600630 off_t len;
631 int fd;
632 char *buf;
Rob Landley055cfcb2007-01-14 20:20:06 -0500633
Rob Landley7aa651a2012-11-13 17:14:08 -0600634 fd = open(name, O_RDONLY);
635 if (fd == -1) return 0;
636 len = fdlength(fd);
637 buf = xmalloc(len+1);
638 buf[readall(fd, buf, len)] = 0;
Rob Landley055cfcb2007-01-14 20:20:06 -0500639
Rob Landley7aa651a2012-11-13 17:14:08 -0600640 return buf;
Rob Landley055cfcb2007-01-14 20:20:06 -0500641}
642
643char *xreadfile(char *name)
644{
Rob Landley7aa651a2012-11-13 17:14:08 -0600645 char *buf = readfile(name);
646 if (!buf) perror_exit("xreadfile %s", name);
647 return buf;
Rob Landley055cfcb2007-01-14 20:20:06 -0500648}
649
650*/
651
652// Open a /var/run/NAME.pid file, dying if we can't write it or if it currently
653// exists and is this executable.
654void xpidfile(char *name)
655{
Rob Landley7aa651a2012-11-13 17:14:08 -0600656 char pidfile[256], spid[32];
657 int i, fd;
658 pid_t pid;
Rob Landley055cfcb2007-01-14 20:20:06 -0500659
Rob Landley7aa651a2012-11-13 17:14:08 -0600660 sprintf(pidfile, "/var/run/%s.pid", name);
661 // Try three times to open the sucker.
662 for (i=0; i<3; i++) {
663 fd = open(pidfile, O_CREAT|O_EXCL, 0644);
664 if (fd != -1) break;
Rob Landley055cfcb2007-01-14 20:20:06 -0500665
Rob Landley7aa651a2012-11-13 17:14:08 -0600666 // If it already existed, read it. Loop for race condition.
667 fd = open(pidfile, O_RDONLY);
668 if (fd == -1) continue;
Rob Landley055cfcb2007-01-14 20:20:06 -0500669
Rob Landley7aa651a2012-11-13 17:14:08 -0600670 // Is the old program still there?
671 spid[xread(fd, spid, sizeof(spid)-1)] = 0;
672 close(fd);
673 pid = atoi(spid);
674 if (pid < 1 || kill(pid, 0) == ESRCH) unlink(pidfile);
Rob Landley2c226852007-11-15 18:30:30 -0600675
Rob Landley7aa651a2012-11-13 17:14:08 -0600676 // An else with more sanity checking might be nice here.
677 }
Rob Landley055cfcb2007-01-14 20:20:06 -0500678
Rob Landley7aa651a2012-11-13 17:14:08 -0600679 if (i == 3) error_exit("xpidfile %s", name);
680
681 xwrite(fd, spid, sprintf(spid, "%ld\n", (long)getpid()));
682 close(fd);
Rob Landley055cfcb2007-01-14 20:20:06 -0500683}
Rob Landley7634b552007-11-29 17:49:50 -0600684
Rob Landley2bfaaf22008-07-03 19:19:00 -0500685// Iterate through an array of files, opening each one and calling a function
686// on that filehandle and name. The special filename "-" means stdin if
687// flags is O_RDONLY, stdout otherwise. An empty argument list calls
688// function() on just stdin/stdout.
689//
690// Note: read only filehandles are automatically closed when function()
691// returns, but writeable filehandles must be close by function()
Rob Landleyad63f4b2011-12-12 15:19:52 -0600692void loopfiles_rw(char **argv, int flags, int permissions, int failok,
Rob Landley7aa651a2012-11-13 17:14:08 -0600693 void (*function)(int fd, char *name))
Rob Landley7634b552007-11-29 17:49:50 -0600694{
Rob Landley7aa651a2012-11-13 17:14:08 -0600695 int fd;
Rob Landley7634b552007-11-29 17:49:50 -0600696
Rob Landley7aa651a2012-11-13 17:14:08 -0600697 // If no arguments, read from stdin.
698 if (!*argv) function(flags ? 1 : 0, "-");
699 else do {
700 // Filename "-" means read from stdin.
701 // Inability to open a file prints a warning, but doesn't exit.
Rob Landley7634b552007-11-29 17:49:50 -0600702
Rob Landley7aa651a2012-11-13 17:14:08 -0600703 if (!strcmp(*argv,"-")) fd=0;
704 else if (0>(fd = open(*argv, flags, permissions)) && !failok) {
705 perror_msg("%s", *argv);
706 toys.exitval = 1;
707 continue;
708 }
709 function(fd, *argv);
710 if (flags == O_RDONLY) close(fd);
711 } while (*++argv);
Rob Landley7634b552007-11-29 17:49:50 -0600712}
Rob Landleybc078652007-12-15 21:47:25 -0600713
Rob Landleyad63f4b2011-12-12 15:19:52 -0600714// Call loopfiles_rw with O_RDONLY and !failok (common case).
Rob Landley2bfaaf22008-07-03 19:19:00 -0500715void loopfiles(char **argv, void (*function)(int fd, char *name))
716{
Rob Landley7aa651a2012-11-13 17:14:08 -0600717 loopfiles_rw(argv, O_RDONLY, 0, 0, function);
Rob Landley2bfaaf22008-07-03 19:19:00 -0500718}
719
Rob Landleybc078652007-12-15 21:47:25 -0600720// Slow, but small.
721
Rob Landley3fc4e0f2008-04-13 00:29:00 -0500722char *get_rawline(int fd, long *plen, char end)
Rob Landleybc078652007-12-15 21:47:25 -0600723{
Rob Landley7aa651a2012-11-13 17:14:08 -0600724 char c, *buf = NULL;
725 long len = 0;
Rob Landleybc078652007-12-15 21:47:25 -0600726
Rob Landley7aa651a2012-11-13 17:14:08 -0600727 for (;;) {
728 if (1>read(fd, &c, 1)) break;
729 if (!(len & 63)) buf=xrealloc(buf, len+65);
730 if ((buf[len++]=c) == end) break;
731 }
732 if (buf) buf[len]=0;
733 if (plen) *plen = len;
Rob Landleybc078652007-12-15 21:47:25 -0600734
Rob Landley7aa651a2012-11-13 17:14:08 -0600735 return buf;
Rob Landleybc078652007-12-15 21:47:25 -0600736}
737
738char *get_line(int fd)
739{
Rob Landley7aa651a2012-11-13 17:14:08 -0600740 long len;
741 char *buf = get_rawline(fd, &len, '\n');
Rob Landleybc078652007-12-15 21:47:25 -0600742
Rob Landley7aa651a2012-11-13 17:14:08 -0600743 if (buf && buf[--len]=='\n') buf[len]=0;
Rob Landleybc078652007-12-15 21:47:25 -0600744
Rob Landley7aa651a2012-11-13 17:14:08 -0600745 return buf;
Rob Landleybc078652007-12-15 21:47:25 -0600746}
747
748// Copy the rest of in to out and close both files.
749
750void xsendfile(int in, int out)
751{
Rob Landley7aa651a2012-11-13 17:14:08 -0600752 long len;
753 char buf[4096];
Rob Landleybc078652007-12-15 21:47:25 -0600754
Rob Landley7aa651a2012-11-13 17:14:08 -0600755 if (in<0) return;
756 for (;;) {
757 len = xread(in, buf, 4096);
758 if (len<1) break;
759 xwrite(out, buf, len);
760 }
Rob Landley42ecbab2007-12-18 02:02:21 -0600761}
762
Rob Landley67a069d2012-06-03 00:32:12 -0500763int wfchmodat(int fd, char *name, mode_t mode)
764{
Rob Landley7aa651a2012-11-13 17:14:08 -0600765 int rc = fchmodat(fd, name, mode, 0);
Rob Landley67a069d2012-06-03 00:32:12 -0500766
Rob Landley7aa651a2012-11-13 17:14:08 -0600767 if (rc) {
768 perror_msg("chmod '%s' to %04o", name, mode);
769 toys.exitval=1;
770 }
771 return rc;
Rob Landley67a069d2012-06-03 00:32:12 -0500772}
773
Rob Landleyc52db602012-07-30 01:01:33 -0500774static char *tempfile2zap;
775static void tempfile_handler(int i)
776{
Rob Landley7aa651a2012-11-13 17:14:08 -0600777 if (1 < (long)tempfile2zap) unlink(tempfile2zap);
778 _exit(1);
Rob Landleyc52db602012-07-30 01:01:33 -0500779}
780
Rob Landley42ecbab2007-12-18 02:02:21 -0600781// Open a temporary file to copy an existing file into.
782int copy_tempfile(int fdin, char *name, char **tempname)
783{
Rob Landley7aa651a2012-11-13 17:14:08 -0600784 struct stat statbuf;
785 int fd;
Rob Landley42ecbab2007-12-18 02:02:21 -0600786
Rob Landley7aa651a2012-11-13 17:14:08 -0600787 *tempname = xstrndup(name, strlen(name)+6);
788 strcat(*tempname,"XXXXXX");
789 if(-1 == (fd = mkstemp(*tempname))) error_exit("no temp file");
790 if (!tempfile2zap) sigatexit(tempfile_handler);
791 tempfile2zap = *tempname;
Rob Landley42ecbab2007-12-18 02:02:21 -0600792
Rob Landley7aa651a2012-11-13 17:14:08 -0600793 // Set permissions of output file
Rob Landley42ecbab2007-12-18 02:02:21 -0600794
Rob Landley7aa651a2012-11-13 17:14:08 -0600795 fstat(fdin, &statbuf);
796 fchmod(fd, statbuf.st_mode);
Rob Landley42ecbab2007-12-18 02:02:21 -0600797
Rob Landley7aa651a2012-11-13 17:14:08 -0600798 return fd;
Rob Landley42ecbab2007-12-18 02:02:21 -0600799}
800
801// Abort the copy and delete the temporary file.
802void delete_tempfile(int fdin, int fdout, char **tempname)
803{
Rob Landley7aa651a2012-11-13 17:14:08 -0600804 close(fdin);
805 close(fdout);
806 unlink(*tempname);
807 tempfile2zap = (char *)1;
808 free(*tempname);
809 *tempname = NULL;
Rob Landley42ecbab2007-12-18 02:02:21 -0600810}
811
812// Copy the rest of the data and replace the original with the copy.
813void replace_tempfile(int fdin, int fdout, char **tempname)
814{
Rob Landley7aa651a2012-11-13 17:14:08 -0600815 char *temp = xstrdup(*tempname);
Rob Landley42ecbab2007-12-18 02:02:21 -0600816
Rob Landley7aa651a2012-11-13 17:14:08 -0600817 temp[strlen(temp)-6]=0;
818 if (fdin != -1) {
819 xsendfile(fdin, fdout);
820 xclose(fdin);
821 }
822 xclose(fdout);
823 rename(*tempname, temp);
824 tempfile2zap = (char *)1;
825 free(*tempname);
826 free(temp);
827 *tempname = NULL;
Rob Landleybc078652007-12-15 21:47:25 -0600828}
Rob Landley7e849c52009-01-03 18:15:18 -0600829
830// Create a 256 entry CRC32 lookup table.
831
Rob Landleyb15b8fa2009-01-05 01:05:43 -0600832void crc_init(unsigned int *crc_table, int little_endian)
Rob Landley7e849c52009-01-03 18:15:18 -0600833{
Rob Landley7aa651a2012-11-13 17:14:08 -0600834 unsigned int i;
Rob Landley7e849c52009-01-03 18:15:18 -0600835
Rob Landley7aa651a2012-11-13 17:14:08 -0600836 // Init the CRC32 table (big endian)
837 for (i=0; i<256; i++) {
838 unsigned int j, c = little_endian ? i : i<<24;
839 for (j=8; j; j--)
840 if (little_endian) c = (c&1) ? (c>>1)^0xEDB88320 : c>>1;
841 else c=c&0x80000000 ? (c<<1)^0x04c11db7 : (c<<1);
842 crc_table[i] = c;
843 }
Rob Landley7e849c52009-01-03 18:15:18 -0600844}
Rob Landley26e7b5e2012-02-02 07:27:35 -0600845
846// Quick and dirty query size of terminal, doesn't do ANSI probe fallback.
847// set *x=0 and *y=0 before calling to detect failure to set either, or
848// x=80 y=25 to provide defaults
849
850void terminal_size(unsigned *x, unsigned *y)
851{
Rob Landley7aa651a2012-11-13 17:14:08 -0600852 struct winsize ws;
853 int i;
Rob Landley26e7b5e2012-02-02 07:27:35 -0600854
Rob Landley7aa651a2012-11-13 17:14:08 -0600855 //memset(&ws, 0, sizeof(ws));
856 for (i=0; i<3; i++) {
857 if (ioctl(i, TIOCGWINSZ, &ws)) continue;
858 if (x) *x = ws.ws_col;
859 if (y) *y = ws.ws_row;
860 }
861 if (x) {
862 char *s = getenv("COLUMNS");
Rob Landley26e7b5e2012-02-02 07:27:35 -0600863
Rob Landley7aa651a2012-11-13 17:14:08 -0600864 i = s ? atoi(s) : 0;
865 if (i>0) *x = i;
866 }
867 if (y) {
868 char *s = getenv("ROWS");
Rob Landley26e7b5e2012-02-02 07:27:35 -0600869
Rob Landley7aa651a2012-11-13 17:14:08 -0600870 i = s ? atoi(s) : 0;
871 if (i>0) *y = i;
872 }
Rob Landley26e7b5e2012-02-02 07:27:35 -0600873}
874
875// This should use a raw tty, fixit later.
Rob Landleyf793d532012-02-27 21:56:49 -0600876int yesno(char *prompt, int def)
Rob Landley26e7b5e2012-02-02 07:27:35 -0600877{
Rob Landley7aa651a2012-11-13 17:14:08 -0600878 FILE *fps[] = {stdin, stdout, stderr};
879 int i;
880 char buf;
Rob Landley26e7b5e2012-02-02 07:27:35 -0600881
Rob Landley7aa651a2012-11-13 17:14:08 -0600882 for (i=0; i<3; i++) if (isatty(i)) break;
883 if (i == 3) return 1;
Rob Landley26e7b5e2012-02-02 07:27:35 -0600884
Rob Landley7aa651a2012-11-13 17:14:08 -0600885 fprintf(fps[i], "%s (%c/%c):", prompt, def ? 'Y' : 'y', def ? 'n' : 'N');
886 fflush(fps[i]);
887 while (fread(&buf, 1, 1, fps[i])) {
888 if (tolower(buf) == 'y') def = 1;
889 if (tolower(buf) == 'n') def = 0;
890 else if (!isspace(buf)) continue;
Rob Landleyee00a7f2012-03-19 19:19:21 -0500891
Rob Landley7aa651a2012-11-13 17:14:08 -0600892 break;
893 }
Rob Landleyee00a7f2012-03-19 19:19:21 -0500894
Rob Landley7aa651a2012-11-13 17:14:08 -0600895 return def;
Rob Landley26e7b5e2012-02-02 07:27:35 -0600896}
Rob Landleyff9ee8f2012-02-18 15:12:41 -0600897
898// Execute a callback for each PID that matches a process name from a list.
Rob Landleyf42e11b2012-02-18 18:09:14 -0600899void for_each_pid_with_name_in(char **names, void (*callback)(pid_t pid))
900{
Rob Landley7aa651a2012-11-13 17:14:08 -0600901 DIR *dp;
902 struct dirent *entry;
903 char cmd[sizeof(toybuf)], path[64];
904 char **curname;
Rob Landleyff9ee8f2012-02-18 15:12:41 -0600905
Rob Landley7aa651a2012-11-13 17:14:08 -0600906 if (!(dp = opendir("/proc"))) perror_exit("opendir");
Rob Landleyff9ee8f2012-02-18 15:12:41 -0600907
Rob Landley7aa651a2012-11-13 17:14:08 -0600908 while ((entry = readdir(dp))) {
909 int fd, n;
Rob Landleyff9ee8f2012-02-18 15:12:41 -0600910
Rob Landley7aa651a2012-11-13 17:14:08 -0600911 if (!isdigit(*entry->d_name)) continue;
Rob Landleyff9ee8f2012-02-18 15:12:41 -0600912
Rob Landley7aa651a2012-11-13 17:14:08 -0600913 if (sizeof(path) <= snprintf(path, sizeof(path), "/proc/%s/cmdline",
914 entry->d_name)) continue;
Rob Landleyff9ee8f2012-02-18 15:12:41 -0600915
Rob Landley7aa651a2012-11-13 17:14:08 -0600916 if (-1 == (fd=open(path, O_RDONLY))) continue;
917 n = read(fd, cmd, sizeof(cmd));
918 close(fd);
919 if (n<1) continue;
Rob Landleyff9ee8f2012-02-18 15:12:41 -0600920
Rob Landley7aa651a2012-11-13 17:14:08 -0600921 for (curname = names; *curname; curname++)
922 if (!strcmp(basename(cmd), *curname)) callback(atol(entry->d_name));
923 }
Rob Landleyff9ee8f2012-02-18 15:12:41 -0600924
Rob Landley7aa651a2012-11-13 17:14:08 -0600925 closedir(dp);
Rob Landleyff9ee8f2012-02-18 15:12:41 -0600926}
Rob Landley2dd50ad2012-02-26 13:48:00 -0600927
928struct signame {
Rob Landley7aa651a2012-11-13 17:14:08 -0600929 int num;
930 char *name;
Rob Landley2dd50ad2012-02-26 13:48:00 -0600931};
932
933// Signals required by POSIX 2008:
934// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html
935
936#define SIGNIFY(x) {SIG##x, #x}
937
938static struct signame signames[] = {
Rob Landley7aa651a2012-11-13 17:14:08 -0600939 SIGNIFY(ABRT), SIGNIFY(ALRM), SIGNIFY(BUS),
940 SIGNIFY(FPE), SIGNIFY(HUP), SIGNIFY(ILL), SIGNIFY(INT), SIGNIFY(KILL),
941 SIGNIFY(PIPE), SIGNIFY(QUIT), SIGNIFY(SEGV), SIGNIFY(TERM),
942 SIGNIFY(USR1), SIGNIFY(USR2), SIGNIFY(SYS), SIGNIFY(TRAP),
943 SIGNIFY(VTALRM), SIGNIFY(XCPU), SIGNIFY(XFSZ),
Rob Landleyc52db602012-07-30 01:01:33 -0500944
Rob Landley7aa651a2012-11-13 17:14:08 -0600945 // Start of non-terminal signals
Rob Landleyc52db602012-07-30 01:01:33 -0500946
Rob Landley7aa651a2012-11-13 17:14:08 -0600947 SIGNIFY(CHLD), SIGNIFY(CONT), SIGNIFY(STOP), SIGNIFY(TSTP),
948 SIGNIFY(TTIN), SIGNIFY(TTOU), SIGNIFY(URG)
Rob Landley2dd50ad2012-02-26 13:48:00 -0600949};
950
951// not in posix: SIGNIFY(STKFLT), SIGNIFY(WINCH), SIGNIFY(IO), SIGNIFY(PWR)
952// obsolete: SIGNIFY(PROF) SIGNIFY(POLL)
953
Rob Landleyc52db602012-07-30 01:01:33 -0500954// Install the same handler on every signal that defaults to killing the process
955void sigatexit(void *handler)
956{
Rob Landley7aa651a2012-11-13 17:14:08 -0600957 int i;
958 for (i=0; signames[i].num != SIGCHLD; i++) signal(signames[i].num, handler);
Rob Landleyc52db602012-07-30 01:01:33 -0500959}
Rob Landley2dd50ad2012-02-26 13:48:00 -0600960// Convert name to signal number. If name == NULL print names.
961int sig_to_num(char *pidstr)
962{
Rob Landley7aa651a2012-11-13 17:14:08 -0600963 int i;
Rob Landley2dd50ad2012-02-26 13:48:00 -0600964
Rob Landley7aa651a2012-11-13 17:14:08 -0600965 if (pidstr) {
966 char *s;
967 i = strtol(pidstr, &s, 10);
968 if (!*s) return i;
Rob Landley2dd50ad2012-02-26 13:48:00 -0600969
Rob Landley7aa651a2012-11-13 17:14:08 -0600970 if (!strncasecmp(pidstr, "sig", 3)) pidstr+=3;
971 }
972 for (i = 0; i < sizeof(signames)/sizeof(struct signame); i++)
973 if (!pidstr) xputs(signames[i].name);
974 else if (!strcasecmp(pidstr, signames[i].name)) return signames[i].num;
Rob Landley2dd50ad2012-02-26 13:48:00 -0600975
Rob Landley7aa651a2012-11-13 17:14:08 -0600976 return -1;
Rob Landley2dd50ad2012-02-26 13:48:00 -0600977}
978
979char *num_to_sig(int sig)
980{
Rob Landley7aa651a2012-11-13 17:14:08 -0600981 int i;
Rob Landley2dd50ad2012-02-26 13:48:00 -0600982
Rob Landley7aa651a2012-11-13 17:14:08 -0600983 for (i=0; i<sizeof(signames)/sizeof(struct signame); i++)
984 if (signames[i].num == sig) return signames[i].name;
985 return NULL;
Rob Landley2dd50ad2012-02-26 13:48:00 -0600986}
Daniel Walter05744b32012-03-19 19:57:56 -0500987
Rob Landleyc52db602012-07-30 01:01:33 -0500988// premute mode bits based on posix mode strings.
Rob Landleyb6f601e2012-05-16 21:11:43 -0500989mode_t string_to_mode(char *modestr, mode_t mode)
Daniel Walter05744b32012-03-19 19:57:56 -0500990{
Rob Landley7aa651a2012-11-13 17:14:08 -0600991 char *whos = "ogua", *hows = "=+-", *whats = "xwrstX", *whys = "ogu";
992 char *s, *str = modestr;
Rob Landleycf6bcb22012-03-19 20:56:18 -0500993
Rob Landley7aa651a2012-11-13 17:14:08 -0600994 // Handle octal mode
995 if (isdigit(*str)) {
996 mode = strtol(str, &s, 8);
997 if (*s || (mode & ~(07777))) goto barf;
Rob Landleyb6f601e2012-05-16 21:11:43 -0500998
Rob Landley7aa651a2012-11-13 17:14:08 -0600999 return mode;
1000 }
Rob Landleycf6bcb22012-03-19 20:56:18 -05001001
Rob Landley7aa651a2012-11-13 17:14:08 -06001002 // Gaze into the bin of permission...
1003 for (;;) {
1004 int i, j, dowho, dohow, dowhat, amask;
Rob Landleycf6bcb22012-03-19 20:56:18 -05001005
Rob Landley7aa651a2012-11-13 17:14:08 -06001006 dowho = dohow = dowhat = amask = 0;
Daniel Walter05744b32012-03-19 19:57:56 -05001007
Rob Landley7aa651a2012-11-13 17:14:08 -06001008 // Find the who, how, and what stanzas, in that order
1009 while (*str && (s = strchr(whos, *str))) {
1010 dowho |= 1<<(s-whos);
1011 str++;
1012 }
1013 // If who isn't specified, like "a" but honoring umask.
1014 if (!dowho) {
1015 dowho = 8;
1016 umask(amask=umask(0));
1017 }
1018 if (!*str || !(s = strchr(hows, *str))) goto barf;
1019 dohow = *(str++);
Rob Landley67a069d2012-06-03 00:32:12 -05001020
Rob Landley7aa651a2012-11-13 17:14:08 -06001021 if (!dohow) goto barf;
1022 while (*str && (s = strchr(whats, *str))) {
1023 dowhat |= 1<<(s-whats);
1024 str++;
1025 }
Rob Landleyb6f601e2012-05-16 21:11:43 -05001026
Rob Landley7aa651a2012-11-13 17:14:08 -06001027 // Convert X to x for directory or if already executable somewhere
1028 if ((dowhat&32) && (S_ISDIR(mode) || (mode&0111))) dowhat |= 1;
Rob Landleyb6f601e2012-05-16 21:11:43 -05001029
Rob Landley7aa651a2012-11-13 17:14:08 -06001030 // Copy mode from another category?
1031 if (!dowhat && *str && (s = strchr(whys, *str))) {
1032 dowhat = (mode>>(3*(s-whys)))&7;
1033 str++;
1034 }
Rob Landleyb6f601e2012-05-16 21:11:43 -05001035
Rob Landley7aa651a2012-11-13 17:14:08 -06001036 // Are we ready to do a thing yet?
1037 if (*str && *(str++) != ',') goto barf;
Rob Landleyb6f601e2012-05-16 21:11:43 -05001038
Rob Landley7aa651a2012-11-13 17:14:08 -06001039 // Ok, apply the bits to the mode.
1040 for (i=0; i<4; i++) {
1041 for (j=0; j<3; j++) {
1042 mode_t bit = 0;
1043 int where = 1<<((3*i)+j);
Rob Landley31f49e72012-07-21 22:45:05 -05001044
Rob Landley7aa651a2012-11-13 17:14:08 -06001045 if (amask & where) continue;
Rob Landleyb6f601e2012-05-16 21:11:43 -05001046
Rob Landley7aa651a2012-11-13 17:14:08 -06001047 // Figure out new value at this location
1048 if (i == 3) {
1049 // suid/sticky bit.
1050 if (j) {
1051 if ((dowhat & 8) && (dowho&(8|(1<<i)))) bit++;
1052 } else if (dowhat & 16) bit++;
1053 } else {
1054 if (!(dowho&(8|(1<<i)))) continue;
1055 if (dowhat&(1<<j)) bit++;
1056 }
Rob Landleyb6f601e2012-05-16 21:11:43 -05001057
Rob Landley7aa651a2012-11-13 17:14:08 -06001058 // When selection active, modify bit
Rob Landleyb6f601e2012-05-16 21:11:43 -05001059
Rob Landley7aa651a2012-11-13 17:14:08 -06001060 if (dohow == '=' || (bit && dohow == '-')) mode &= ~where;
1061 if (bit && dohow != '-') mode |= where;
1062 }
1063 }
Rob Landleyb6f601e2012-05-16 21:11:43 -05001064
Rob Landley7aa651a2012-11-13 17:14:08 -06001065 if (!*str) break;
1066 }
1067 return mode;
Rob Landleyb6f601e2012-05-16 21:11:43 -05001068barf:
Rob Landley7aa651a2012-11-13 17:14:08 -06001069 error_exit("bad mode '%s'", modestr);
Daniel Walter05744b32012-03-19 19:57:56 -05001070}
Ashwini Kumar1a0eedf2012-08-26 21:17:00 -05001071
1072
1073char* make_human_readable(unsigned long long size, unsigned long unit)
1074{
Rob Landley7aa651a2012-11-13 17:14:08 -06001075 unsigned int frac = 0;
1076 if(unit) {
1077 size = (size/(unit)) + (size%(unit)?1:0);
1078 return xmsprintf("%llu", size);
1079 }
1080 else {
1081 static char units[] = {'\0', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'};
1082 int index = 0;
1083 while(size >= 1024) {
1084 frac = size%1024;
1085 size /= 1024;
1086 index++;
Ashwini Kumar1a0eedf2012-08-26 21:17:00 -05001087 }
Rob Landley7aa651a2012-11-13 17:14:08 -06001088 frac = (frac/102) + ((frac%102)?1:0);
1089 if(frac >= 10) {
1090 size += 1;
1091 frac = 0;
Ashwini Kumar1a0eedf2012-08-26 21:17:00 -05001092 }
Rob Landley7aa651a2012-11-13 17:14:08 -06001093 if(frac) return xmsprintf("%llu.%u%c", size, frac, units[index]);
1094 else return xmsprintf("%llu%c", size, units[index]);
1095 }
1096 return NULL; //not reached
Ashwini Kumar1a0eedf2012-08-26 21:17:00 -05001097}