1 /* print.c -- print/printf-related code.
2 Copyright (C) 1990-2022 Free Software Foundation, Inc.
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 /* We always include config.h first. */
19 #include <config.h>
20
21 /* system headers go here. */
22 #include <assert.h>
23 #include <ctype.h>
24 #include <errno.h>
25 #include <grp.h>
26 #include <math.h>
27 #include <pwd.h>
28 #include <stdarg.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31
32 /* gnulib headers. */
33 #include "areadlink.h"
34 #include "dirname.h"
35 #include "error.h"
36 #include "filemode.h"
37 #include "human.h"
38 #include "printquoted.h"
39 #include "stat-size.h"
40 #include "stat-time.h"
41 #include "verify.h"
42 #include "xalloc.h"
43
44 /* find-specific headers. */
45 #include "system.h"
46 #include "defs.h"
47 #include "die.h"
48 #include "print.h"
49
50
51 #if defined STDC_HEADERS
52 # define ISDIGIT(c) isdigit ((unsigned char)c)
53 #else
54 # define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
55 #endif
56 #undef MAX
57 #define MAX(a, b) ((a) > (b) ? (a) : (b))
58
59 static void checked_fprintf (struct format_val *dest, const char *fmt, ...)
60 _GL_ATTRIBUTE_FORMAT_PRINTF_STANDARD(2, 3);
61
62
63 /* Create a new fprintf segment in *SEGMENT, with type KIND,
64 from the text in FORMAT, which has length LEN.
65 Return the address of the `next' pointer of the new segment. */
66 struct segment **
67 make_segment (struct segment **segment,
68 char *format,
69 int len,
70 int kind,
71 char format_char,
72 char aux_format_char,
73 struct predicate *pred)
74 {
75 enum EvaluationCost mycost = NeedsNothing;
76 char *fmt;
77
78 assert (format_char != '{');
79 assert (format_char != '[');
80 assert (format_char != '(');
81
82 *segment = xmalloc (sizeof (struct segment));
83
84 (*segment)->segkind = kind;
85 (*segment)->format_char[0] = format_char;
86 (*segment)->format_char[1] = aux_format_char;
87 (*segment)->next = NULL;
88 (*segment)->text_len = len;
89
90 fmt = (*segment)->text = xmalloc (len + sizeof "d");
91 strncpy (fmt, format, len);
92 fmt += len;
93
94 if (kind == KIND_PLAIN /* Plain text string, no % conversion. */
95 || kind == KIND_STOP) /* Terminate argument, no newline. */
96 {
97 assert (0 == format_char);
98 assert (0 == aux_format_char);
99 *fmt = '\0';
100 if (mycost > pred->p_cost)
101 pred->p_cost = NeedsNothing;
102 return &(*segment)->next;
103 }
104
105 assert (kind == KIND_FORMAT);
106 switch (format_char)
107 {
108 case '%': /* literal % */
109 *fmt++ = '%';
110 break;
111
112 case 'l': /* object of symlink */
113 pred->need_stat = true;
114 mycost = NeedsLinkName;
115 *fmt++ = 's';
116 break;
117
118 case 'y': /* file type */
119 pred->need_type = true;
120 mycost = NeedsType;
121 *fmt++ = 's';
122 break;
123
124 case 'i': /* inode number */
125 pred->need_inum = true;
126 mycost = NeedsInodeNumber;
127 *fmt++ = 's';
128 break;
129
130 case 'a': /* atime in `ctime' format */
131 case 'A': /* atime in user-specified strftime format */
132 case 'B': /* birth time in user-specified strftime format */
133 case 'c': /* ctime in `ctime' format */
134 case 'C': /* ctime in user-specified strftime format */
135 case 'F': /* file system type */
136 case 'g': /* group name */
137 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
138 case 's': /* size in bytes */
139 case 't': /* mtime in `ctime' format */
140 case 'T': /* mtime in user-specified strftime format */
141 case 'u': /* user name */
142 pred->need_stat = true;
143 mycost = NeedsStatInfo;
144 *fmt++ = 's';
145 break;
146
147 case 'S': /* sparseness */
148 pred->need_stat = true;
149 mycost = NeedsStatInfo;
150 *fmt++ = 'g';
151 break;
152
153 case 'Y': /* symlink pointed file type */
154 pred->need_stat = true;
155 mycost = NeedsType; /* true for amortised effect */
156 *fmt++ = 's';
157 break;
158
159 case 'f': /* basename of path */
160 case 'h': /* leading directories part of path */
161 case 'p': /* pathname */
162 case 'P': /* pathname with ARGV element stripped */
163 *fmt++ = 's';
164 break;
165
166 case 'Z': /* SELinux security context */
167 mycost = NeedsAccessInfo;
168 *fmt++ = 's';
169 break;
170
171 case 'H': /* ARGV element file was found under */
172 *fmt++ = 's';
173 break;
174
175 /* Numeric items that one might expect to honour
176 * #, 0, + flags but which do not.
177 */
178 case 'G': /* GID number */
179 case 'U': /* UID number */
180 case 'b': /* size in 512-byte blocks (NOT birthtime in ctime fmt)*/
181 case 'D': /* Filesystem device on which the file exits */
182 case 'k': /* size in 1K blocks */
183 case 'n': /* number of links */
184 pred->need_stat = true;
185 mycost = NeedsStatInfo;
186 *fmt++ = 's';
187 break;
188
189 /* Numeric items that DO honour #, 0, + flags.
190 */
191 case 'd': /* depth in search tree (0 = ARGV element) */
192 *fmt++ = 'd';
193 break;
194
195 case 'm': /* mode as octal number (perms only) */
196 *fmt++ = 'o';
197 pred->need_stat = true;
198 mycost = NeedsStatInfo;
199 break;
200 }
201 *fmt = '\0';
202
203 if (mycost > pred->p_cost)
204 pred->p_cost = mycost;
205 return &(*segment)->next;
206 }
207
208 static bool
209 is_octal_char (char ch)
210 {
211 return ch >= '0' && ch <= '7';
212 }
213
214 static char
215 parse_octal_escape(const char *p, size_t *consumed)
216 {
217 register int n, i;
218 size_t pos = 0;
219
220 for (i = n = 0; i < 3 && is_octal_char(p[pos]); i++, pos++)
221 {
222 n = 8 * n + p[pos] - '0';
223 }
224 --pos;
225 *consumed = pos;
226 return n;
227 }
228
229 static int
230 parse_escape_char(const char ch)
231 {
232 char value = 0;
233 switch (ch)
234 {
235 case 'a':
236 value = '\a';
237 break;
238 case 'b':
239 value = '\b';
240 break;
241 case 'f':
242 value = '\f';
243 break;
244 case 'n':
245 value = '\n';
246 break;
247 case 'r':
248 value = '\r';
249 break;
250 case 't':
251 value = '\t';
252 break;
253 case 'v':
254 value = '\v';
255 break;
256 case '\\':
257 value = '\\';
258 break;
259 }
260 return value;
261 }
262
263
264 static size_t
265 get_format_flags_length(const char *p)
266 {
267 size_t n = 0;
268 /* Scan past flags, width and precision, to verify kind. */
269 for (; p[++n] && strchr ("-+ #", p[n]);)
270 {
271 /* Do nothing. */
272 }
273 while (ISDIGIT (p[n]))
274 n++;
275 if (p[n] == '.')
276 for (n++; ISDIGIT (p[n]); n++)
277 /* Do nothing. */ ;
278 return n;
279 }
280
281 static size_t
282 get_format_specifer_length(char ch)
283 {
284 if (strchr ("abcdDfFgGhHiklmMnpPsStuUyYZ%", ch))
285 {
286 return 1;
287 }
288 else if (strchr ("ABCT", ch))
289 {
290 return 2;
291 }
292 else
293 {
294 return 0;
295 }
296 }
297
298
299 bool
300 insert_fprintf (struct format_val *vec,
301 const struct parser_table *entry,
302 char *format)
303 {
304 char *segstart = format;
305 char *fmt_editpos; /* Current address in scanning `format'. */
306 struct segment **segmentp; /* Address of current segment. */
307 struct predicate *our_pred;
308
309 our_pred = insert_primary_withpred (entry, pred_fprintf, format);
310 our_pred->side_effects = our_pred->no_default_print = true;
311 our_pred->args.printf_vec = *vec;
312 our_pred->need_type = false;
313 our_pred->need_stat = false;
314 our_pred->p_cost = NeedsNothing;
315
316 segmentp = &our_pred->args.printf_vec.segment;
317 *segmentp = NULL;
318
319 for (fmt_editpos = segstart; *fmt_editpos; fmt_editpos++)
320 {
321 if (fmt_editpos[0] == '\\' && fmt_editpos[1] == 'c')
322 {
323 make_segment (segmentp, segstart, fmt_editpos - segstart,
324 KIND_STOP, 0, 0,
325 our_pred);
326 if (our_pred->need_stat && (our_pred->p_cost < NeedsStatInfo))
327 our_pred->p_cost = NeedsStatInfo;
328 return true;
329 }
330 else if (*fmt_editpos == '\\')
331 {
332 size_t readpos = 1;
333 if (!fmt_editpos[readpos])
334 {
335 error (0, 0, _("warning: escape `\\' followed by nothing at all"));
336 --readpos;
337 /* (*fmt_editpos) is already '\\' and that's a reasonable result. */
338 }
339 else if (is_octal_char(fmt_editpos[readpos]))
340 {
341 size_t consumed = 0;
342 *fmt_editpos = parse_octal_escape(fmt_editpos + readpos, &consumed);
343 readpos += consumed;
344 }
345 else
346 {
347 const char val = parse_escape_char(fmt_editpos[readpos]);
348 if (val)
349 {
350 fmt_editpos[0] = val;
351 }
352 else
353 {
354 error (0, 0, _("warning: unrecognized escape `\\%c'"),
355 fmt_editpos[readpos]);
356 fmt_editpos += readpos;
357 continue;
358 }
359 }
360 segmentp = make_segment (segmentp,
361 segstart, fmt_editpos - segstart + 1,
362 KIND_PLAIN, 0, 0,
363 our_pred);
364 segstart = fmt_editpos + readpos + 1; /* Move past the escape. */
365 fmt_editpos += readpos; /* Incremented immediately by `for'. */
366 }
367 else if (fmt_editpos[0] == '%')
368 {
369 size_t len;
370 if (fmt_editpos[1] == 0)
371 {
372 /* Trailing %. We don't like those. */
373 die (EXIT_FAILURE, 0,
374 _("error: %s at end of format string"), fmt_editpos);
375 }
376
377 if (fmt_editpos[1] == '%') /* %% produces just %. */
378 len = 1;
379 else
380 len = get_format_flags_length(fmt_editpos);
381 fmt_editpos += len;
382
383 len = get_format_specifer_length (fmt_editpos[0]);
384 if (len && (fmt_editpos[len-1]))
385 {
386 const char fmt2 = (len == 2) ? fmt_editpos[1] : 0;
387 segmentp = make_segment (segmentp, segstart,
388 fmt_editpos - segstart,
389 KIND_FORMAT, fmt_editpos[0], fmt2,
390 our_pred);
391 fmt_editpos += (len - 1);
392 }
393 else
394 {
395 if (strchr ("{[(", fmt_editpos[0]))
396 {
397 die (EXIT_FAILURE, 0,
398 _("error: the format directive `%%%c' is reserved for future use"),
399 (int)fmt_editpos[0]);
400 /*NOTREACHED*/
401 }
402
403 if (len == 2 && !fmt_editpos[1])
404 {
405 error (0, 0,
406 _("warning: format directive `%%%c' "
407 "should be followed by another character"),
408 fmt_editpos[0]);
409 }
410 else
411 {
412 /* An unrecognized % escape. Print the char after the %. */
413 error (0, 0,
414 _("warning: unrecognized format directive `%%%c'"),
415 fmt_editpos[0]);
416 }
417 segmentp = make_segment (segmentp,
418 segstart, fmt_editpos + 1 - segstart,
419 KIND_PLAIN, 0, 0,
420 our_pred);
421 }
422 segstart = fmt_editpos + 1;
423 }
424 }
425
426 if (fmt_editpos > segstart)
427 make_segment (segmentp, segstart, fmt_editpos - segstart, KIND_PLAIN, 0, 0,
428 our_pred);
429 return true;
430 }
431
432 static bool
433 scan_for_digit_differences (const char *p, const char *q,
434 size_t *first, size_t *n)
435 {
436 bool seen = false;
437 size_t i;
438
439 for (i=0; p[i] && q[i]; i++)
440 {
441 if (p[i] != q[i])
442 {
443 if (!isdigit ((unsigned char)p[i]) || !isdigit ((unsigned char)q[i]))
444 return false;
445
446 if (!seen)
447 {
448 *first = i;
449 *n = 1;
450 seen = 1;
451 }
452 else
453 {
454 if (i-*first == *n)
455 {
456 /* Still in the first sequence of differing digits. */
457 ++*n;
458 }
459 else
460 {
461 /* More than one differing contiguous character sequence. */
462 return false;
463 }
464 }
465 }
466 }
467 if (p[i] || q[i])
468 {
469 /* strings are different lengths. */
470 return false;
471 }
472 return true;
473 }
474
475 static char*
476 do_time_format (const char *fmt, const struct tm *p, const char *ns, size_t ns_size)
477 {
478 static char *buf = NULL;
479 static size_t buf_size;
480 char *timefmt = NULL;
481 struct tm altered_time;
482
483
484 /* If the format expands to nothing (%p in some locales, for
485 * example), strftime can return 0. We actually want to distinguish
486 * the error case where the buffer is too short, so we just prepend
487 * an otherwise uninteresting character to prevent the no-output
488 * case.
489 */
490 timefmt = xmalloc (strlen (fmt) + 2u);
491 timefmt[0] = '_';
492 memcpy (timefmt + 1, fmt, strlen (fmt) + 1);
493
494 /* altered_time is a similar time, but in which both
495 * digits of the seconds field are different.
496 */
497 altered_time = *p;
498 if (altered_time.tm_sec >= 11)
499 altered_time.tm_sec -= 11;
500 else
501 altered_time.tm_sec += 11;
502
503 /* If we call strftime() with buf_size=0, the program will coredump
504 * on Solaris, since it unconditionally writes the terminating null
505 * character.
506 */
507 if (buf == NULL)
508 {
509 buf_size = 1u;
510 buf = xmalloc (buf_size);
511 }
512 while (true)
513 {
514 /* I'm not sure that Solaris will return 0 when the buffer is too small.
515 * Therefore we do not check for (buf_used != 0) as the termination
516 * condition.
517 */
518 size_t buf_used = strftime (buf, buf_size, timefmt, p);
519 if (buf_used /* Conforming POSIX system */
520 && (buf_used < buf_size)) /* Solaris workaround */
521 {
522 char *altbuf;
523 size_t i = 0, n = 0;
524 size_t final_len = (buf_used
525 + 1u /* for \0 */
526 + ns_size);
527 buf = xrealloc (buf, final_len);
528 buf_size = final_len;
529 altbuf = xmalloc (final_len);
530 strftime (altbuf, buf_size, timefmt, &altered_time);
531
532 /* Find the seconds digits; they should be the only changed part.
533 * In theory the result of the two formatting operations could differ in
534 * more than just one sequence of decimal digits (for example %X might
535 * in theory return a spelled-out time like "thirty seconds past noon").
536 * When that happens, we just avoid inserting the nanoseconds field.
537 */
538 if (scan_for_digit_differences (buf, altbuf, &i, &n)
539 && (2==n) && !isdigit ((unsigned char)buf[i+n]))
540 {
541 const size_t end_of_seconds = i + n;
542 const size_t suffix_len = buf_used-(end_of_seconds)+1;
543
544 /* Move the tail (including the \0). Note that this
545 * is a move of an overlapping memory block, so we
546 * must use memmove instead of memcpy. Then insert
547 * the nanoseconds (but not its trailing \0).
548 */
549 assert (end_of_seconds + ns_size + suffix_len == final_len);
550 memmove (buf+end_of_seconds+ns_size,
551 buf+end_of_seconds,
552 suffix_len);
553 memcpy (buf+i+n, ns, ns_size);
554 }
555 else
556 {
557 /* No seconds digits. No need to insert anything. */
558 }
559 /* The first character of buf is the underscore, which we actually
560 * don't want.
561 */
562 free (timefmt);
563 free (altbuf);
564 return buf+1;
565 }
566 else
567 {
568 buf = x2nrealloc (buf, &buf_size, sizeof *buf);
569 }
570 }
571 }
572
573 /* Return a static string formatting the time WHEN according to the
574 * strftime format character KIND.
575 *
576 * This function contains a number of assertions. These look like
577 * runtime checks of the results of computations, which would be a
578 * problem since external events should not be tested for with
579 * "assert" (instead you should use "if"). However, they are not
580 * really runtime checks. The assertions actually exist to verify
581 * that the various buffers are correctly sized.
582 */
583 static char *
584 format_date (struct timespec ts, int kind)
585 {
586 /* In theory, we use an extra 10 characters for 9 digits of
587 * nanoseconds and 1 for the decimal point. However, the real
588 * world is more complex than that.
589 *
590 * For example, some systems return junk in the tv_nsec part of
591 * st_birthtime. An example of this is the NetBSD-4.0-RELENG kernel
592 * (at Sat Mar 24 18:46:46 2007) running a NetBSD-3.1-RELEASE
593 * runtime and examining files on an msdos filesytem. So for that
594 * reason we set NS_BUF_LEN to 32, which is simply "long enough" as
595 * opposed to "exactly the right size". Note that the behaviour of
596 * NetBSD appears to be a result of the use of uninitialized data,
597 * as it's not 100% reproducible (more like 25%).
598 */
599 enum {
600 NS_BUF_LEN = 32,
601 DATE_LEN_PERCENT_APLUS=21 /* length of result of %A+ (it's longer than %c)*/
602 };
603 static char buf[128u+10u + MAX(DATE_LEN_PERCENT_APLUS,
604 MAX (LONGEST_HUMAN_READABLE + 2, NS_BUF_LEN+64+200))];
605 char ns_buf[NS_BUF_LEN]; /* -.9999999990 (- sign can happen!)*/
606 int charsprinted, need_ns_suffix;
607 struct tm *tm;
608 char fmt[12];
609
610 /* human_readable() assumes we pass a buffer which is at least as
611 * long as LONGEST_HUMAN_READABLE. We use an assertion here to
612 * ensure that no nasty unsigned overflow happened in our calculation
613 * of the size of buf. Do the assertion here rather than in the
614 * code for %@ so that we find the problem quickly if it exists. If
615 * you want to submit a patch to move this into the if statement, go
616 * ahead, I'll apply it. But include performance timings
617 * demonstrating that the performance difference is actually
618 * measurable.
619 */
620 verify (sizeof (buf) >= LONGEST_HUMAN_READABLE);
621
622 charsprinted = 0;
623 need_ns_suffix = 0;
624
625 /* Format the main part of the time. */
626 if (kind == '+')
627 {
628 /* Avoid %F, some Unix versions lack it. For example:
629 HP Tru64 UNIX V5.1B (Rev. 2650); Wed Feb 17 22:59:59 CST 2016
630 Also, some older HP-UX versions expand %F as the full month (like %B).
631 Reported by Steven M. Schweda <sms@antinode.info> */
632 strcpy (fmt, "%Y-%m-%d+%T");
633 need_ns_suffix = 1;
634 }
635 else
636 {
637 fmt[0] = '%';
638 fmt[1] = kind;
639 fmt[2] = '\0';
640
641 /* %a, %c, and %t are handled in ctime_format() */
642 switch (kind)
643 {
644 case 'S':
645 case 'T':
646 case 'X':
647 case '@':
648 need_ns_suffix = 1;
649 break;
650 default:
651 need_ns_suffix = 0;
652 break;
653 }
654 }
655
656 if (need_ns_suffix)
657 {
658 /* Format the nanoseconds part. Leave a trailing zero to
659 * discourage people from writing scripts which extract the
660 * fractional part of the timestamp by using column offsets.
661 * The reason for discouraging this is that in the future, the
662 * granularity may not be nanoseconds.
663 */
664 charsprinted = snprintf (ns_buf, NS_BUF_LEN, ".%09ld0", (long int)ts.tv_nsec);
665 assert (charsprinted < NS_BUF_LEN);
666 }
667 else
668 {
669 charsprinted = 0;
670 ns_buf[0] = 0;
671 }
672
673 if (kind != '@')
674 {
675 tm = localtime (&ts.tv_sec);
676 if (tm)
677 {
678 char *s = do_time_format (fmt, tm, ns_buf, charsprinted);
679 if (s)
680 return s;
681 }
682 }
683
684 /* If we get to here, either the format was %@, or we have fallen back to it
685 * because strftime failed.
686 */
687 if (1)
688 {
689 uintmax_t w = ts.tv_sec;
690 size_t used, len, remaining;
691
692 /* XXX: note that we are negating an unsigned type which is the
693 * widest possible unsigned type.
694 */
695 char *p = human_readable (ts.tv_sec < 0 ? -w : w, buf + 1,
696 human_ceiling, 1, 1);
697 assert (p > buf);
698 assert (p < (buf + (sizeof buf)));
699 if (ts.tv_sec < 0)
700 *--p = '-'; /* XXX: Ugh, relying on internal details of human_readable(). */
701
702 /* Add the nanoseconds part. Because we cannot enforce a
703 * particlar implementation of human_readable, we cannot assume
704 * any particular value for (p-buf). So we need to be careful
705 * that there is enough space remaining in the buffer.
706 */
707 if (need_ns_suffix)
708 {
709 len = strlen (p);
710 used = (p-buf) + len; /* Offset into buf of current end */
711 assert (sizeof buf > used); /* Ensure we can perform subtraction safely. */
712 remaining = sizeof buf - used - 1u; /* allow space for NUL */
713
714 if (strlen (ns_buf) >= remaining)
715 {
716 error (0, 0,
717 "charsprinted=%ld but remaining=%lu: ns_buf=%s",
718 (long)charsprinted, (unsigned long)remaining, ns_buf);
719 }
720 assert (strlen (ns_buf) < remaining);
721 strcat (p, ns_buf);
722 }
723 return p;
724 }
725 }
726
727 static const char *weekdays[] =
728 {
729 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
730 };
731 static const char * months[] =
732 {
733 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
734 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
735 };
736
737
738 static char *
739 ctime_format (struct timespec ts)
740 {
741 const struct tm * ptm;
742 #define TIME_BUF_LEN 1024
743 static char resultbuf[TIME_BUF_LEN];
744 int nout;
745
746 ptm = localtime (&ts.tv_sec);
747 if (ptm)
748 {
749 assert (ptm->tm_wday >= 0);
750 assert (ptm->tm_wday < 7);
751 assert (ptm->tm_mon >= 0);
752 assert (ptm->tm_mon < 12);
753 assert (ptm->tm_hour >= 0);
754 assert (ptm->tm_hour < 24);
755 assert (ptm->tm_min < 60);
756 assert (ptm->tm_sec <= 61); /* allows 2 leap seconds. */
757
758 /* wkday mon mday hh:mm:ss.nnnnnnnnn yyyy */
759 nout = snprintf (resultbuf, TIME_BUF_LEN,
760 "%3s %3s %2d %02d:%02d:%02d.%09ld0 %04d",
761 weekdays[ptm->tm_wday],
762 months[ptm->tm_mon],
763 ptm->tm_mday,
764 ptm->tm_hour,
765 ptm->tm_min,
766 ptm->tm_sec,
767 (long int)ts.tv_nsec,
768 1900 + ptm->tm_year);
769
770 assert (nout < TIME_BUF_LEN);
771 return resultbuf;
772 }
773 else
774 {
775 /* The time cannot be represented as a struct tm.
776 Output it as an integer. */
777 return format_date (ts, '@');
778 }
779 }
780
781 static double
782 file_sparseness (const struct stat *p)
783 {
784 if (0 == p->st_size)
785 {
786 if (0 == ST_NBLOCKS(*p))
787 return 1.0;
788 else
789 return ST_NBLOCKS(*p) < 0 ? -HUGE_VAL : HUGE_VAL;
790 }
791 else
792 {
793 double blklen = ST_NBLOCKSIZE * (double)ST_NBLOCKS(*p);
794 return blklen / p->st_size;
795 }
796 }
797
798
799 static void
800 checked_fprintf (struct format_val *dest, const char *fmt, ...)
801 {
802 int rv;
803 va_list ap;
804
805 va_start (ap, fmt);
806 rv = vfprintf (dest->stream, fmt, ap);
807 va_end (ap);
808 if (rv < 0)
809 nonfatal_nontarget_file_error (errno, dest->filename);
810 }
811
812 static void
813 checked_print_quoted (struct format_val *dest,
814 const char *format, const char *s)
815 {
816 int rv = print_quoted (dest->stream, dest->quote_opts, dest->dest_is_tty,
817 format, s);
818 if (rv < 0)
819 nonfatal_nontarget_file_error (errno, dest->filename);
820 }
821
822
823 static void
824 checked_fwrite (void *p, size_t siz, size_t nmemb, struct format_val *dest)
825 {
826 const size_t items_written = fwrite (p, siz, nmemb, dest->stream);
827 if (items_written < nmemb)
828 nonfatal_nontarget_file_error (errno, dest->filename);
829 }
830
831 static void
832 checked_fflush (struct format_val *dest)
833 {
834 if (0 != fflush (dest->stream))
835 {
836 nonfatal_nontarget_file_error (errno, dest->filename);
837 }
838 }
839
840 static const char*
841 mode_to_filetype (mode_t m)
842 {
843 #define HANDLE_TYPE(t,letter) if (m==t) { return letter; }
844 #ifdef S_IFREG
845 HANDLE_TYPE(S_IFREG, "f"); /* regular file */
846 #endif
847 #ifdef S_IFDIR
848 HANDLE_TYPE(S_IFDIR, "d"); /* directory */
849 #endif
850 #ifdef S_IFLNK
851 HANDLE_TYPE(S_IFLNK, "l"); /* symbolic link */
852 #endif
853 #ifdef S_IFSOCK
854 HANDLE_TYPE(S_IFSOCK, "s"); /* Unix domain socket */
855 #endif
856 #ifdef S_IFBLK
857 HANDLE_TYPE(S_IFBLK, "b"); /* block device */
858 #endif
859 #ifdef S_IFCHR
860 HANDLE_TYPE(S_IFCHR, "c"); /* character device */
861 #endif
862 #ifdef S_IFIFO
863 HANDLE_TYPE(S_IFIFO, "p"); /* FIFO */
864 #endif
865 #ifdef S_IFDOOR
866 HANDLE_TYPE(S_IFDOOR, "D"); /* Door (e.g. on Solaris) */
867 #endif
868 return "U"; /* Unknown */
869 }
870
871
872
873 static void
874 do_fprintf (struct format_val *dest,
875 struct segment *segment,
876 const char *pathname,
877 const struct stat *stat_buf)
878 {
879 char hbuf[LONGEST_HUMAN_READABLE + 1];
880 const char *cp;
881
882 switch (segment->segkind)
883 {
884 case KIND_PLAIN: /* Plain text string (no % conversion). */
885 /* trusted */
886 checked_fwrite(segment->text, 1, segment->text_len, dest);
887 break;
888
889 case KIND_STOP: /* Terminate argument and flush output. */
890 /* trusted */
891 checked_fwrite (segment->text, 1, segment->text_len, dest);
892 checked_fflush (dest);
893 break;
894
895 case KIND_FORMAT:
896 switch (segment->format_char[0])
897 {
898 case 'a': /* atime in `ctime' format. */
899 /* UNTRUSTED, probably unexploitable */
900 checked_fprintf (dest, segment->text, ctime_format (get_stat_atime (stat_buf)));
901 break;
902 case 'b': /* size in 512-byte blocks */
903 /* UNTRUSTED, probably unexploitable */
904 checked_fprintf (dest, segment->text,
905 human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
906 hbuf, human_ceiling,
907 ST_NBLOCKSIZE, 512));
908 break;
909 case 'c': /* ctime in `ctime' format */
910 /* UNTRUSTED, probably unexploitable */
911 checked_fprintf (dest, segment->text, ctime_format (get_stat_ctime (stat_buf)));
912 break;
913 case 'd': /* depth in search tree */
914 /* UNTRUSTED, probably unexploitable */
915 checked_fprintf (dest, segment->text, state.curdepth);
916 break;
917 case 'D': /* Device on which file exists (stat.st_dev) */
918 /* trusted */
919 checked_fprintf (dest, segment->text,
920 human_readable ((uintmax_t) stat_buf->st_dev, hbuf,
921 human_ceiling, 1, 1));
922 break;
923 case 'f': /* base name of path */
924 /* sanitised */
925 {
926 char *base = base_name (pathname);
927 checked_print_quoted (dest, segment->text, base);
928 free (base);
929 }
930 break;
931 case 'F': /* file system type */
932 /* trusted */
933 checked_print_quoted (dest, segment->text, filesystem_type (stat_buf, pathname));
934 break;
935 case 'g': /* group name */
936 /* trusted */
937 /* (well, the actual group is selected by the user but
938 * its name was selected by the system administrator)
939 */
940 {
941 struct group *g;
942
943 g = getgrgid (stat_buf->st_gid);
944 if (g)
945 {
946 segment->text[segment->text_len] = 's';
947 checked_fprintf (dest, segment->text, g->gr_name);
948 break;
949 }
950 }
951 FALLTHROUGH; /*...sometimes, so 'G' case.*/
952
953 case 'G': /* GID number */
954 /* UNTRUSTED, probably unexploitable */
955 checked_fprintf (dest, segment->text,
956 human_readable ((uintmax_t) stat_buf->st_gid, hbuf,
957 human_ceiling, 1, 1));
958 break;
959 case 'h': /* leading directories part of path */
960 /* sanitised */
961 {
962 char *pname = xstrdup (pathname);
963
964 /* Remove trailing slashes - unless it's the root '/' directory. */
965 char *s = pname + strlen (pname) -1;
966 for ( ; pname <= s; s--)
967 if (*s != '/')
968 break;
969 if (pname < s && *(s+1) == '/')
970 *(s+1) = '\0';
971
972 s = strrchr (pname, '/');
973 if (s == NULL) /* No leading directories. */
974 {
975 /* If there is no slash in the pathname, we still
976 * print the string because it contains characters
977 * other than just '%s'. The %h expands to ".".
978 */
979 checked_print_quoted (dest, segment->text, ".");
980 }
981 else
982 {
983 *s = '\0';
984 checked_print_quoted (dest, segment->text, pname);
985 }
986 free (pname);
987 }
988 break;
989
990 case 'H': /* ARGV element file was found under */
991 /* trusted */
992 {
993 char *s = xmalloc (state.starting_path_length+1);
994 memcpy (s, pathname, state.starting_path_length);
995 s[state.starting_path_length] = 0;
996 checked_fprintf (dest, segment->text, s);
997 free (s);
998 }
999 break;
1000
1001 case 'i': /* inode number */
1002 /* UNTRUSTED, but not exploitable I think */
1003 /* POSIX does not guarantee that ino_t is unsigned or even
1004 * integral (except as an XSI extension), but we'll work on
1005 * fixing that if we ever get a report of a system where
1006 * ino_t is indeed a signed integral type or a non-integral
1007 * arithmetic type. */
1008 checked_fprintf (dest, segment->text,
1009 human_readable ((uintmax_t) stat_buf->st_ino, hbuf,
1010 human_ceiling,
1011 1, 1));
1012 break;
1013 case 'k': /* size in 1K blocks */
1014 /* UNTRUSTED, but not exploitable I think */
1015 checked_fprintf (dest, segment->text,
1016 human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
1017 hbuf, human_ceiling,
1018 ST_NBLOCKSIZE, 1024));
1019 break;
1020 case 'l': /* object of symlink */
1021 /* sanitised */
1022 #ifdef S_ISLNK
1023 {
1024 char *linkname = NULL;
1025
1026 if (S_ISLNK (stat_buf->st_mode))
1027 {
1028 linkname = areadlinkat (state.cwd_dir_fd, state.rel_pathname);
1029 if (linkname == NULL)
1030 {
1031 nonfatal_target_file_error (errno, pathname);
1032 state.exit_status = EXIT_FAILURE;
1033 }
1034 }
1035 if (linkname)
1036 {
1037 checked_print_quoted (dest, segment->text, linkname);
1038 }
1039 else
1040 {
1041 /* We still need to honour the field width etc., so this is
1042 * not a no-op.
1043 */
1044 checked_print_quoted (dest, segment->text, "");
1045 }
1046 free (linkname);
1047 }
1048 #endif /* S_ISLNK */
1049 break;
1050
1051 case 'M': /* mode as 10 chars (eg., "-rwxr-x--x" */
1052 /* UNTRUSTED, probably unexploitable */
1053 {
1054 char modestring[16] ;
1055 filemodestring (stat_buf, modestring);
1056 modestring[10] = '\0';
1057 checked_fprintf (dest, segment->text, modestring);
1058 }
1059 break;
1060
1061 case 'm': /* mode as octal number (perms only) */
1062 /* UNTRUSTED, probably unexploitable */
1063 {
1064 /* Output the mode portably using the traditional numbers,
1065 even if the host unwisely uses some other numbering
1066 scheme. But help the compiler in the common case where
1067 the host uses the traditional numbering scheme. */
1068 mode_t m = stat_buf->st_mode;
1069 bool traditional_numbering_scheme =
1070 (S_ISUID == 04000 && S_ISGID == 02000 && S_ISVTX == 01000
1071 && S_IRUSR == 00400 && S_IWUSR == 00200 && S_IXUSR == 00100
1072 && S_IRGRP == 00040 && S_IWGRP == 00020 && S_IXGRP == 00010
1073 && S_IROTH == 00004 && S_IWOTH == 00002 && S_IXOTH == 00001);
1074 checked_fprintf (dest, segment->text,
1075 (traditional_numbering_scheme
1076 ? m & MODE_ALL
1077 : ((m & S_ISUID ? 04000 : 0)
1078 | (m & S_ISGID ? 02000 : 0)
1079 | (m & S_ISVTX ? 01000 : 0)
1080 | (m & S_IRUSR ? 00400 : 0)
1081 | (m & S_IWUSR ? 00200 : 0)
1082 | (m & S_IXUSR ? 00100 : 0)
1083 | (m & S_IRGRP ? 00040 : 0)
1084 | (m & S_IWGRP ? 00020 : 0)
1085 | (m & S_IXGRP ? 00010 : 0)
1086 | (m & S_IROTH ? 00004 : 0)
1087 | (m & S_IWOTH ? 00002 : 0)
1088 | (m & S_IXOTH ? 00001 : 0))));
1089 }
1090 break;
1091
1092 case 'n': /* number of links */
1093 /* UNTRUSTED, probably unexploitable */
1094 checked_fprintf (dest, segment->text,
1095 human_readable ((uintmax_t) stat_buf->st_nlink,
1096 hbuf,
1097 human_ceiling,
1098 1, 1));
1099 break;
1100
1101 case 'p': /* pathname */
1102 /* sanitised */
1103 checked_print_quoted (dest, segment->text, pathname);
1104 break;
1105
1106 case 'P': /* pathname with ARGV element stripped */
1107 /* sanitised */
1108 if (state.curdepth > 0)
1109 {
1110 cp = pathname + state.starting_path_length;
1111 if (*cp == '/')
1112 /* Move past the slash between the ARGV element
1113 and the rest of the pathname. But if the ARGV element
1114 ends in a slash, we didn't add another, so we've
1115 already skipped past it. */
1116 cp++;
1117 }
1118 else
1119 {
1120 cp = "";
1121 }
1122 checked_print_quoted (dest, segment->text, cp);
1123 break;
1124
1125 case 's': /* size in bytes */
1126 /* UNTRUSTED, probably unexploitable */
1127 checked_fprintf (dest, segment->text,
1128 human_readable ((uintmax_t) stat_buf->st_size,
1129 hbuf, human_ceiling, 1, 1));
1130 break;
1131
1132 case 'S': /* sparseness */
1133 /* UNTRUSTED, probably unexploitable */
1134 checked_fprintf (dest, segment->text, file_sparseness (stat_buf));
1135 break;
1136
1137 case 't': /* mtime in `ctime' format */
1138 /* UNTRUSTED, probably unexploitable */
1139 checked_fprintf (dest, segment->text,
1140 ctime_format (get_stat_mtime (stat_buf)));
1141 break;
1142
1143 case 'u': /* user name */
1144 /* trusted */
1145 /* (well, the actual user is selected by the user on systems
1146 * where chown is not restricted, but the user name was
1147 * selected by the system administrator)
1148 */
1149 {
1150 struct passwd *p;
1151
1152 p = getpwuid (stat_buf->st_uid);
1153 if (p)
1154 {
1155 segment->text[segment->text_len] = 's';
1156 checked_fprintf (dest, segment->text, p->pw_name);
1157 break;
1158 }
1159 }
1160 FALLTHROUGH; /* .. to case U */
1161
1162 case 'U': /* UID number */
1163 /* UNTRUSTED, probably unexploitable */
1164 checked_fprintf (dest, segment->text,
1165 human_readable ((uintmax_t) stat_buf->st_uid, hbuf,
1166 human_ceiling, 1, 1));
1167 break;
1168
1169 /* %Y: type of file system entry like `ls -l`:
1170 * (d,-,l,s,p,b,c,n) n=nonexistent (symlink)
1171 */
1172 case 'Y': /* in case of symlink */
1173 /* trusted */
1174 {
1175 #ifdef S_ISLNK
1176 if (S_ISLNK (stat_buf->st_mode))
1177 {
1178 struct stat sbuf;
1179 /* %Y needs to stat the symlink target regardless of
1180 * whether we would normally follow symbolic links or not.
1181 * (Actually we do not even come here when following_links()
1182 * other than the ENOENT case.)
1183 */
1184 if (fstatat (state.cwd_dir_fd, state.rel_pathname, &sbuf, 0) != 0)
1185 {
1186 if ( (errno == ENOENT) || (errno == ENOTDIR) )
1187 {
1188 checked_fprintf (dest, segment->text, "N");
1189 break;
1190 }
1191 else if ( errno == ELOOP )
1192 {
1193 checked_fprintf (dest, segment->text, "L");
1194 break;
1195 }
1196 else
1197 {
1198 checked_fprintf (dest, segment->text, "?");
1199 error (0, errno, "%s",
1200 safely_quote_err_filename (0, pathname));
1201 /* exit_status = EXIT_FAILURE;
1202 return ; */
1203 break;
1204 }
1205 }
1206 checked_fprintf (dest, segment->text,
1207 mode_to_filetype (sbuf.st_mode & S_IFMT));
1208 }
1209 else
1210 #endif /* S_ISLNK */
1211 {
1212 checked_fprintf (dest, segment->text,
1213 mode_to_filetype (stat_buf->st_mode & S_IFMT));
1214 }
1215 }
1216 break;
1217
1218 case 'y':
1219 /* trusted */
1220 {
1221 checked_fprintf (dest, segment->text,
1222 mode_to_filetype (stat_buf->st_mode & S_IFMT));
1223 }
1224 break;
1225
1226 case 'Z': /* SELinux security context */
1227 {
1228 char *scontext;
1229 int rv = (*options.x_getfilecon) (state.cwd_dir_fd, state.rel_pathname,
1230 &scontext);
1231 if (rv < 0)
1232 {
1233 /* If getfilecon fails, there will in the general case
1234 still be some text to print. We just make %Z expand
1235 to an empty string. */
1236 checked_fprintf (dest, segment->text, "");
1237
1238 error (0, errno, _("getfilecon failed: %s"),
1239 safely_quote_err_filename (0, pathname));
1240 state.exit_status = EXIT_FAILURE;
1241 }
1242 else
1243 {
1244 checked_fprintf (dest, segment->text, scontext);
1245 freecon (scontext);
1246 }
1247 }
1248 break;
1249
1250 case '%':
1251 checked_fwrite (segment->text, 1, segment->text_len, dest);
1252 break;
1253
1254 case 0:
1255 /* Trailing single %. This should have been rejected by
1256 insert_fprintf. We use %s here in the error message
1257 simply to ensure that the error message matches the one
1258 in insert_fprintf, easing the translation burden.
1259 */
1260 die (EXIT_FAILURE, 0, _("error: %s at end of format string"), "%");
1261 /*NOTREACHED*/
1262 break;
1263 }
1264 /* end of KIND_FORMAT case */
1265 break;
1266 }
1267 }
1268
1269 bool
1270 pred_fprintf (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1271 {
1272 struct format_val *dest = &pred_ptr->args.printf_vec;
1273 struct segment *segment;
1274
1275 for (segment = dest->segment; segment; segment = segment->next)
1276 {
1277 if ( (KIND_FORMAT == segment->segkind) && segment->format_char[1]) /* Component of date. */
1278 {
1279 struct timespec ts;
1280 int valid = 0;
1281
1282 switch (segment->format_char[0])
1283 {
1284 case 'A':
1285 ts = get_stat_atime (stat_buf);
1286 valid = 1;
1287 break;
1288 case 'B':
1289 ts = get_stat_birthtime (stat_buf);
1290 if ('@' == segment->format_char[1])
1291 valid = 1;
1292 else
1293 valid = (ts.tv_nsec >= 0);
1294 break;
1295 case 'C':
1296 ts = get_stat_ctime (stat_buf);
1297 valid = 1;
1298 break;
1299 case 'T':
1300 ts = get_stat_mtime (stat_buf);
1301 valid = 1;
1302 break;
1303 default:
1304 assert (0);
1305 abort ();
1306 }
1307 /* We trust the output of format_date not to contain
1308 * nasty characters, though the value of the date
1309 * is itself untrusted data.
1310 */
1311 if (valid)
1312 {
1313 /* trusted */
1314 checked_fprintf (dest, segment->text,
1315 format_date (ts, segment->format_char[1]));
1316 }
1317 else
1318 {
1319 /* The specified timestamp is not available, output
1320 * nothing for the timestamp, but use the rest (so that
1321 * for example find foo -printf '[%Bs] %p\n' can print
1322 * "[] foo").
1323 */
1324 /* trusted */
1325 checked_fprintf (dest, segment->text, "");
1326 }
1327 }
1328 else
1329 {
1330 /* Print a segment which is not a date. */
1331 do_fprintf (dest, segment, pathname, stat_buf);
1332 }
1333 }
1334 return true;
1335 }