Mercurial > hg > toybox
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 } |