|
1 // stat.c - stat builtin interface to system call |
|
2 // |
|
3 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved. |
|
4 // |
|
5 /* |
|
6 * This file is part of zsh, the Z shell. |
|
7 * |
|
8 * Copyright (c) 1996-1997 Peter Stephenson |
|
9 * All rights reserved. |
|
10 * |
|
11 * Permission is hereby granted, without written agreement and without |
|
12 * license or royalty fees, to use, copy, modify, and distribute this |
|
13 * software and to distribute modified versions of this software for any |
|
14 * purpose, provided that the above copyright notice and the following |
|
15 * two paragraphs appear in all copies of this software. |
|
16 * |
|
17 * In no event shall Peter Stephenson or the Zsh Development Group be liable |
|
18 * to any party for direct, indirect, special, incidental, or consequential |
|
19 * damages arising out of the use of this software and its documentation, |
|
20 * even if Peter Stephenson and the Zsh Development Group have been advised of |
|
21 * the possibility of such damage. |
|
22 * |
|
23 * Peter Stephenson and the Zsh Development Group specifically disclaim any |
|
24 * warranties, including, but not limited to, the implied warranties of |
|
25 * merchantability and fitness for a particular purpose. The software |
|
26 * provided hereunder is on an "as is" basis, and Peter Stephenson and the |
|
27 * Zsh Development Group have no obligation to provide maintenance, |
|
28 * support, updates, enhancements, or modifications. |
|
29 * |
|
30 */ |
|
31 #include "stat.mdh" |
|
32 #include "stat.pro" |
|
33 |
|
34 #ifdef __SYMBIAN32__ |
|
35 #ifdef __WINSCW__ |
|
36 #pragma warn_unusedarg off |
|
37 #endif//__WINSCW__ |
|
38 #endif//__SYMBIAN32__ |
|
39 |
|
40 enum statnum { ST_DEV, ST_INO, ST_MODE, ST_NLINK, ST_UID, ST_GID, |
|
41 ST_RDEV, ST_SIZE, ST_ATIM, ST_MTIM, ST_CTIM, |
|
42 ST_BLKSIZE, ST_BLOCKS, ST_READLINK, ST_COUNT }; |
|
43 enum statflags { STF_NAME = 1, STF_FILE = 2, STF_STRING = 4, STF_RAW = 8, |
|
44 STF_PICK = 16, STF_ARRAY = 32, STF_GMT = 64, |
|
45 STF_HASH = 128, STF_OCTAL = 256 }; |
|
46 static char *statelts[] = { "device", "inode", "mode", "nlink", |
|
47 "uid", "gid", "rdev", "size", "atime", |
|
48 "mtime", "ctime", "blksize", "blocks", |
|
49 "link", NULL }; |
|
50 #define HNAMEKEY "name" |
|
51 |
|
52 /**/ |
|
53 static void |
|
54 statmodeprint(mode_t mode, char *outbuf, int flags) |
|
55 { |
|
56 if (flags & STF_RAW) { |
|
57 sprintf(outbuf, (flags & STF_OCTAL) ? "0%lo" : "%lu", |
|
58 (unsigned long)mode); |
|
59 if (flags & STF_STRING) |
|
60 strcat(outbuf, " ("); |
|
61 } |
|
62 if (flags & STF_STRING) { |
|
63 static const char *modes = "?rwxrwxrwx"; |
|
64 #ifdef __CYGWIN__ |
|
65 static mode_t mflags[9] = { 0 }; |
|
66 #else |
|
67 static const mode_t mflags[9] = { |
|
68 S_IRUSR, S_IWUSR, S_IXUSR, |
|
69 S_IRGRP, S_IWGRP, S_IXGRP, |
|
70 S_IROTH, S_IWOTH, S_IXOTH |
|
71 }; |
|
72 #endif |
|
73 const mode_t *mfp = mflags; |
|
74 char pm[11]; |
|
75 int i; |
|
76 |
|
77 #ifdef __CYGWIN__ |
|
78 if (mflags[0] == 0) { |
|
79 mflags[0] = S_IRUSR; |
|
80 mflags[1] = S_IWUSR; |
|
81 mflags[2] = S_IXUSR; |
|
82 mflags[3] = S_IRGRP; |
|
83 mflags[4] = S_IWGRP; |
|
84 mflags[5] = S_IXGRP; |
|
85 mflags[6] = S_IROTH; |
|
86 mflags[7] = S_IWOTH; |
|
87 mflags[8] = S_IXOTH; |
|
88 } |
|
89 #endif |
|
90 |
|
91 if (S_ISBLK(mode)) |
|
92 *pm = 'b'; |
|
93 else if (S_ISCHR(mode)) |
|
94 *pm = 'c'; |
|
95 else if (S_ISDIR(mode)) |
|
96 *pm = 'd'; |
|
97 else if (S_ISDOOR(mode)) |
|
98 *pm = 'D'; |
|
99 else if (S_ISFIFO(mode)) |
|
100 *pm = 'p'; |
|
101 else if (S_ISLNK(mode)) |
|
102 *pm = 'l'; |
|
103 else if (S_ISMPC(mode)) |
|
104 *pm = 'm'; |
|
105 else if (S_ISNWK(mode)) |
|
106 *pm = 'n'; |
|
107 else if (S_ISOFD(mode)) |
|
108 *pm = 'M'; |
|
109 else if (S_ISOFL(mode)) |
|
110 *pm = 'M'; |
|
111 else if (S_ISREG(mode)) |
|
112 *pm = '-'; |
|
113 else if (S_ISSOCK(mode)) |
|
114 *pm = 's'; |
|
115 else |
|
116 *pm = '?'; |
|
117 |
|
118 for (i = 1; i <= 9; i++) |
|
119 pm[i] = (mode & *mfp++) ? modes[i] : '-'; |
|
120 pm[10] = '\0'; |
|
121 |
|
122 if (mode & S_ISUID) |
|
123 pm[3] = (mode & S_IXUSR) ? 's' : 'S'; |
|
124 if (mode & S_ISGID) |
|
125 pm[6] = (mode & S_IXGRP) ? 's' : 'S'; |
|
126 if (mode & S_ISVTX) |
|
127 pm[9] = (mode & S_IXOTH) ? 't' : 'T'; |
|
128 |
|
129 pm[10] = 0; |
|
130 strcat(outbuf, pm); |
|
131 if (flags & STF_RAW) |
|
132 strcat(outbuf, ")"); |
|
133 } |
|
134 } |
|
135 |
|
136 |
|
137 /**/ |
|
138 static void |
|
139 statuidprint(uid_t uid, char *outbuf, int flags) |
|
140 { |
|
141 if (flags & STF_RAW) { |
|
142 sprintf(outbuf, "%lu", (unsigned long)uid); |
|
143 if (flags & STF_STRING) |
|
144 strcat(outbuf, " ("); |
|
145 } |
|
146 if (flags & STF_STRING) { |
|
147 #ifdef HAVE_GETPWUID |
|
148 struct passwd *pwd; |
|
149 pwd = getpwuid(uid); |
|
150 strcat(outbuf, pwd ? pwd->pw_name : "???"); |
|
151 #else /* !HAVE_GETPWUID */ |
|
152 strcat(outbuf, "???"); |
|
153 #endif /* !HAVE_GETPWUID */ |
|
154 if (flags & STF_RAW) |
|
155 strcat(outbuf, ")"); |
|
156 } |
|
157 } |
|
158 |
|
159 |
|
160 /**/ |
|
161 static void |
|
162 statgidprint(gid_t gid, char *outbuf, int flags) |
|
163 { |
|
164 if (flags & STF_RAW) { |
|
165 sprintf(outbuf, "%lu", (unsigned long)gid); |
|
166 if (flags & STF_STRING) |
|
167 strcat(outbuf, " ("); |
|
168 } |
|
169 if (flags & STF_STRING) { |
|
170 #ifdef HAVE_GETGRGID |
|
171 struct group *gr; |
|
172 gr = getgrgid(gid); |
|
173 strcat(outbuf, gr ? gr->gr_name : "???"); |
|
174 #else /* !HAVE_GETGRGID */ |
|
175 strcat(outbuf, "???"); |
|
176 #endif /* !HAVE_GETGRGID */ |
|
177 if (flags & STF_RAW) |
|
178 strcat(outbuf, ")"); |
|
179 } |
|
180 } |
|
181 |
|
182 static char *timefmt; |
|
183 |
|
184 /**/ |
|
185 static void |
|
186 stattimeprint(time_t tim, char *outbuf, int flags) |
|
187 { |
|
188 if (flags & STF_RAW) { |
|
189 sprintf(outbuf, "%ld", (unsigned long)tim); |
|
190 if (flags & STF_STRING) |
|
191 strcat(outbuf, " ("); |
|
192 } |
|
193 if (flags & STF_STRING) { |
|
194 char *oend = outbuf + strlen(outbuf); |
|
195 ztrftime(oend, 40, timefmt, (flags & STF_GMT) ? gmtime(&tim) : |
|
196 localtime(&tim)); |
|
197 if (flags & STF_RAW) |
|
198 strcat(outbuf, ")"); |
|
199 } |
|
200 } |
|
201 |
|
202 |
|
203 /**/ |
|
204 static void |
|
205 statulprint(unsigned long num, char *outbuf) |
|
206 { |
|
207 sprintf(outbuf, "%lu", num); |
|
208 } |
|
209 |
|
210 |
|
211 /**/ |
|
212 static void |
|
213 statlinkprint(struct stat *sbuf, char *outbuf, char *fname) |
|
214 { |
|
215 int num; |
|
216 |
|
217 /* fname is NULL if we are looking at an fd */ |
|
218 if (fname && S_ISLNK(sbuf->st_mode) && |
|
219 (num = readlink(fname, outbuf, PATH_MAX)) > 0) { |
|
220 /* readlink doesn't terminate the buffer itself */ |
|
221 outbuf[num] = '\0'; |
|
222 } |
|
223 } |
|
224 |
|
225 |
|
226 /**/ |
|
227 static void |
|
228 statprint(struct stat *sbuf, char *outbuf, char *fname, int iwhich, int flags) |
|
229 { |
|
230 char *optr = outbuf; |
|
231 |
|
232 if (flags & STF_NAME) { |
|
233 sprintf(outbuf, (flags & (STF_PICK|STF_ARRAY)) ? |
|
234 "%s " : "%-8s", statelts[iwhich]); |
|
235 optr += strlen(outbuf); |
|
236 } |
|
237 *optr = '\0'; |
|
238 |
|
239 /* cast values to unsigned long as safest bet */ |
|
240 switch (iwhich) { |
|
241 case ST_DEV: |
|
242 statulprint((unsigned long)sbuf->st_dev, optr); |
|
243 break; |
|
244 |
|
245 case ST_INO: |
|
246 #ifdef INO_T_IS_64_BIT |
|
247 convbase(optr, sbuf->st_ino, 0); |
|
248 #else |
|
249 DPUTS(sizeof(sbuf->st_ino) > 4, |
|
250 "Shell compiled with wrong ino_t size"); |
|
251 statulprint((unsigned long)sbuf->st_ino, optr); |
|
252 #endif |
|
253 break; |
|
254 |
|
255 case ST_MODE: |
|
256 statmodeprint(sbuf->st_mode, optr, flags); |
|
257 break; |
|
258 |
|
259 case ST_NLINK: |
|
260 statulprint((unsigned long)sbuf->st_nlink, optr); |
|
261 break; |
|
262 |
|
263 case ST_UID: |
|
264 statuidprint(sbuf->st_uid, optr, flags); |
|
265 break; |
|
266 |
|
267 case ST_GID: |
|
268 statgidprint(sbuf->st_gid, optr, flags); |
|
269 break; |
|
270 |
|
271 case ST_RDEV: |
|
272 statulprint((unsigned long)sbuf->st_rdev, optr); |
|
273 break; |
|
274 |
|
275 case ST_SIZE: |
|
276 #ifdef OFF_T_IS_64_BIT |
|
277 convbase(optr, sbuf->st_size, 0); |
|
278 #else |
|
279 DPUTS(sizeof(sbuf->st_size) > 4, |
|
280 "Shell compiled with wrong off_t size"); |
|
281 statulprint((unsigned long)sbuf->st_size, optr); |
|
282 #endif |
|
283 break; |
|
284 |
|
285 case ST_ATIM: |
|
286 stattimeprint(sbuf->st_atime, optr, flags); |
|
287 break; |
|
288 |
|
289 case ST_MTIM: |
|
290 stattimeprint(sbuf->st_mtime, optr, flags); |
|
291 break; |
|
292 |
|
293 case ST_CTIM: |
|
294 stattimeprint(sbuf->st_ctime, optr, flags); |
|
295 break; |
|
296 |
|
297 case ST_BLKSIZE: |
|
298 statulprint((unsigned long)sbuf->st_blksize, optr); |
|
299 break; |
|
300 |
|
301 case ST_BLOCKS: |
|
302 statulprint((unsigned long)sbuf->st_blocks, optr); |
|
303 break; |
|
304 |
|
305 case ST_READLINK: |
|
306 statlinkprint(sbuf, optr, fname); |
|
307 break; |
|
308 |
|
309 case ST_COUNT: /* keep some compilers happy */ |
|
310 break; |
|
311 } |
|
312 } |
|
313 |
|
314 |
|
315 /* |
|
316 * |
|
317 * Options: |
|
318 * -f fd: stat fd instead of file |
|
319 * -g: use GMT rather than local time for time strings (forces -s on). |
|
320 * -n: always print file name of file being statted |
|
321 * -N: never print file name |
|
322 * -l: list stat types |
|
323 * -L: do lstat (else links are implicitly dereferenced by stat) |
|
324 * -t: always print name of stat type |
|
325 * -T: never print name of stat type |
|
326 * -r: print raw alongside string data |
|
327 * -s: string, print mode, times, uid, gid as appropriate strings: |
|
328 * harmless but unnecessary when combined with -r. |
|
329 * -A array: assign results to given array, one stat result per element. |
|
330 * File names and type names are only added if explicitly requested: |
|
331 * file names are returned as a separate array element, type names as |
|
332 * prefix to element. Note the formatting deliberately contains |
|
333 * fewer frills when -A is used. |
|
334 * -H hash: as for -A array, but returns a hash with the keys being those |
|
335 * from stat -l |
|
336 * -F fmt: specify a $TIME-like format for printing times; the default |
|
337 * is the (CTIME-like) "%a %b %e %k:%M:%S". This option implies |
|
338 * -s as it is not useful for numerical times. |
|
339 * |
|
340 * +type selects just element type of stat buffer (-l gives list): |
|
341 * type can be shortened to unambiguous string. only one type is |
|
342 * allowed. The extra type, +link, reads the target of a symbolic |
|
343 * link; it is empty if the stat was not an lstat or if |
|
344 * a file descriptor was stat'd, if the stat'd file is |
|
345 * not a symbolic link, or if symbolic links are not |
|
346 * supported. If +link is explicitly requested, the -L (lstat) |
|
347 * option is set automatically. |
|
348 */ |
|
349 /**/ |
|
350 static int |
|
351 bin_stat(char *name, char **args, Options ops, UNUSED(int func)) |
|
352 { |
|
353 char **aptr, *arrnam = NULL, **array = NULL, **arrptr = NULL; |
|
354 char *hashnam = NULL, **hash = NULL, **hashptr = NULL; |
|
355 int len, iwhich = -1, ret = 0, flags = 0, arrsize = 0, fd = 0; |
|
356 struct stat statbuf; |
|
357 int found = 0, nargs; |
|
358 |
|
359 timefmt = "%a %b %e %k:%M:%S"; |
|
360 |
|
361 for (; *args && (**args == '+' || **args == '-'); args++) { |
|
362 char *arg = *args+1; |
|
363 if (!*arg || *arg == '-' || *arg == '+') { |
|
364 args++; |
|
365 break; |
|
366 } |
|
367 |
|
368 if (**args == '+') { |
|
369 if (found) |
|
370 break; |
|
371 len = strlen(arg); |
|
372 for (aptr = statelts; *aptr; aptr++) |
|
373 if (!strncmp(*aptr, arg, len)) { |
|
374 found++; |
|
375 iwhich = aptr - statelts; |
|
376 } |
|
377 if (found > 1) { |
|
378 zwarnnam(name, "%s: ambiguous stat element", arg, 0); |
|
379 return 1; |
|
380 } else if (found == 0) { |
|
381 zwarnnam(name, "%s: no such stat element", arg, 0); |
|
382 return 1; |
|
383 } |
|
384 /* if name of link requested, turn on lstat */ |
|
385 if (iwhich == ST_READLINK) |
|
386 ops->ind['L'] = 1; |
|
387 flags |= STF_PICK; |
|
388 } else { |
|
389 for (; *arg; arg++) { |
|
390 if (strchr("glLnNorstT", *arg)) |
|
391 ops->ind[STOUC(*arg)] = 1; |
|
392 else if (*arg == 'A') { |
|
393 if (arg[1]) { |
|
394 arrnam = arg+1; |
|
395 } else if (!(arrnam = *++args)) { |
|
396 zwarnnam(name, "missing parameter name", |
|
397 NULL, 0); |
|
398 return 1; |
|
399 } |
|
400 flags |= STF_ARRAY; |
|
401 break; |
|
402 } else if (*arg == 'H') { |
|
403 if (arg[1]) { |
|
404 hashnam = arg+1; |
|
405 } else if (!(hashnam = *++args)) { |
|
406 zwarnnam(name, "missing parameter name", |
|
407 NULL, 0); |
|
408 return 1; |
|
409 } |
|
410 flags |= STF_HASH; |
|
411 break; |
|
412 } else if (*arg == 'f') { |
|
413 char *sfd; |
|
414 ops->ind['f'] = 1; |
|
415 if (arg[1]) { |
|
416 sfd = arg+1; |
|
417 } else if (!(sfd = *++args)) { |
|
418 zwarnnam(name, "missing file descriptor", NULL, 0); |
|
419 return 1; |
|
420 } |
|
421 fd = zstrtol(sfd, &sfd, 10); |
|
422 if (*sfd) { |
|
423 zwarnnam(name, "bad file descriptor", NULL, 0); |
|
424 return 1; |
|
425 } |
|
426 break; |
|
427 } else if (*arg == 'F') { |
|
428 if (arg[1]) { |
|
429 timefmt = arg+1; |
|
430 } else if (!(timefmt = *++args)) { |
|
431 zwarnnam(name, "missing time format", NULL, 0); |
|
432 return 1; |
|
433 } |
|
434 /* force string format in order to use time format */ |
|
435 ops->ind['s'] = 1; |
|
436 break; |
|
437 } else { |
|
438 zwarnnam(name, "bad option: -%c", NULL, *arg); |
|
439 return 1; |
|
440 } |
|
441 } |
|
442 } |
|
443 } |
|
444 |
|
445 if ((flags & STF_ARRAY) && (flags & STF_HASH)) { |
|
446 /* We don't implement setting multiple variables at once */ |
|
447 zwarnnam(name, "both array and hash requested", NULL, 0); |
|
448 return 1; |
|
449 /* Alternate method would be to make -H blank arrnam etc etc * |
|
450 * and so get 'silent loss' of earlier choice, which would * |
|
451 * be similar to stat -A foo -A bar filename */ |
|
452 } |
|
453 |
|
454 if (OPT_ISSET(ops,'l')) { |
|
455 /* list types and return: can also list to array */ |
|
456 if (arrnam) { |
|
457 arrptr = array = (char **)zalloc((ST_COUNT+1)*sizeof(char *)); |
|
458 array[ST_COUNT] = NULL; |
|
459 } |
|
460 for (aptr = statelts; *aptr; aptr++) { |
|
461 if (arrnam) { |
|
462 *arrptr++ = ztrdup(*aptr); |
|
463 } else { |
|
464 printf("%s", *aptr); |
|
465 if (aptr[1]) |
|
466 putchar(' '); |
|
467 } |
|
468 } |
|
469 if (arrnam) { |
|
470 setaparam(arrnam, array); |
|
471 if (errflag) |
|
472 return 1; |
|
473 } else |
|
474 putchar('\n'); |
|
475 return 0; |
|
476 } |
|
477 |
|
478 if (!*args && !OPT_ISSET(ops,'f')) { |
|
479 zwarnnam(name, "no files given", NULL, 0); |
|
480 return 1; |
|
481 } else if (*args && OPT_ISSET(ops,'f')) { |
|
482 zwarnnam(name, "no files allowed with -f", NULL, 0); |
|
483 return 1; |
|
484 } |
|
485 |
|
486 nargs = 0; |
|
487 if (OPT_ISSET(ops,'f')) |
|
488 nargs = 1; |
|
489 else |
|
490 for (aptr = args; *aptr; aptr++) |
|
491 nargs++; |
|
492 |
|
493 if (OPT_ISSET(ops,'g')) { |
|
494 flags |= STF_GMT; |
|
495 ops->ind['s'] = 1; |
|
496 } |
|
497 if (OPT_ISSET(ops,'s') || OPT_ISSET(ops,'r')) |
|
498 flags |= STF_STRING; |
|
499 if (OPT_ISSET(ops,'r') || !OPT_ISSET(ops,'s')) |
|
500 flags |= STF_RAW; |
|
501 if (OPT_ISSET(ops,'n')) |
|
502 flags |= STF_FILE; |
|
503 if (OPT_ISSET(ops,'o')) |
|
504 flags |= STF_OCTAL; |
|
505 if (OPT_ISSET(ops,'t')) |
|
506 flags |= STF_NAME; |
|
507 |
|
508 if (!(arrnam || hashnam)) { |
|
509 if (nargs > 1) |
|
510 flags |= STF_FILE; |
|
511 if (!(flags & STF_PICK)) |
|
512 flags |= STF_NAME; |
|
513 } |
|
514 |
|
515 if (OPT_ISSET(ops,'N') || OPT_ISSET(ops,'f')) |
|
516 flags &= ~STF_FILE; |
|
517 if (OPT_ISSET(ops,'T') || OPT_ISSET(ops,'H')) |
|
518 flags &= ~STF_NAME; |
|
519 |
|
520 if (hashnam) { |
|
521 if (nargs > 1) { |
|
522 zwarnnam(name, "only one file allowed with -H", NULL, 0); |
|
523 return 1; |
|
524 } |
|
525 arrsize = (flags & STF_PICK) ? 1 : ST_COUNT; |
|
526 if (flags & STF_FILE) |
|
527 arrsize++; |
|
528 hashptr = hash = (char **)zshcalloc((arrsize+1)*2*sizeof(char *)); |
|
529 } |
|
530 |
|
531 if (arrnam) { |
|
532 arrsize = (flags & STF_PICK) ? 1 : ST_COUNT; |
|
533 if (flags & STF_FILE) |
|
534 arrsize++; |
|
535 arrsize *= nargs; |
|
536 arrptr = array = (char **)zshcalloc((arrsize+1)*sizeof(char *)); |
|
537 } |
|
538 |
|
539 for (; OPT_ISSET(ops,'f') || *args; args++) { |
|
540 char outbuf[PATH_MAX + 9]; /* "link " + link name + NULL */ |
|
541 int rval = OPT_ISSET(ops,'f') ? fstat(fd, &statbuf) : |
|
542 OPT_ISSET(ops,'L') ? lstat(*args, &statbuf) : |
|
543 stat(*args, &statbuf); |
|
544 if (rval) { |
|
545 if (OPT_ISSET(ops,'f')) |
|
546 sprintf(outbuf, "%d", fd); |
|
547 zwarnnam(name, "%s: %e", OPT_ISSET(ops,'f') ? outbuf : *args, |
|
548 errno); |
|
549 ret = 1; |
|
550 if (OPT_ISSET(ops,'f') || arrnam) |
|
551 break; |
|
552 else |
|
553 continue; |
|
554 } |
|
555 |
|
556 if (flags & STF_FILE) { |
|
557 if (arrnam) |
|
558 *arrptr++ = ztrdup(*args); |
|
559 else if (hashnam) { |
|
560 *hashptr++ = ztrdup(HNAMEKEY); |
|
561 *hashptr++ = ztrdup(*args); |
|
562 } else |
|
563 printf("%s%s", *args, (flags & STF_PICK) ? " " : ":\n"); |
|
564 } |
|
565 if (iwhich > -1) { |
|
566 statprint(&statbuf, outbuf, *args, iwhich, flags); |
|
567 if (arrnam) |
|
568 *arrptr++ = ztrdup(outbuf); |
|
569 else if (hashnam) { |
|
570 /* STF_NAME explicitly turned off for ops.ind['H'] above */ |
|
571 *hashptr++ = ztrdup(statelts[iwhich]); |
|
572 *hashptr++ = ztrdup(outbuf); |
|
573 } else |
|
574 printf("%s\n", outbuf); |
|
575 } else { |
|
576 int i; |
|
577 for (i = 0; i < ST_COUNT; i++) { |
|
578 statprint(&statbuf, outbuf, *args, i, flags); |
|
579 if (arrnam) |
|
580 *arrptr++= ztrdup(outbuf); |
|
581 else if (hashnam) { |
|
582 /* STF_NAME explicitly turned off for ops.ind['H'] above */ |
|
583 *hashptr++ = ztrdup(statelts[i]); |
|
584 *hashptr++ = ztrdup(outbuf); |
|
585 } else |
|
586 printf("%s\n", outbuf); |
|
587 } |
|
588 } |
|
589 if (OPT_ISSET(ops,'f')) |
|
590 break; |
|
591 |
|
592 if (!arrnam && !hashnam && args[1] && !(flags & STF_PICK)) |
|
593 putchar('\n'); |
|
594 } |
|
595 |
|
596 if (arrnam) { |
|
597 if (ret) |
|
598 freearray(array); |
|
599 else { |
|
600 setaparam(arrnam, array); |
|
601 if (errflag) |
|
602 return 1; |
|
603 } |
|
604 } |
|
605 |
|
606 if (hashnam) { |
|
607 if (ret) |
|
608 freearray(hash); |
|
609 else { |
|
610 sethparam(hashnam, hash); |
|
611 if (errflag) |
|
612 return 1; |
|
613 } |
|
614 } |
|
615 |
|
616 return ret; |
|
617 } |
|
618 |
|
619 static struct builtin bintab[] = { |
|
620 BUILTIN("stat", 0, bin_stat, 0, -1, 0, NULL, NULL), |
|
621 }; |
|
622 |
|
623 /**/ |
|
624 int |
|
625 setup_(UNUSED(Module m)) |
|
626 { |
|
627 return 0; |
|
628 } |
|
629 |
|
630 /**/ |
|
631 int |
|
632 boot_(Module m) |
|
633 { |
|
634 return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); |
|
635 } |
|
636 |
|
637 /**/ |
|
638 int |
|
639 cleanup_(Module m) |
|
640 { |
|
641 deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)); |
|
642 return 0; |
|
643 } |
|
644 |
|
645 /**/ |
|
646 int |
|
647 finish_(UNUSED(Module m)) |
|
648 { |
|
649 return 0; |
|
650 } |