1 /* print.c -- print/printf-related code.
2 Copyright (C) 1990, 1991, 1992, 1993, 1994, 2000, 2001, 2003, 2004,
3 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation,
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 /* We always include config.h first. */
23 /* system headers go here. */
33 #include <sys/types.h>
36 #include "areadlink.h"
42 #include "printquoted.h"
43 #include "stat-size.h"
44 #include "stat-time.h"
48 /* find-specific headers. */
54 # define _(Text) gettext (Text)
59 # define N_(String) gettext_noop (String)
61 /* See locate.c for explanation as to why not use (String) */
62 # define N_(String) String
65 #if defined STDC_HEADERS
66 # define ISDIGIT(c) isdigit ((unsigned char)c)
68 # define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
71 #define MAX(a, b) ((a) > (b) ? (a) : (b))
74 /* Create a new fprintf segment in *SEGMENT, with type KIND,
75 from the text in FORMAT, which has length LEN.
76 Return the address of the `next' pointer of the new segment. */
78 make_segment (struct segment **segment,
84 struct predicate *pred)
86 enum EvaluationCost mycost = NeedsNothing;
89 assert (format_char != '{');
90 assert (format_char != '[');
91 assert (format_char != '(');
93 *segment = xmalloc (sizeof (struct segment));
95 (*segment)->segkind = kind;
96 (*segment)->format_char[0] = format_char;
97 (*segment)->format_char[1] = aux_format_char;
98 (*segment)->next = NULL;
99 (*segment)->text_len = len;
101 fmt = (*segment)->text = xmalloc (len + sizeof "d");
102 strncpy (fmt, format, len);
105 if (kind == KIND_PLAIN /* Plain text string, no % conversion. */
106 || kind == KIND_STOP) /* Terminate argument, no newline. */
108 assert (0 == format_char);
109 assert (0 == aux_format_char);
111 if (mycost > pred->p_cost)
112 pred->p_cost = NeedsNothing;
113 return &(*segment)->next;
116 assert (kind == KIND_FORMAT);
119 case '%': /* literal % */
123 case 'l': /* object of symlink */
124 pred->need_stat = true;
125 mycost = NeedsLinkName;
129 case 'y': /* file type */
130 pred->need_type = true;
135 case 'i': /* inode number */
136 pred->need_inum = true;
137 mycost = NeedsInodeNumber;
141 case 'a': /* atime in `ctime' format */
142 case 'A': /* atime in user-specified strftime format */
143 case 'B': /* birth time in user-specified strftime format */
144 case 'c': /* ctime in `ctime' format */
145 case 'C': /* ctime in user-specified strftime format */
146 case 'F': /* file system type */
147 case 'g': /* group name */
148 case 'M': /* mode in `ls -l' format (eg., "drwxr-xr-x") */
149 case 's': /* size in bytes */
150 case 't': /* mtime in `ctime' format */
151 case 'T': /* mtime in user-specified strftime format */
152 case 'u': /* user name */
153 pred->need_stat = true;
154 mycost = NeedsStatInfo;
158 case 'S': /* sparseness */
159 pred->need_stat = true;
160 mycost = NeedsStatInfo;
164 case 'Y': /* symlink pointed file type */
165 pred->need_stat = true;
166 mycost = NeedsType; /* true for amortised effect */
170 case 'f': /* basename of path */
171 case 'h': /* leading directories part of path */
172 case 'p': /* pathname */
173 case 'P': /* pathname with ARGV element stripped */
177 case 'Z': /* SELinux security context */
178 mycost = NeedsAccessInfo;
182 case 'H': /* ARGV element file was found under */
186 /* Numeric items that one might expect to honour
187 * #, 0, + flags but which do not.
189 case 'G': /* GID number */
190 case 'U': /* UID number */
191 case 'b': /* size in 512-byte blocks (NOT birthtime in ctime fmt)*/
192 case 'D': /* Filesystem device on which the file exits */
193 case 'k': /* size in 1K blocks */
194 case 'n': /* number of links */
195 pred->need_stat = true;
196 mycost = NeedsStatInfo;
200 /* Numeric items that DO honour #, 0, + flags.
202 case 'd': /* depth in search tree (0 = ARGV element) */
206 case 'm': /* mode as octal number (perms only) */
208 pred->need_stat = true;
209 mycost = NeedsStatInfo;
214 if (mycost > pred->p_cost)
215 pred->p_cost = mycost;
216 return &(*segment)->next;
220 is_octal_char (char ch)
222 return ch >= '0' && ch <= '7';
226 parse_octal_escape(const char *p, size_t *consumed)
231 for (i = n = 0; i < 3 && is_octal_char(p[pos]); i++, pos++)
233 n = 8 * n + p[pos] - '0';
241 parse_escape_char(const char ch)
276 get_format_flags_length(const char *p)
279 /* Scan past flags, width and precision, to verify kind. */
280 for (; p[++n] && strchr ("-+ #", p[n]);)
284 while (ISDIGIT (p[n]))
287 for (n++; ISDIGIT (p[n]); n++)
293 get_format_specifer_length(char ch)
295 if (strchr ("abcdDfFgGhHiklmMnpPsStuUyYZ%", ch))
299 else if (strchr ("ABCT", ch))
311 insert_fprintf (struct format_val *vec,
312 const struct parser_table *entry,
315 char *segstart = format;
316 char *fmt_editpos; /* Current address in scanning `format'. */
317 struct segment **segmentp; /* Address of current segment. */
318 struct predicate *our_pred;
320 our_pred = insert_primary_withpred (entry, pred_fprintf, format);
321 our_pred->side_effects = our_pred->no_default_print = true;
322 our_pred->args.printf_vec = *vec;
323 our_pred->need_type = false;
324 our_pred->need_stat = false;
325 our_pred->p_cost = NeedsNothing;
327 segmentp = &our_pred->args.printf_vec.segment;
330 for (fmt_editpos = segstart; *fmt_editpos; fmt_editpos++)
332 if (fmt_editpos[0] == '\\' && fmt_editpos[1] == 'c')
334 make_segment (segmentp, segstart, fmt_editpos - segstart,
337 if (our_pred->need_stat && (our_pred->p_cost < NeedsStatInfo))
338 our_pred->p_cost = NeedsStatInfo;
341 else if (*fmt_editpos == '\\')
344 if (!fmt_editpos[readpos])
346 error (0, 0, _("warning: escape `\\' followed by nothing at all"));
348 /* (*fmt_editpos) is already '\\' and that's a reasonable result. */
350 else if (is_octal_char(fmt_editpos[readpos]))
353 *fmt_editpos = parse_octal_escape(fmt_editpos + readpos, &consumed);
358 const char val = parse_escape_char(fmt_editpos[readpos]);
361 fmt_editpos[0] = val;
365 error (0, 0, _("warning: unrecognized escape `\\%c'"),
366 fmt_editpos[readpos]);
367 fmt_editpos += readpos;
371 segmentp = make_segment (segmentp,
372 segstart, fmt_editpos - segstart + 1,
375 segstart = fmt_editpos + readpos + 1; /* Move past the escape. */
376 fmt_editpos += readpos; /* Incremented immediately by `for'. */
378 else if (fmt_editpos[0] == '%')
381 if (fmt_editpos[1] == 0)
383 /* Trailing %. We don't like those. */
384 error (EXIT_FAILURE, 0,
385 _("error: %s at end of format string"), fmt_editpos);
388 if (fmt_editpos[1] == '%') /* %% produces just %. */
391 len = get_format_flags_length(fmt_editpos);
394 len = get_format_specifer_length (fmt_editpos[0]);
395 if (len && (fmt_editpos[len-1]))
397 const char fmt2 = (len == 2) ? fmt_editpos[1] : 0;
398 segmentp = make_segment (segmentp, segstart,
399 fmt_editpos - segstart,
400 KIND_FORMAT, fmt_editpos[0], fmt2,
402 fmt_editpos += (len - 1);
406 if (strchr ("{[(", fmt_editpos[0]))
408 error (EXIT_FAILURE, 0,
409 _("error: the format directive `%%%c' is reserved for future use"),
410 (int)fmt_editpos[0]);
414 if (len == 2 && !fmt_editpos[1])
417 _("warning: format directive `%%%c' "
418 "should be followed by another character"),
423 /* An unrecognized % escape. Print the char after the %. */
425 _("warning: unrecognized format directive `%%%c'"),
428 segmentp = make_segment (segmentp,
429 segstart, fmt_editpos + 1 - segstart,
433 segstart = fmt_editpos + 1;
437 if (fmt_editpos > segstart)
438 make_segment (segmentp, segstart, fmt_editpos - segstart, KIND_PLAIN, 0, 0,
444 scan_for_digit_differences (const char *p, const char *q,
445 size_t *first, size_t *n)
450 for (i=0; p[i] && q[i]; i++)
454 if (!isdigit ((unsigned char)q[i]) || !isdigit ((unsigned char)q[i]))
467 /* Still in the first sequence of differing digits. */
472 /* More than one differing contiguous character sequence. */
480 /* strings are different lengths. */
487 do_time_format (const char *fmt, const struct tm *p, const char *ns, size_t ns_size)
489 static char *buf = NULL;
490 static size_t buf_size;
491 char *timefmt = NULL;
492 struct tm altered_time;
495 /* If the format expands to nothing (%p in some locales, for
496 * example), strftime can return 0. We actually want to distinguish
497 * the error case where the buffer is too short, so we just prepend
498 * an otherwise uninteresting character to prevent the no-output
501 timefmt = xmalloc (strlen (fmt) + 2u);
503 memcpy (timefmt + 1, fmt, strlen (fmt) + 1);
505 /* altered_time is a similar time, but in which both
506 * digits of the seconds field are different.
509 if (altered_time.tm_sec >= 11)
510 altered_time.tm_sec -= 11;
512 altered_time.tm_sec += 11;
514 /* If we call strftime() with buf_size=0, the program will coredump
515 * on Solaris, since it unconditionally writes the terminating null
521 buf = xmalloc (buf_size);
525 /* I'm not sure that Solaris will return 0 when the buffer is too small.
526 * Therefore we do not check for (buf_used != 0) as the termination
529 size_t buf_used = strftime (buf, buf_size, timefmt, p);
530 if (buf_used /* Conforming POSIX system */
531 && (buf_used < buf_size)) /* Solaris workaround */
535 size_t final_len = (buf_used
538 buf = xrealloc (buf, final_len);
539 buf_size = final_len;
540 altbuf = xmalloc (final_len);
541 strftime (altbuf, buf_size, timefmt, &altered_time);
543 /* Find the seconds digits; they should be the only changed part.
544 * In theory the result of the two formatting operations could differ in
545 * more than just one sequence of decimal digits (for example %X might
546 * in theory return a spelled-out time like "thirty seconds past noon").
547 * When that happens, we just avoid inserting the nanoseconds field.
549 if (scan_for_digit_differences (buf, altbuf, &i, &n)
550 && (2==n) && !isdigit ((unsigned char)buf[i+n]))
552 const size_t end_of_seconds = i + n;
553 const size_t suffix_len = buf_used-(end_of_seconds)+1;
555 /* Move the tail (including the \0). Note that this
556 * is a move of an overlapping memory block, so we
557 * must use memmove instead of memcpy. Then insert
558 * the nanoseconds (but not its trailing \0).
560 assert (end_of_seconds + ns_size + suffix_len == final_len);
561 memmove (buf+end_of_seconds+ns_size,
564 memcpy (buf+i+n, ns, ns_size);
568 /* No seconds digits. No need to insert anything. */
570 /* The first character of buf is the underscore, which we actually
579 buf = x2nrealloc (buf, &buf_size, sizeof *buf);
584 /* Return a static string formatting the time WHEN according to the
585 * strftime format character KIND.
587 * This function contains a number of assertions. These look like
588 * runtime checks of the results of computations, which would be a
589 * problem since external events should not be tested for with
590 * "assert" (instead you should use "if"). However, they are not
591 * really runtime checks. The assertions actually exist to verify
592 * that the various buffers are correctly sized.
595 format_date (struct timespec ts, int kind)
597 /* In theory, we use an extra 10 characters for 9 digits of
598 * nanoseconds and 1 for the decimal point. However, the real
599 * world is more complex than that.
601 * For example, some systems return junk in the tv_nsec part of
602 * st_birthtime. An example of this is the NetBSD-4.0-RELENG kernel
603 * (at Sat Mar 24 18:46:46 2007) running a NetBSD-3.1-RELEASE
604 * runtime and examining files on an msdos filesytem. So for that
605 * reason we set NS_BUF_LEN to 32, which is simply "long enough" as
606 * opposed to "exactly the right size". Note that the behaviour of
607 * NetBSD appears to be a result of the use of uninitialized data,
608 * as it's not 100% reproducible (more like 25%).
612 DATE_LEN_PERCENT_APLUS=21 /* length of result of %A+ (it's longer than %c)*/
614 static char buf[128u+10u + MAX(DATE_LEN_PERCENT_APLUS,
615 MAX (LONGEST_HUMAN_READABLE + 2, NS_BUF_LEN+64+200))];
616 char ns_buf[NS_BUF_LEN]; /* -.9999999990 (- sign can happen!)*/
617 int charsprinted, need_ns_suffix;
621 /* human_readable() assumes we pass a buffer which is at least as
622 * long as LONGEST_HUMAN_READABLE. We use an assertion here to
623 * ensure that no nasty unsigned overflow happened in our calculation
624 * of the size of buf. Do the assertion here rather than in the
625 * code for %@ so that we find the problem quickly if it exists. If
626 * you want to submit a patch to move this into the if statement, go
627 * ahead, I'll apply it. But include performance timings
628 * demonstrating that the performance difference is actually
631 verify (sizeof (buf) >= LONGEST_HUMAN_READABLE);
636 /* Format the main part of the time. */
639 strcpy (fmt, "%F+%T");
648 /* %a, %c, and %t are handled in ctime_format() */
665 /* Format the nanoseconds part. Leave a trailing zero to
666 * discourage people from writing scripts which extract the
667 * fractional part of the timestamp by using column offsets.
668 * The reason for discouraging this is that in the future, the
669 * granularity may not be nanoseconds.
671 charsprinted = snprintf (ns_buf, NS_BUF_LEN, ".%09ld0", (long int)ts.tv_nsec);
672 assert (charsprinted < NS_BUF_LEN);
682 tm = localtime (&ts.tv_sec);
685 char *s = do_time_format (fmt, tm, ns_buf, charsprinted);
691 /* If we get to here, either the format was %@, or we have fallen back to it
692 * because strftime failed.
696 uintmax_t w = ts.tv_sec;
697 size_t used, len, remaining;
699 /* XXX: note that we are negating an unsigned type which is the
700 * widest possible unsigned type.
702 char *p = human_readable (ts.tv_sec < 0 ? -w : w, buf + 1,
703 human_ceiling, 1, 1);
705 assert (p < (buf + (sizeof buf)));
707 *--p = '-'; /* XXX: Ugh, relying on internal details of human_readable(). */
709 /* Add the nanoseconds part. Because we cannot enforce a
710 * particlar implementation of human_readable, we cannot assume
711 * any particular value for (p-buf). So we need to be careful
712 * that there is enough space remaining in the buffer.
717 used = (p-buf) + len; /* Offset into buf of current end */
718 assert (sizeof buf > used); /* Ensure we can perform subtraction safely. */
719 remaining = sizeof buf - used - 1u; /* allow space for NUL */
721 if (strlen (ns_buf) >= remaining)
724 "charsprinted=%ld but remaining=%lu: ns_buf=%s",
725 (long)charsprinted, (unsigned long)remaining, ns_buf);
727 assert (strlen (ns_buf) < remaining);
734 static const char *weekdays[] =
736 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
738 static const char * months[] =
740 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
741 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
746 ctime_format (struct timespec ts)
748 const struct tm * ptm;
749 #define TIME_BUF_LEN 1024
750 static char resultbuf[TIME_BUF_LEN];
753 ptm = localtime (&ts.tv_sec);
756 assert (ptm->tm_wday >= 0);
757 assert (ptm->tm_wday < 7);
758 assert (ptm->tm_mon >= 0);
759 assert (ptm->tm_mon < 12);
760 assert (ptm->tm_hour >= 0);
761 assert (ptm->tm_hour < 24);
762 assert (ptm->tm_min < 60);
763 assert (ptm->tm_sec <= 61); /* allows 2 leap seconds. */
765 /* wkday mon mday hh:mm:ss.nnnnnnnnn yyyy */
766 nout = snprintf (resultbuf, TIME_BUF_LEN,
767 "%3s %3s %2d %02d:%02d:%02d.%010ld %04d",
768 weekdays[ptm->tm_wday],
774 (long int)ts.tv_nsec,
775 1900 + ptm->tm_year);
777 assert (nout < TIME_BUF_LEN);
782 /* The time cannot be represented as a struct tm.
783 Output it as an integer. */
784 return format_date (ts, '@');
789 file_sparseness (const struct stat *p)
793 if (0 == ST_NBLOCKS(*p))
796 return ST_NBLOCKS(*p) < 0 ? -HUGE_VAL : HUGE_VAL;
800 double blklen = ST_NBLOCKSIZE * (double)ST_NBLOCKS(*p);
801 return blklen / p->st_size;
806 checked_fprintf (struct format_val *dest, const char *fmt, ...)
812 rv = vfprintf (dest->stream, fmt, ap);
814 nonfatal_nontarget_file_error (errno, dest->filename);
818 checked_print_quoted (struct format_val *dest,
819 const char *format, const char *s)
821 int rv = print_quoted (dest->stream, dest->quote_opts, dest->dest_is_tty,
824 nonfatal_nontarget_file_error (errno, dest->filename);
829 checked_fwrite (void *p, size_t siz, size_t nmemb, struct format_val *dest)
831 const size_t items_written = fwrite (p, siz, nmemb, dest->stream);
832 if (items_written < nmemb)
833 nonfatal_nontarget_file_error (errno, dest->filename);
837 checked_fflush (struct format_val *dest)
839 if (0 != fflush (dest->stream))
841 nonfatal_nontarget_file_error (errno, dest->filename);
846 mode_to_filetype (mode_t m)
848 #define HANDLE_TYPE(t,letter) if (m==t) { return letter; }
850 HANDLE_TYPE(S_IFREG, "f"); /* regular file */
853 HANDLE_TYPE(S_IFDIR, "d"); /* directory */
856 HANDLE_TYPE(S_IFLNK, "l"); /* symbolic link */
859 HANDLE_TYPE(S_IFSOCK, "s"); /* Unix domain socket */
862 HANDLE_TYPE(S_IFBLK, "b"); /* block device */
865 HANDLE_TYPE(S_IFCHR, "c"); /* character device */
868 HANDLE_TYPE(S_IFIFO, "p"); /* FIFO */
871 HANDLE_TYPE(S_IFDOOR, "D"); /* Door (e.g. on Solaris) */
873 return "U"; /* Unknown */
879 do_fprintf (struct format_val *dest,
880 struct segment *segment,
881 const char *pathname,
882 const struct stat *stat_buf)
884 char hbuf[LONGEST_HUMAN_READABLE + 1];
887 switch (segment->segkind)
889 case KIND_PLAIN: /* Plain text string (no % conversion). */
891 checked_fwrite(segment->text, 1, segment->text_len, dest);
894 case KIND_STOP: /* Terminate argument and flush output. */
896 checked_fwrite (segment->text, 1, segment->text_len, dest);
897 checked_fflush (dest);
901 switch (segment->format_char[0])
903 case 'a': /* atime in `ctime' format. */
904 /* UNTRUSTED, probably unexploitable */
905 checked_fprintf (dest, segment->text, ctime_format (get_stat_atime (stat_buf)));
907 case 'b': /* size in 512-byte blocks */
908 /* UNTRUSTED, probably unexploitable */
909 checked_fprintf (dest, segment->text,
910 human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
912 ST_NBLOCKSIZE, 512));
914 case 'c': /* ctime in `ctime' format */
915 /* UNTRUSTED, probably unexploitable */
916 checked_fprintf (dest, segment->text, ctime_format (get_stat_ctime (stat_buf)));
918 case 'd': /* depth in search tree */
919 /* UNTRUSTED, probably unexploitable */
920 checked_fprintf (dest, segment->text, state.curdepth);
922 case 'D': /* Device on which file exists (stat.st_dev) */
924 checked_fprintf (dest, segment->text,
925 human_readable ((uintmax_t) stat_buf->st_dev, hbuf,
926 human_ceiling, 1, 1));
928 case 'f': /* base name of path */
931 char *base = base_name (pathname);
932 checked_print_quoted (dest, segment->text, base);
936 case 'F': /* file system type */
938 checked_print_quoted (dest, segment->text, filesystem_type (stat_buf, pathname));
940 case 'g': /* group name */
942 /* (well, the actual group is selected by the user but
943 * its name was selected by the system administrator)
948 g = getgrgid (stat_buf->st_gid);
951 segment->text[segment->text_len] = 's';
952 checked_fprintf (dest, segment->text, g->gr_name);
961 /*FALLTHROUGH*/ /*...sometimes, so 'G' case.*/
963 case 'G': /* GID number */
964 /* UNTRUSTED, probably unexploitable */
965 checked_fprintf (dest, segment->text,
966 human_readable ((uintmax_t) stat_buf->st_gid, hbuf,
967 human_ceiling, 1, 1));
969 case 'h': /* leading directories part of path */
972 cp = strrchr (pathname, '/');
973 if (cp == NULL) /* No leading directories. */
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 ".".
979 checked_print_quoted (dest, segment->text, ".");
983 char *s = strdup (pathname);
984 s[cp - pathname] = 0;
985 checked_print_quoted (dest, segment->text, s);
991 case 'H': /* ARGV element file was found under */
994 char *s = xmalloc (state.starting_path_length+1);
995 memcpy (s, pathname, state.starting_path_length);
996 s[state.starting_path_length] = 0;
997 checked_fprintf (dest, segment->text, s);
1002 case 'i': /* inode number */
1003 /* UNTRUSTED, but not exploitable I think */
1004 checked_fprintf (dest, segment->text,
1005 human_readable ((uintmax_t) stat_buf->st_ino, hbuf,
1009 case 'k': /* size in 1K blocks */
1010 /* UNTRUSTED, but not exploitable I think */
1011 checked_fprintf (dest, segment->text,
1012 human_readable ((uintmax_t) ST_NBLOCKS (*stat_buf),
1013 hbuf, human_ceiling,
1014 ST_NBLOCKSIZE, 1024));
1016 case 'l': /* object of symlink */
1022 if (S_ISLNK (stat_buf->st_mode))
1024 linkname = areadlinkat (state.cwd_dir_fd, state.rel_pathname);
1025 if (linkname == NULL)
1027 nonfatal_target_file_error (errno, pathname);
1028 state.exit_status = 1;
1033 checked_print_quoted (dest, segment->text, linkname);
1037 /* We still need to honour the field width etc., so this is
1040 checked_print_quoted (dest, segment->text, "");
1044 #endif /* S_ISLNK */
1047 case 'M': /* mode as 10 chars (eg., "-rwxr-x--x" */
1048 /* UNTRUSTED, probably unexploitable */
1050 char modestring[16] ;
1051 filemodestring (stat_buf, modestring);
1052 modestring[10] = '\0';
1053 checked_fprintf (dest, segment->text, modestring);
1057 case 'm': /* mode as octal number (perms only) */
1058 /* UNTRUSTED, probably unexploitable */
1060 /* Output the mode portably using the traditional numbers,
1061 even if the host unwisely uses some other numbering
1062 scheme. But help the compiler in the common case where
1063 the host uses the traditional numbering scheme. */
1064 mode_t m = stat_buf->st_mode;
1065 bool traditional_numbering_scheme =
1066 (S_ISUID == 04000 && S_ISGID == 02000 && S_ISVTX == 01000
1067 && S_IRUSR == 00400 && S_IWUSR == 00200 && S_IXUSR == 00100
1068 && S_IRGRP == 00040 && S_IWGRP == 00020 && S_IXGRP == 00010
1069 && S_IROTH == 00004 && S_IWOTH == 00002 && S_IXOTH == 00001);
1070 checked_fprintf (dest, segment->text,
1071 (traditional_numbering_scheme
1073 : ((m & S_ISUID ? 04000 : 0)
1074 | (m & S_ISGID ? 02000 : 0)
1075 | (m & S_ISVTX ? 01000 : 0)
1076 | (m & S_IRUSR ? 00400 : 0)
1077 | (m & S_IWUSR ? 00200 : 0)
1078 | (m & S_IXUSR ? 00100 : 0)
1079 | (m & S_IRGRP ? 00040 : 0)
1080 | (m & S_IWGRP ? 00020 : 0)
1081 | (m & S_IXGRP ? 00010 : 0)
1082 | (m & S_IROTH ? 00004 : 0)
1083 | (m & S_IWOTH ? 00002 : 0)
1084 | (m & S_IXOTH ? 00001 : 0))));
1088 case 'n': /* number of links */
1089 /* UNTRUSTED, probably unexploitable */
1090 checked_fprintf (dest, segment->text,
1091 human_readable ((uintmax_t) stat_buf->st_nlink,
1097 case 'p': /* pathname */
1099 checked_print_quoted (dest, segment->text, pathname);
1102 case 'P': /* pathname with ARGV element stripped */
1104 if (state.curdepth > 0)
1106 cp = pathname + state.starting_path_length;
1108 /* Move past the slash between the ARGV element
1109 and the rest of the pathname. But if the ARGV element
1110 ends in a slash, we didn't add another, so we've
1111 already skipped past it. */
1118 checked_print_quoted (dest, segment->text, cp);
1121 case 's': /* size in bytes */
1122 /* UNTRUSTED, probably unexploitable */
1123 checked_fprintf (dest, segment->text,
1124 human_readable ((uintmax_t) stat_buf->st_size,
1125 hbuf, human_ceiling, 1, 1));
1128 case 'S': /* sparseness */
1129 /* UNTRUSTED, probably unexploitable */
1130 checked_fprintf (dest, segment->text, file_sparseness (stat_buf));;
1133 case 't': /* mtime in `ctime' format */
1134 /* UNTRUSTED, probably unexploitable */
1135 checked_fprintf (dest, segment->text,
1136 ctime_format (get_stat_mtime (stat_buf)));
1139 case 'u': /* user name */
1141 /* (well, the actual user is selected by the user on systems
1142 * where chown is not restricted, but the user name was
1143 * selected by the system administrator)
1148 p = getpwuid (stat_buf->st_uid);
1151 segment->text[segment->text_len] = 's';
1152 checked_fprintf (dest, segment->text, p->pw_name);
1157 /* FALLTHROUGH*/ /* .. to case U */
1159 case 'U': /* UID number */
1160 /* UNTRUSTED, probably unexploitable */
1161 checked_fprintf (dest, segment->text,
1162 human_readable ((uintmax_t) stat_buf->st_uid, hbuf,
1163 human_ceiling, 1, 1));
1166 /* %Y: type of file system entry like `ls -l`:
1167 * (d,-,l,s,p,b,c,n) n=nonexistent (symlink)
1169 case 'Y': /* in case of symlink */
1173 if (S_ISLNK (stat_buf->st_mode))
1176 /* If we would normally follow links, do not do so.
1177 * If we would normally not follow links, do so.
1179 if ((following_links () ? optionp_stat : optionl_stat)
1180 (state.rel_pathname, &sbuf) != 0)
1182 if ( errno == ENOENT )
1184 checked_fprintf (dest, segment->text, "N");
1187 else if ( errno == ELOOP )
1189 checked_fprintf (dest, segment->text, "L");
1194 checked_fprintf (dest, segment->text, "?");
1195 error (0, errno, "%s",
1196 safely_quote_err_filename (0, pathname));
1202 checked_fprintf (dest, segment->text,
1203 mode_to_filetype (sbuf.st_mode & S_IFMT));
1205 #endif /* S_ISLNK */
1208 checked_fprintf (dest, segment->text,
1209 mode_to_filetype (stat_buf->st_mode & S_IFMT));
1217 checked_fprintf (dest, segment->text,
1218 mode_to_filetype (stat_buf->st_mode & S_IFMT));
1222 case 'Z': /* SELinux security context */
1224 security_context_t scontext;
1225 int rv = (*options.x_getfilecon) (state.cwd_dir_fd, state.rel_pathname,
1229 /* If getfilecon fails, there will in the general case
1230 still be some text to print. We just make %Z expand
1231 to an empty string. */
1232 checked_fprintf (dest, segment->text, "");
1234 error (0, errno, _("getfilecon failed: %s"),
1235 safely_quote_err_filename (0, pathname));
1236 state.exit_status = 1;
1240 checked_fprintf (dest, segment->text, scontext);
1248 checked_fprintf (dest, segment->text);
1251 /* end of KIND_FORMAT case */
1257 pred_fprintf (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
1259 struct format_val *dest = &pred_ptr->args.printf_vec;
1260 struct segment *segment;
1262 for (segment = dest->segment; segment; segment = segment->next)
1264 if ( (KIND_FORMAT == segment->segkind) && segment->format_char[1]) /* Component of date. */
1269 switch (segment->format_char[0])
1272 ts = get_stat_atime (stat_buf);
1276 ts = get_stat_birthtime (stat_buf);
1277 if ('@' == segment->format_char[1])
1280 valid = (ts.tv_nsec >= 0);
1283 ts = get_stat_ctime (stat_buf);
1287 ts = get_stat_mtime (stat_buf);
1294 /* We trust the output of format_date not to contain
1295 * nasty characters, though the value of the date
1296 * is itself untrusted data.
1301 checked_fprintf (dest, segment->text,
1302 format_date (ts, segment->format_char[1]));
1306 /* The specified timestamp is not available, output
1307 * nothing for the timestamp, but use the rest (so that
1308 * for example find foo -printf '[%Bs] %p\n' can print
1312 checked_fprintf (dest, segment->text, "");
1317 /* Print a segment which is not a date. */
1318 do_fprintf (dest, segment, pathname, stat_buf);