tls.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. * Trivial ls for comparing two directories after running an rsync.
  3. *
  4. * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
  5. * Copyright (C) 2003-2009 Wayne Davison
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along
  18. * with this program; if not, write to the Free Software Foundation, Inc.,
  19. * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
  20. */
  21. /* The problem with using the system's own ls is that some features
  22. * have little quirks that make directories look different when for
  23. * our purposes they're the same -- for example, the BSD braindamage
  24. * about setting the mode on symlinks based on your current umask.
  25. *
  26. * All the filenames must be given on the command line -- tls does not
  27. * even read directories, let alone recurse. The typical usage is
  28. * "find|sort|xargs tls".
  29. *
  30. * The format is not exactly the same as any particular Unix ls(1).
  31. *
  32. * A key requirement for this program is that the output be "very
  33. * reproducible." So we mask away information that can accidentally
  34. * change. */
  35. #include "rsync.h"
  36. #include <popt.h>
  37. #include "lib/sysxattrs.h"
  38. #define PROGRAM "tls"
  39. /* These are to make syscall.o shut up. */
  40. int dry_run = 0;
  41. int am_root = 0;
  42. int read_only = 1;
  43. int list_only = 0;
  44. int link_times = 0;
  45. int link_owner = 0;
  46. int preserve_perms = 0;
  47. int preserve_executability = 0;
  48. #ifdef SUPPORT_XATTRS
  49. #ifdef HAVE_LINUX_XATTRS
  50. #define XSTAT_ATTR "user.rsync.%stat"
  51. #else
  52. #define XSTAT_ATTR "rsync.%stat"
  53. #endif
  54. static int stat_xattr(const char *fname, STRUCT_STAT *fst)
  55. {
  56. int mode, rdev_major, rdev_minor, uid, gid, len;
  57. char buf[256];
  58. if (am_root >= 0 || IS_DEVICE(fst->st_mode) || IS_SPECIAL(fst->st_mode))
  59. return -1;
  60. len = sys_lgetxattr(fname, XSTAT_ATTR, buf, sizeof buf - 1);
  61. if (len >= (int)sizeof buf) {
  62. len = -1;
  63. errno = ERANGE;
  64. }
  65. if (len < 0) {
  66. if (errno == ENOTSUP || errno == ENOATTR)
  67. return -1;
  68. if (errno == EPERM && S_ISLNK(fst->st_mode)) {
  69. fst->st_uid = 0;
  70. fst->st_gid = 0;
  71. return 0;
  72. }
  73. fprintf(stderr, "failed to read xattr %s for %s: %s\n",
  74. XSTAT_ATTR, fname, strerror(errno));
  75. return -1;
  76. }
  77. buf[len] = '\0';
  78. if (sscanf(buf, "%o %d,%d %d:%d",
  79. &mode, &rdev_major, &rdev_minor, &uid, &gid) != 5) {
  80. fprintf(stderr, "Corrupt %s xattr attached to %s: \"%s\"\n",
  81. XSTAT_ATTR, fname, buf);
  82. exit(1);
  83. }
  84. #if _S_IFLNK != 0120000
  85. if ((mode & (_S_IFMT)) == 0120000)
  86. mode = (mode & ~(_S_IFMT)) | _S_IFLNK;
  87. #endif
  88. fst->st_mode = mode;
  89. fst->st_rdev = MAKEDEV(rdev_major, rdev_minor);
  90. fst->st_uid = uid;
  91. fst->st_gid = gid;
  92. return 0;
  93. }
  94. #endif
  95. static void failed(char const *what, char const *where)
  96. {
  97. fprintf(stderr, PROGRAM ": %s %s: %s\n",
  98. what, where, strerror(errno));
  99. exit(1);
  100. }
  101. static void list_file(const char *fname)
  102. {
  103. STRUCT_STAT buf;
  104. char permbuf[PERMSTRING_SIZE];
  105. struct tm *mt;
  106. char datebuf[50];
  107. char linkbuf[4096];
  108. if (do_lstat(fname, &buf) < 0)
  109. failed("stat", fname);
  110. #ifdef SUPPORT_XATTRS
  111. if (am_root < 0)
  112. stat_xattr(fname, &buf);
  113. #endif
  114. /* The size of anything but a regular file is probably not
  115. * worth thinking about. */
  116. if (!S_ISREG(buf.st_mode))
  117. buf.st_size = 0;
  118. /* On some BSD platforms the mode bits of a symlink are
  119. * undefined. Also it tends not to be possible to reset a
  120. * symlink's mtime, so we default to ignoring it too. */
  121. if (S_ISLNK(buf.st_mode)) {
  122. int len;
  123. buf.st_mode &= ~0777;
  124. if (!link_times)
  125. buf.st_mtime = (time_t)0;
  126. if (!link_owner)
  127. buf.st_uid = buf.st_gid = 0;
  128. strlcpy(linkbuf, " -> ", sizeof linkbuf);
  129. /* const-cast required for silly UNICOS headers */
  130. len = readlink((char *) fname, linkbuf+4, sizeof(linkbuf) - 4);
  131. if (len == -1)
  132. failed("readlink", fname);
  133. else
  134. /* it's not nul-terminated */
  135. linkbuf[4+len] = 0;
  136. } else {
  137. linkbuf[0] = 0;
  138. }
  139. permstring(permbuf, buf.st_mode);
  140. if (buf.st_mtime) {
  141. mt = gmtime(&buf.st_mtime);
  142. snprintf(datebuf, sizeof datebuf,
  143. "%04d-%02d-%02d %02d:%02d:%02d",
  144. (int)mt->tm_year + 1900,
  145. (int)mt->tm_mon + 1,
  146. (int)mt->tm_mday,
  147. (int)mt->tm_hour,
  148. (int)mt->tm_min,
  149. (int)mt->tm_sec);
  150. } else
  151. strlcpy(datebuf, " ", sizeof datebuf);
  152. /* TODO: Perhaps escape special characters in fname? */
  153. printf("%s ", permbuf);
  154. if (S_ISCHR(buf.st_mode) || S_ISBLK(buf.st_mode)) {
  155. printf("%5ld,%6ld",
  156. (long)major(buf.st_rdev),
  157. (long)minor(buf.st_rdev));
  158. } else /* NB: use double for size since it might not fit in a long. */
  159. printf("%12.0f", (double)buf.st_size);
  160. printf(" %6ld.%-6ld %6ld %s %s%s\n",
  161. (long)buf.st_uid, (long)buf.st_gid, (long)buf.st_nlink,
  162. datebuf, fname, linkbuf);
  163. }
  164. static struct poptOption long_options[] = {
  165. /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
  166. {"link-times", 'l', POPT_ARG_NONE, &link_times, 0, 0, 0 },
  167. {"link-owner", 'L', POPT_ARG_NONE, &link_owner, 0, 0, 0 },
  168. #ifdef SUPPORT_XATTRS
  169. {"fake-super", 'f', POPT_ARG_VAL, &am_root, -1, 0, 0 },
  170. #endif
  171. {"help", 'h', POPT_ARG_NONE, 0, 'h', 0, 0 },
  172. {0,0,0,0,0,0,0}
  173. };
  174. static void tls_usage(int ret)
  175. {
  176. FILE *F = ret ? stderr : stdout;
  177. fprintf(F,"usage: " PROGRAM " [OPTIONS] FILE ...\n");
  178. fprintf(F,"Trivial file listing program for portably checking rsync\n");
  179. fprintf(F,"\nOptions:\n");
  180. fprintf(F," -l, --link-times display the time on a symlink\n");
  181. fprintf(F," -L, --link-owner display the owner+group on a symlink\n");
  182. #ifdef SUPPORT_XATTRS
  183. fprintf(F," -f, --fake-super display attributes including fake-super xattrs\n");
  184. #endif
  185. fprintf(F," -h, --help show this help\n");
  186. exit(ret);
  187. }
  188. int
  189. main(int argc, char *argv[])
  190. {
  191. poptContext pc;
  192. const char **extra_args;
  193. int opt;
  194. pc = poptGetContext(PROGRAM, argc, (const char **)argv,
  195. long_options, 0);
  196. while ((opt = poptGetNextOpt(pc)) != -1) {
  197. switch (opt) {
  198. case 'h':
  199. tls_usage(0);
  200. default:
  201. fprintf(stderr,
  202. "%s: %s\n",
  203. poptBadOption(pc, POPT_BADOPTION_NOALIAS),
  204. poptStrerror(opt));
  205. tls_usage(1);
  206. }
  207. }
  208. extra_args = poptGetArgs(pc);
  209. if (!extra_args || *extra_args == NULL)
  210. tls_usage(1);
  211. for (; *extra_args; extra_args++)
  212. list_file(*extra_args);
  213. poptFreeContext(pc);
  214. return 0;
  215. }