00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #ifndef lint
00035 static const char copyright[] =
00036 "@(#) Copyright (c) 1989, 1990, 1993\n\
00037 The Regents of the University of California. All rights reserved.\n";
00038 #endif
00039
00040 #include "system.h"
00041
00042 #include <fnmatch.h>
00043 #include <signal.h>
00044 #include <stdarg.h>
00045
00046 #if !defined(HAVE_ASPRINTF)
00047 #include "asprintf.h"
00048 #endif
00049
00050 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__APPLE__)
00051 #define HAVE_ST_FLAGS 1
00052 #else
00053 #undef HAVE_ST_FLAGS
00054 #endif
00055
00056 #if defined(__linux__)
00057 #define st_mtimespec st_mtim
00058 #endif
00059
00060 #if defined(__QNXNTO__)
00061 #define st_mtimespec st_mtime
00062 #endif
00063
00064 #include <rpmio_internal.h>
00065 #include <fts.h>
00066 #include <ugid.h>
00067 #include <poptIO.h>
00068
00069 #undef _RPMFI_INTERNAL
00070 #if defined(_RPMFI_INTERNAL)
00071 #define _RPMAV_INTERNAL
00072 #include <rpmdav.h>
00073 #include <rpmtag.h>
00074 #include <rpmfi.h>
00075
00076 #include <rpmlib.h>
00077 #include <rpmts.h>
00078 #endif
00079
00080 #define RPM_LIST_HEAD(name, type) \
00081 struct name { struct type *lh_first; }
00082 #define RPM_LIST_ENTRY(type) \
00083 struct { struct type *le_next;struct type **le_prev; }
00084 #define RPM_LIST_EMPTY(head) \
00085 ((head)->lh_first == NULL)
00086 #define RPM_LIST_FIRST(head) \
00087 ((head)->lh_first)
00088 #define RPM_LIST_NEXT(elm, field) \
00089 ((elm)->field.le_next)
00090 #define RPM_LIST_INIT(head) \
00091 do { RPM_LIST_FIRST((head)) = NULL; } while (0)
00092 #define RPM_LIST_INSERT_HEAD(head, elm, field) \
00093 do { if ((RPM_LIST_NEXT((elm), field) = RPM_LIST_FIRST((head))) != NULL) \
00094 RPM_LIST_FIRST((head))->field.le_prev = &RPM_LIST_NEXT((elm), field);\
00095 RPM_LIST_FIRST((head)) = (elm); \
00096 (elm)->field.le_prev = &RPM_LIST_FIRST((head)); } while (0)
00097 #define RPM_LIST_FOREACH(var, head, field) \
00098 for ((var) = RPM_LIST_FIRST((head)); (var); (var) = RPM_LIST_NEXT((var), field))
00099
00100 #define _MTREE_INTERNAL
00101
00102
00103 #define _KFB(n) (1U << (n))
00104 #define _MFB(n) (_KFB(n) | 0x40000000)
00105
00109 enum mtreeFlags_e {
00110 MTREE_FLAGS_NONE = 0,
00111 MTREE_FLAGS_QUIET = _MFB( 0),
00112 MTREE_FLAGS_WARN = _MFB( 1),
00113 MTREE_FLAGS_CREATE = _MFB( 2),
00114 MTREE_FLAGS_DIRSONLY = _MFB( 3),
00115 MTREE_FLAGS_IGNORE = _MFB( 4),
00116 MTREE_FLAGS_INDENT = _MFB( 5),
00117 MTREE_FLAGS_LOOSE = _MFB( 6),
00118 MTREE_FLAGS_NOCOMMENT = _MFB( 7),
00119 MTREE_FLAGS_REMOVE = _MFB( 8),
00120 MTREE_FLAGS_SEEDED = _MFB( 9),
00121 MTREE_FLAGS_TOUCH = _MFB(10),
00122 MTREE_FLAGS_UPDATE = _MFB(11),
00123 MTREE_FLAGS_MISMATCHOK = _MFB(12),
00124
00125 };
00126
00129 typedef struct rpmfts_s * rpmfts;
00130
00131 #if defined(_MTREE_INTERNAL)
00132
00135 enum mtreeKeys_e {
00136 MTREE_KEYS_NONE = 0,
00137 MTREE_KEYS_CKSUM = _KFB( 0),
00138 MTREE_KEYS_DONE = _KFB( 1),
00139 MTREE_KEYS_GID = _KFB( 2),
00140 MTREE_KEYS_GNAME = _KFB( 3),
00141 MTREE_KEYS_IGN = _KFB( 4),
00142 MTREE_KEYS_MAGIC = _KFB( 5),
00143 MTREE_KEYS_MODE = _KFB( 6),
00144 MTREE_KEYS_NLINK = _KFB( 7),
00145 MTREE_KEYS_SIZE = _KFB( 8),
00146 MTREE_KEYS_SLINK = _KFB( 9),
00147 MTREE_KEYS_TIME = _KFB(10),
00148 MTREE_KEYS_TYPE = _KFB(11),
00149 MTREE_KEYS_UID = _KFB(12),
00150 MTREE_KEYS_UNAME = _KFB(13),
00151 MTREE_KEYS_VISIT = _KFB(14),
00152 MTREE_KEYS_FLAGS = _KFB(15),
00153 MTREE_KEYS_NOCHANGE = _KFB(16),
00154 MTREE_KEYS_OPT = _KFB(17),
00155 MTREE_KEYS_DIGEST = _KFB(18),
00156
00157 };
00158
00159 typedef struct _node {
00160 struct _node *parent, *child;
00161 struct _node *prev, *next;
00162 struct stat sb;
00163 char *slink;
00164 ARGI_t algos;
00165 ARGV_t digests;
00167 uint32_t cksum;
00169 enum mtreeKeys_e flags;
00171 uint8_t type;
00172 #define F_BLOCK 0x001
00173 #define F_CHAR 0x002
00174 #define F_DIR 0x004
00175 #define F_FIFO 0x008
00176 #define F_FILE 0x010
00177 #define F_LINK 0x020
00178 #define F_SOCK 0x040
00180 char name[1];
00181 } NODE;
00182
00183 struct rpmfts_s {
00184 FTS * t;
00185 FTSENT * p;
00186 struct stat sb;
00187 int sb_is_valid;
00188 uint32_t crc_total;
00189 unsigned lineno;
00190
00191 NODE * root;
00192
00193 ARGV_t paths;
00194 enum mtreeKeys_e keys;
00195
00196 ARGI_t algos;
00197
00198
00199 FILE * spec1;
00200
00201 FILE * spec2;
00202
00203
00204 const char * fullpath;
00205
00206 char * path;
00207 int ftsoptions;
00208
00209 #if defined(HAVE_ST_FLAGS)
00210 size_t maxf;
00211
00212 unsigned long * f;
00213 #endif
00214 size_t maxg;
00215
00216 gid_t * g;
00217 size_t maxm;
00218
00219 mode_t * m;
00220 size_t maxu;
00221
00222 uid_t * u;
00223
00224 #if defined(_RPMFI_INTERNAL)
00225
00226 rpmts ts;
00227
00228 rpmfi fi;
00229 #endif
00230 };
00231 #endif
00232
00233 #undef _KFB
00234 #undef _MFB
00235
00236 #ifdef __cplusplus
00237 extern "C" {
00238 #endif
00239
00240
00241 static NODE * mtreeSpec(rpmfts fts, FILE * fp)
00242
00243 ;
00244
00245 static int mtreeVSpec(rpmfts fts)
00246
00247 ;
00248
00249 static int mtreeCWalk(rpmfts fts)
00250
00251 ;
00252
00253 static int mtreeVWalk(rpmfts fts)
00254
00255 ;
00256
00257 #ifdef __cplusplus
00258 }
00259 #endif
00260
00261
00262
00263 static void mtreeMiss(rpmfts fts, NODE * p, char * tail)
00264
00265 ;
00266
00267 #include "debug.h"
00268
00269
00270
00271
00272
00273
00274 #define MF_ISSET(_FLAG) ((mtreeFlags & ((MTREE_FLAGS_##_FLAG) & ~0x40000000)) != MTREE_FLAGS_NONE)
00275
00276 #define KEYDEFAULT \
00277 (MTREE_KEYS_GID | MTREE_KEYS_MODE | MTREE_KEYS_NLINK | MTREE_KEYS_SIZE | \
00278 MTREE_KEYS_SLINK | MTREE_KEYS_TIME | MTREE_KEYS_UID)
00279
00280 #define MISMATCHEXIT 2
00281
00282 #if !defined(S_ISTXT) && defined(S_ISVTX)
00283 #define S_ISTXT S_ISVTX
00284 #endif
00285 #define MBITS (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO)
00286
00287
00288 static struct rpmfts_s __rpmfts;
00289
00290 static rpmfts _rpmfts = &__rpmfts;
00291
00292
00293 static enum mtreeFlags_e mtreeFlags = MTREE_FLAGS_NONE;
00294
00295
00296 struct exclude {
00297 RPM_LIST_ENTRY(exclude) link;
00298 const char *glob;
00299 int pathname;
00300 };
00301
00302
00303 static RPM_LIST_HEAD(, exclude) excludes;
00304
00305
00306 static struct rpmop_s dc_totalops;
00307
00308
00309 static struct rpmop_s dc_readops;
00310
00311
00312 static struct rpmop_s dc_digestops;
00313
00314
00315
00316
00317 static void
00318 mtree_error(const char *fmt, ...)
00319 #ifdef __GNUC__
00320 __attribute__ ((format (printf, 1, 2)))
00321 #endif
00322
00323 ;
00324
00325 void
00326 mtree_error(const char *fmt, ...)
00327 {
00328 va_list ap;
00329
00330 va_start(ap, fmt);
00331 (void) fflush(NULL);
00332 (void) fprintf(stderr, "\n%s: ", __progname);
00333 (void) vfprintf(stderr, fmt, ap);
00334 va_end (ap);
00335 (void) fprintf(stderr, "\n");
00336 if (_rpmfts->lineno)
00337 (void)fprintf(stderr, _("%s: failed at line %d of the specification\n"),
00338 __progname, _rpmfts->lineno);
00339 exit(EXIT_FAILURE);
00340
00341 }
00342
00343 typedef struct _key {
00344
00345 const char *name;
00346 unsigned val;
00347 #define NEEDVALUE 0xffffffff
00348 uint32_t flags;
00349 } KEY;
00350
00351
00352
00353 static KEY keylist[] = {
00354 { "adler32", MTREE_KEYS_DIGEST, PGPHASHALGO_ADLER32 },
00355 { "cksum", MTREE_KEYS_CKSUM, NEEDVALUE },
00356 { "crc32", MTREE_KEYS_DIGEST, PGPHASHALGO_CRC32 },
00357 { "crc64", MTREE_KEYS_DIGEST, PGPHASHALGO_CRC64 },
00358 { "flags", MTREE_KEYS_FLAGS, NEEDVALUE },
00359 { "gid", MTREE_KEYS_GID, NEEDVALUE },
00360 { "gname", MTREE_KEYS_GNAME, NEEDVALUE },
00361 { "haval160digest", MTREE_KEYS_DIGEST, PGPHASHALGO_HAVAL_5_160 },
00362 { "ignore", MTREE_KEYS_IGN, 0 },
00363 { "jlu32", MTREE_KEYS_DIGEST, PGPHASHALGO_JLU32 },
00364 { "link", MTREE_KEYS_SLINK, NEEDVALUE },
00365 { "md2digest", MTREE_KEYS_DIGEST, PGPHASHALGO_MD2 },
00366 { "md4digest", MTREE_KEYS_DIGEST, PGPHASHALGO_MD4 },
00367 { "md5digest", MTREE_KEYS_DIGEST, PGPHASHALGO_MD5 },
00368 { "mode", MTREE_KEYS_MODE, NEEDVALUE },
00369 { "nlink", MTREE_KEYS_NLINK, NEEDVALUE },
00370 { "nochange", MTREE_KEYS_NOCHANGE, 0 },
00371 { "optional", MTREE_KEYS_OPT, 0 },
00372 { "rmd128digest", MTREE_KEYS_DIGEST, PGPHASHALGO_RIPEMD128 },
00373 { "rmd160digest", MTREE_KEYS_DIGEST, PGPHASHALGO_RIPEMD160 },
00374 { "rmd256digest", MTREE_KEYS_DIGEST, PGPHASHALGO_RIPEMD256 },
00375 { "rmd320digest", MTREE_KEYS_DIGEST, PGPHASHALGO_RIPEMD320 },
00376 { "salsa10", MTREE_KEYS_DIGEST, PGPHASHALGO_SALSA10 },
00377 { "salsa20", MTREE_KEYS_DIGEST, PGPHASHALGO_SALSA20 },
00378 { "sha1digest", MTREE_KEYS_DIGEST, PGPHASHALGO_SHA1 },
00379 { "sha224digest", MTREE_KEYS_DIGEST, PGPHASHALGO_SHA224 },
00380 { "sha256digest", MTREE_KEYS_DIGEST, PGPHASHALGO_SHA256 },
00381 { "sha384digest", MTREE_KEYS_DIGEST, PGPHASHALGO_SHA384 },
00382 { "sha512digest", MTREE_KEYS_DIGEST, PGPHASHALGO_SHA512 },
00383 { "size", MTREE_KEYS_SIZE, NEEDVALUE },
00384 { "tiger192digest", MTREE_KEYS_DIGEST, PGPHASHALGO_TIGER192 },
00385 { "time", MTREE_KEYS_TIME, NEEDVALUE },
00386 { "type", MTREE_KEYS_TYPE, NEEDVALUE },
00387 { "uid", MTREE_KEYS_UID, NEEDVALUE },
00388 { "uname", MTREE_KEYS_UNAME, NEEDVALUE },
00389 };
00390
00391 static int
00392 keycompare(const void * a, const void * b)
00393
00394 {
00395 return strcmp(((KEY *)a)->name, ((KEY *)b)->name);
00396 }
00397
00398 static unsigned
00399 parsekey(char *name, uint32_t *needvaluep)
00400
00401
00402
00403 {
00404 KEY *k, tmp;
00405
00406 if (needvaluep != NULL)
00407 *needvaluep = 0;
00408 if (*name == '\0')
00409 return 0;
00410 tmp.name = name;
00411 k = (KEY *)bsearch(&tmp, keylist, sizeof(keylist) / sizeof(keylist[0]),
00412 sizeof(keylist[0]), keycompare);
00413 if (k == NULL)
00414 mtree_error("unknown keyword %s", name);
00415
00416 if (needvaluep != NULL)
00417 *needvaluep = k->flags;
00418 return k->val;
00419 }
00420
00421 static const char *
00422 algo2tagname(uint32_t algo)
00423
00424 {
00425 const char * tagname = NULL;
00426
00427 switch (algo) {
00428 case PGPHASHALGO_MD5: tagname = "md5digest"; break;
00429 case PGPHASHALGO_SHA1: tagname = "sha1digest"; break;
00430 case PGPHASHALGO_RIPEMD160: tagname = "rmd160digest"; break;
00431 case PGPHASHALGO_MD2: tagname = "md2digest"; break;
00432 case PGPHASHALGO_TIGER192: tagname = "tiger192digest"; break;
00433 case PGPHASHALGO_HAVAL_5_160: tagname = "haval160digest"; break;
00434 case PGPHASHALGO_SHA256: tagname = "sha256digest"; break;
00435 case PGPHASHALGO_SHA384: tagname = "sha384digest"; break;
00436 case PGPHASHALGO_SHA512: tagname = "sha512digest"; break;
00437 case PGPHASHALGO_MD4: tagname = "md4digest"; break;
00438 case PGPHASHALGO_RIPEMD128: tagname = "rmd128digest"; break;
00439 case PGPHASHALGO_CRC32: tagname = "crc32"; break;
00440 case PGPHASHALGO_ADLER32: tagname = "adler32"; break;
00441 case PGPHASHALGO_CRC64: tagname = "crc64"; break;
00442 case PGPHASHALGO_JLU32: tagname = "jlu32"; break;
00443 case PGPHASHALGO_SHA224: tagname = "sha224digest"; break;
00444 case PGPHASHALGO_RIPEMD256: tagname = "rmd256digest"; break;
00445 case PGPHASHALGO_RIPEMD320: tagname = "rmd320digest"; break;
00446 case PGPHASHALGO_SALSA10: tagname = "salsa10"; break;
00447 case PGPHASHALGO_SALSA20: tagname = "salsa20"; break;
00448 default: tagname = NULL; break;
00449 }
00450 return tagname;
00451 }
00452
00453 #if defined(HAVE_ST_FLAGS)
00454 static const char *
00455 flags_to_string(u_long fflags)
00456
00457 {
00458 char * string = fflagstostr(fflags);
00459 if (string != NULL && *string == '\0') {
00460 free(string);
00461 string = xstrdup("none");
00462 }
00463 return string;
00464 }
00465 #endif
00466
00467
00468
00469
00470 static const uint32_t crctab[] = {
00471 0x0,
00472 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
00473 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
00474 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
00475 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
00476 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
00477 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
00478 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
00479 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
00480 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
00481 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
00482 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
00483 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
00484 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
00485 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
00486 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
00487 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
00488 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
00489 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
00490 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
00491 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
00492 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
00493 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
00494 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
00495 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
00496 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
00497 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
00498 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
00499 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
00500 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
00501 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
00502 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
00503 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
00504 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
00505 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
00506 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
00507 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
00508 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
00509 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
00510 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
00511 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
00512 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
00513 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
00514 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
00515 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
00516 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
00517 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
00518 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
00519 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
00520 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
00521 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
00522 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
00523 };
00524
00525
00526
00527
00528
00529
00530
00531 static int
00532 crc(FD_t fd, uint32_t * cval, uint32_t * clen)
00533
00534
00535 {
00536 uint32_t crc = 0;
00537 uint32_t len = 0;
00538
00539 #define COMPUTE(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)]
00540
00541 _rpmfts->crc_total ^= 0xffffffff;
00542
00543 { uint8_t buf[16 * 1024];
00544 size_t nr;
00545 while ((nr = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) != 0) {
00546 uint8_t *p;
00547 for (len += nr, p = buf; nr--; ++p) {
00548 COMPUTE(crc, *p);
00549 COMPUTE(_rpmfts->crc_total, *p);
00550 }
00551 }
00552 if (Ferror(fd))
00553 return 1;
00554 }
00555
00556 *clen = len;
00557
00558
00559 for (; len != 0; len >>= 8) {
00560 COMPUTE(crc, len & 0xff);
00561 COMPUTE(_rpmfts->crc_total, len & 0xff);
00562 }
00563
00564 *cval = (crc ^ 0xffffffff);
00565 _rpmfts->crc_total ^= 0xffffffff;
00566 return 0;
00567 }
00568
00569
00570
00571
00572
00573
00574 #define VIS_OCTAL 0x01
00575 #define VIS_CSTYLE 0x02
00576
00577
00578
00579
00580
00581 #define VIS_SP 0x04
00582 #define VIS_TAB 0x08
00583 #define VIS_NL 0x10
00584 #define VIS_WHITE (VIS_SP | VIS_TAB | VIS_NL)
00585 #define VIS_SAFE 0x20
00586
00587
00588
00589
00590 #define VIS_NOSLASH 0x40
00591
00592
00593
00594
00595 #define UNVIS_VALID 1
00596 #define UNVIS_VALIDPUSH 2
00597 #define UNVIS_NOCHAR 3
00598 #define UNVIS_SYNBAD -1
00599 #define UNVIS_ERROR -2
00600
00601
00602
00603
00604 #define UNVIS_END 1
00605
00606 static char *vis( char *dst, int c, int flag, int nextc)
00607 ;
00608 static int strvis( char *dst, const char *src, int flag)
00609 ;
00610 #ifdef NOTUSED
00611 static int strnvis( char *dst, const char *src, size_t siz, int flag)
00612 ;
00613 static int strvisx( char *dst, const char *src, size_t len, int flag)
00614 ;
00615 #endif
00616 static int strunvis( char *dst, const char *src)
00617 ;
00618 static int unvis( char *cp, char c, int *astate, int flag)
00619 ;
00620
00621 #define isoctal(c) (((unsigned char)(c)) >= '0' && ((unsigned char)(c)) <= '7')
00622 #define isvisible(c) \
00623 (((unsigned)(c) <= (unsigned)UCHAR_MAX && isascii((unsigned char)(c)) && \
00624 isgraph((unsigned char)(c))) \
00625 || ((flag & VIS_SP) == 0 && (c) == (int)' ') \
00626 || ((flag & VIS_TAB) == 0 && (c) == (int)'\t') \
00627 || ((flag & VIS_NL) == 0 && (c) == (int)'\n') \
00628 || ((flag & VIS_SAFE) \
00629 && ((c) == (int)'\b' || (c) == (int)'\007' || (c) == (int)'\r')))
00630
00631
00632
00633
00634 char *
00635 vis(char * dst, int c, int flag, int nextc)
00636 {
00637 if (isvisible(c)) {
00638 *dst++ = (char)c;
00639 if (c == (int)'\\' && (flag & VIS_NOSLASH) == 0)
00640 *dst++ = '\\';
00641 *dst = '\0';
00642 return dst;
00643 }
00644
00645 if (flag & VIS_CSTYLE) {
00646 switch(c) {
00647 case '\n':
00648 *dst++ = '\\';
00649 *dst++ = 'n';
00650 goto done;
00651 case '\r':
00652 *dst++ = '\\';
00653 *dst++ = 'r';
00654 goto done;
00655 case '\b':
00656 *dst++ = '\\';
00657 *dst++ = 'b';
00658 goto done;
00659 case '\a':
00660 *dst++ = '\\';
00661 *dst++ = 'a';
00662 goto done;
00663 case '\v':
00664 *dst++ = '\\';
00665 *dst++ = 'v';
00666 goto done;
00667 case '\t':
00668 *dst++ = '\\';
00669 *dst++ = 't';
00670 goto done;
00671 case '\f':
00672 *dst++ = '\\';
00673 *dst++ = 'f';
00674 goto done;
00675 case ' ':
00676 *dst++ = '\\';
00677 *dst++ = 's';
00678 goto done;
00679 case '\0':
00680 *dst++ = '\\';
00681 *dst++ = '0';
00682 if (isoctal(nextc)) {
00683 *dst++ = '0';
00684 *dst++ = '0';
00685 }
00686 goto done;
00687 }
00688 }
00689 if (((c & 0177) == (int)' ') || (flag & VIS_OCTAL)) {
00690 *dst++ = '\\';
00691 *dst++ = ((unsigned char)c >> 6 & 07) + '0';
00692 *dst++ = ((unsigned char)c >> 3 & 07) + '0';
00693 *dst++ = ((unsigned char)c & 07) + '0';
00694 goto done;
00695 }
00696 if ((flag & VIS_NOSLASH) == 0)
00697 *dst++ = '\\';
00698 if (c & 0200) {
00699 c &= 0177;
00700 *dst++ = 'M';
00701 }
00702 if (iscntrl(c)) {
00703 *dst++ = '^';
00704 if (c == 0177)
00705 *dst++ = '?';
00706 else
00707 *dst++ = (char)(c + (int)'@');
00708 } else {
00709 *dst++ = '-';
00710 *dst++ = (char)c;
00711 }
00712
00713 done:
00714 *dst = '\0';
00715 return dst;
00716 }
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731 int
00732 strvis(char * dst, const char * src, int flag)
00733 {
00734 char c;
00735 char *start;
00736
00737 for (start = dst; (c = *src) != '\0';)
00738 dst = vis(dst, (int)c, flag, (int)*++src);
00739 *dst = '\0';
00740 return (dst - start);
00741 }
00742
00743 #ifdef NOTUSED
00744 int
00745 strnvis(char * dst, const char * src, size_t siz, int flag)
00746 {
00747 char c;
00748 char *start, *end;
00749
00750 for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) {
00751 if (isvisible((int)c)) {
00752 *dst++ = c;
00753 if (c == '\\' && (flag & VIS_NOSLASH) == 0) {
00754
00755 if (dst < end)
00756 *dst++ = '\\';
00757 else {
00758 dst--;
00759 break;
00760 }
00761 }
00762 src++;
00763 } else {
00764
00765 if (dst + 3 < end)
00766 dst = vis(dst, (int)c, flag, (int)*++src);
00767 else
00768 break;
00769 }
00770 }
00771 *dst = '\0';
00772 if (dst >= end) {
00773 char tbuf[5];
00774
00775
00776 while ((c = *src) != '\0')
00777 dst += vis(tbuf, (int)c, flag, (int)*++src) - tbuf;
00778 }
00779 return (dst - start);
00780 }
00781 #endif
00782
00783 #ifdef NOTUSED
00784 int
00785 strvisx(char * dst, const char * src, size_t len, int flag)
00786 {
00787 char c;
00788 char *start;
00789
00790 for (start = dst; len > 1; len--) {
00791 c = *src;
00792 dst = vis(dst, (int)c, flag, (int)*++src);
00793 }
00794 if (len)
00795 dst = vis(dst, (int)*src, flag, (int)'\0');
00796 *dst = '\0';
00797 return (dst - start);
00798 }
00799 #endif
00800
00801
00802
00803
00804 #define S_GROUND 0
00805 #define S_START 1
00806 #define S_META 2
00807 #define S_META1 3
00808 #define S_CTRL 4
00809 #define S_OCTAL2 5
00810 #define S_OCTAL3 6
00811
00812 #if !defined(isoctal)
00813 #define isoctal(c) (((unsigned char)(c)) >= '0' && ((unsigned char)(c)) <= '7')
00814 #endif
00815
00816
00817
00818
00819 int
00820 unvis(char *cp, char c, int *astate, int flag)
00821 {
00822
00823 if (flag & UNVIS_END) {
00824 if (*astate == S_OCTAL2 || *astate == S_OCTAL3) {
00825 *astate = S_GROUND;
00826 return (UNVIS_VALID);
00827 }
00828 return (*astate == S_GROUND ? UNVIS_NOCHAR : UNVIS_SYNBAD);
00829 }
00830
00831 switch (*astate) {
00832
00833 case S_GROUND:
00834 *cp = '\0';
00835 if (c == '\\') {
00836 *astate = S_START;
00837 return (0);
00838 }
00839 *cp = c;
00840 return (UNVIS_VALID);
00841
00842 case S_START:
00843 switch(c) {
00844 case '\\':
00845 *cp = c;
00846 *astate = S_GROUND;
00847 return (UNVIS_VALID);
00848 case '0': case '1': case '2': case '3':
00849 case '4': case '5': case '6': case '7':
00850 *cp = (c - '0');
00851 *astate = S_OCTAL2;
00852 return (0);
00853 case 'M':
00854 *cp = (char) 0200;
00855 *astate = S_META;
00856 return (0);
00857 case '^':
00858 *astate = S_CTRL;
00859 return (0);
00860 case 'n':
00861 *cp = '\n';
00862 *astate = S_GROUND;
00863 return (UNVIS_VALID);
00864 case 'r':
00865 *cp = '\r';
00866 *astate = S_GROUND;
00867 return (UNVIS_VALID);
00868 case 'b':
00869 *cp = '\b';
00870 *astate = S_GROUND;
00871 return (UNVIS_VALID);
00872 case 'a':
00873 *cp = '\007';
00874 *astate = S_GROUND;
00875 return (UNVIS_VALID);
00876 case 'v':
00877 *cp = '\v';
00878 *astate = S_GROUND;
00879 return (UNVIS_VALID);
00880 case 't':
00881 *cp = '\t';
00882 *astate = S_GROUND;
00883 return (UNVIS_VALID);
00884 case 'f':
00885 *cp = '\f';
00886 *astate = S_GROUND;
00887 return (UNVIS_VALID);
00888 case 's':
00889 *cp = ' ';
00890 *astate = S_GROUND;
00891 return (UNVIS_VALID);
00892 case 'E':
00893 *cp = '\033';
00894 *astate = S_GROUND;
00895 return (UNVIS_VALID);
00896 case '\n':
00897 *astate = S_GROUND;
00898 return (UNVIS_NOCHAR);
00899 case '$':
00900 *astate = S_GROUND;
00901 return (UNVIS_NOCHAR);
00902 }
00903 *astate = S_GROUND;
00904 return (UNVIS_SYNBAD);
00905
00906 case S_META:
00907 if (c == '-')
00908 *astate = S_META1;
00909 else if (c == '^')
00910 *astate = S_CTRL;
00911 else {
00912 *astate = S_GROUND;
00913 return (UNVIS_SYNBAD);
00914 }
00915 return (0);
00916
00917 case S_META1:
00918 *astate = S_GROUND;
00919 *cp |= c;
00920 return (UNVIS_VALID);
00921
00922 case S_CTRL:
00923 if (c == '?')
00924 *cp |= 0177;
00925 else
00926 *cp |= c & 037;
00927 *astate = S_GROUND;
00928 return (UNVIS_VALID);
00929
00930 case S_OCTAL2:
00931 if (isoctal(c)) {
00932
00933
00934
00935 *cp = (*cp << 3) + (c - '0');
00936 *astate = S_OCTAL3;
00937 return (0);
00938 }
00939
00940
00941
00942 *astate = S_GROUND;
00943 return (UNVIS_VALIDPUSH);
00944
00945 case S_OCTAL3:
00946 *astate = S_GROUND;
00947 if (isoctal(c)) {
00948 *cp = (*cp << 3) + (c - '0');
00949 return (UNVIS_VALID);
00950 }
00951
00952
00953
00954 return (UNVIS_VALIDPUSH);
00955
00956 default:
00957
00958
00959
00960 *astate = S_GROUND;
00961 return (UNVIS_SYNBAD);
00962 }
00963 }
00964
00965
00966
00967
00968
00969
00970
00971
00972 int
00973 strunvis(char * dst, const char * src)
00974 {
00975 char c;
00976 char *start = dst;
00977 int state = 0;
00978
00979 while ((c = *src++) != '\0') {
00980 again:
00981 switch (unvis(dst, c, &state, 0)) {
00982 case UNVIS_VALID:
00983 dst++;
00984 break;
00985 case UNVIS_VALIDPUSH:
00986 dst++;
00987 goto again;
00988 case 0:
00989 case UNVIS_NOCHAR:
00990 break;
00991 default:
00992 return (-1);
00993 }
00994 }
00995 if (unvis(dst, c, &state, UNVIS_END) == UNVIS_VALID)
00996 dst++;
00997 *dst = '\0';
00998 return (dst - start);
00999 }
01000
01001
01002
01003
01004 #if defined(__linux__) || defined(__LCLINT__) || defined(__QNXNTO__)
01005 #if !defined(HAVE_GETMODE) || !defined(HAVE_SETMODE)
01006
01007 #define SET_LEN 6
01008 #define SET_LEN_INCR 4
01009
01010 typedef struct bitcmd {
01011 char cmd;
01012 char cmd2;
01013 mode_t bits;
01014 } BITCMD;
01015
01016 #define CMD2_CLR 0x01
01017 #define CMD2_SET 0x02
01018 #define CMD2_GBITS 0x04
01019 #define CMD2_OBITS 0x08
01020 #define CMD2_UBITS 0x10
01021
01022 #if !defined(HAVE_GETMODE)
01023
01024
01025
01026
01027
01028
01029 static mode_t
01030 getmode(const void * bbox, mode_t omode)
01031
01032 {
01033 const BITCMD *set;
01034 mode_t clrval, newmode, value;
01035
01036 set = (const BITCMD *)bbox;
01037 newmode = omode;
01038 for (value = 0;; set++)
01039 switch(set->cmd) {
01040
01041
01042
01043
01044
01045
01046 case 'u':
01047 value = (newmode & S_IRWXU) >> 6;
01048 goto common;
01049
01050 case 'g':
01051 value = (newmode & S_IRWXG) >> 3;
01052 goto common;
01053
01054 case 'o':
01055 value = newmode & S_IRWXO;
01056 common: if ((set->cmd2 & CMD2_CLR) != '\0') {
01057 clrval = (set->cmd2 & CMD2_SET) != '\0' ? S_IRWXO : value;
01058 if ((set->cmd2 & CMD2_UBITS) != '\0')
01059 newmode &= ~((clrval<<6) & set->bits);
01060 if ((set->cmd2 & CMD2_GBITS) != '\0')
01061 newmode &= ~((clrval<<3) & set->bits);
01062 if ((set->cmd2 & CMD2_OBITS) != '\0')
01063 newmode &= ~(clrval & set->bits);
01064 }
01065 if ((set->cmd2 & CMD2_SET) != '\0') {
01066 if ((set->cmd2 & CMD2_UBITS) != '\0')
01067 newmode |= (value<<6) & set->bits;
01068 if ((set->cmd2 & CMD2_GBITS) != '\0')
01069 newmode |= (value<<3) & set->bits;
01070 if ((set->cmd2 & CMD2_OBITS) != '\0')
01071 newmode |= value & set->bits;
01072 }
01073 break;
01074
01075 case '+':
01076 newmode |= set->bits;
01077 break;
01078
01079 case '-':
01080 newmode &= ~set->bits;
01081 break;
01082
01083 case 'X':
01084 if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH))
01085 newmode |= set->bits;
01086 break;
01087
01088 case '\0':
01089 default:
01090 #ifdef SETMODE_DEBUG
01091 (void) printf("getmode:%04o -> %04o\n", omode, newmode);
01092 #endif
01093 return newmode;
01094 }
01095 }
01096 #endif
01097
01098 #if !defined(HAVE_SETMODE)
01099 #ifdef SETMODE_DEBUG
01100 static void
01101 dumpmode(BITCMD *set)
01102 {
01103 for (; set->cmd; ++set)
01104 (void) printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n",
01105 set->cmd, set->bits, set->cmd2 ? " cmd2:" : "",
01106 set->cmd2 & CMD2_CLR ? " CLR" : "",
01107 set->cmd2 & CMD2_SET ? " SET" : "",
01108 set->cmd2 & CMD2_UBITS ? " UBITS" : "",
01109 set->cmd2 & CMD2_GBITS ? " GBITS" : "",
01110 set->cmd2 & CMD2_OBITS ? " OBITS" : "");
01111 }
01112 #endif
01113
01114 #define ADDCMD(a, b, c, d) \
01115 if (set >= endset) { \
01116 BITCMD *newset; \
01117 setlen += SET_LEN_INCR; \
01118 newset = realloc(saveset, sizeof(*newset) * setlen); \
01119 if (newset == NULL) { \
01120 if (saveset != NULL) \
01121 free(saveset); \
01122 saveset = NULL; \
01123 return (NULL); \
01124 } \
01125 set = newset + (set - saveset); \
01126 saveset = newset; \
01127 endset = newset + (setlen - 2); \
01128 } \
01129 set = addcmd(set, (a), (b), (c), (d))
01130
01131 #define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
01132
01133 static BITCMD *
01134 addcmd( BITCMD *set, int op, int who, int oparg, unsigned mask)
01135
01136 {
01137 switch (op) {
01138 case '=':
01139 set->cmd = '-';
01140 set->bits = who ? who : (int) STANDARD_BITS;
01141 set++;
01142
01143 op = (int)'+';
01144
01145 case '+':
01146 case '-':
01147 case 'X':
01148 set->cmd = (char)op;
01149 set->bits = (who ? (unsigned)who : mask) & oparg;
01150 break;
01151
01152 case 'u':
01153 case 'g':
01154 case 'o':
01155 set->cmd = (char)op;
01156 if (who) {
01157 set->cmd2 = (char)( ((who & S_IRUSR) ? CMD2_UBITS : 0) |
01158 ((who & S_IRGRP) ? CMD2_GBITS : 0) |
01159 ((who & S_IROTH) ? CMD2_OBITS : 0));
01160 set->bits = (mode_t)~0;
01161 } else {
01162 set->cmd2 =(char)(CMD2_UBITS | CMD2_GBITS | CMD2_OBITS);
01163 set->bits = mask;
01164 }
01165
01166 if (oparg == (int)'+')
01167 set->cmd2 |= CMD2_SET;
01168 else if (oparg == (int)'-')
01169 set->cmd2 |= CMD2_CLR;
01170 else if (oparg == (int)'=')
01171 set->cmd2 |= CMD2_SET|CMD2_CLR;
01172 break;
01173 }
01174 return set + 1;
01175 }
01176
01177
01178
01179
01180
01181
01182
01183 static void
01184 compress_mode( BITCMD *set)
01185
01186 {
01187 BITCMD *nset;
01188 int setbits, clrbits, Xbits, op;
01189
01190 for (nset = set;;) {
01191
01192 while ((op = (int)nset->cmd) != (int)'+' && op != (int)'-' && op != (int)'X') {
01193 *set++ = *nset++;
01194 if (!op)
01195 return;
01196 }
01197
01198 for (setbits = clrbits = Xbits = 0;; nset++) {
01199 if ((op = (int)nset->cmd) == (int)'-') {
01200 clrbits |= nset->bits;
01201 setbits &= ~nset->bits;
01202 Xbits &= ~nset->bits;
01203 } else if (op == (int)'+') {
01204 setbits |= nset->bits;
01205 clrbits &= ~nset->bits;
01206 Xbits &= ~nset->bits;
01207 } else if (op == (int)'X')
01208 Xbits |= nset->bits & ~setbits;
01209 else
01210 break;
01211 }
01212 if (clrbits) {
01213 set->cmd = '-';
01214 set->cmd2 = '\0';
01215 set->bits = clrbits;
01216 set++;
01217 }
01218 if (setbits) {
01219 set->cmd = '+';
01220 set->cmd2 = '\0';
01221 set->bits = setbits;
01222 set++;
01223 }
01224 if (Xbits) {
01225 set->cmd = 'X';
01226 set->cmd2 = '\0';
01227 set->bits = Xbits;
01228 set++;
01229 }
01230 }
01231 }
01232
01233
01234
01235 static void *
01236 setmode(const char * p)
01237
01238
01239 {
01240 int perm, who;
01241 char op;
01242 BITCMD *set, *saveset, *endset;
01243 sigset_t sigset, sigoset;
01244 mode_t mask;
01245 int equalopdone = 0;
01246 int permXbits, setlen;
01247 long perml;
01248
01249 if (!*p)
01250 return (NULL);
01251
01252
01253
01254
01255
01256
01257
01258 (void) sigfillset(&sigset);
01259 (void) sigprocmask(SIG_BLOCK, &sigset, &sigoset);
01260 (void) umask(mask = umask(0));
01261 mask = ~mask;
01262 (void) sigprocmask(SIG_SETMASK, &sigoset, NULL);
01263
01264 setlen = SET_LEN + 2;
01265
01266 if ((set = malloc((unsigned)(sizeof(*set) * setlen))) == NULL)
01267 return (NULL);
01268 saveset = set;
01269 endset = set + (setlen - 2);
01270
01271
01272
01273
01274
01275 if (isdigit(*p)) {
01276 perml = strtol(p, NULL, 8);
01277
01278 if (perml < 0 || (perml & ~(STANDARD_BITS|S_ISTXT)))
01279
01280 {
01281 free(saveset);
01282 return (NULL);
01283 }
01284 perm = (int)(mode_t)perml;
01285 while (*++p != '\0')
01286 if (*p < '0' || *p > '7') {
01287 free(saveset);
01288 return (NULL);
01289 }
01290 ADDCMD((int)'=', (int)(STANDARD_BITS|S_ISTXT), perm, (unsigned)mask);
01291 return (saveset);
01292 }
01293
01294
01295
01296
01297
01298 for (;;) {
01299
01300 for (who = 0;; ++p) {
01301 switch (*p) {
01302 case 'a':
01303 who |= STANDARD_BITS;
01304 break;
01305 case 'u':
01306 who |= S_ISUID|S_IRWXU;
01307 break;
01308 case 'g':
01309 who |= S_ISGID|S_IRWXG;
01310 break;
01311 case 'o':
01312 who |= S_IRWXO;
01313 break;
01314 default:
01315 goto getop;
01316 }
01317 }
01318
01319 getop: if ((op = *p++) != '+' && op != '-' && op != '=') {
01320 free(saveset);
01321 return (NULL);
01322 }
01323 if (op == '=')
01324 equalopdone = 0;
01325
01326 who &= ~S_ISTXT;
01327 for (perm = 0, permXbits = 0;; ++p) {
01328 switch (*p) {
01329 case 'r':
01330 perm |= S_IRUSR|S_IRGRP|S_IROTH;
01331 break;
01332 case 's':
01333
01334
01335
01336
01337 if (who == 0 || (who & ~S_IRWXO))
01338 perm |= S_ISUID|S_ISGID;
01339 break;
01340 case 't':
01341
01342
01343
01344
01345 if (who == 0 || (who & ~S_IRWXO)) {
01346 who |= S_ISTXT;
01347 perm |= S_ISTXT;
01348 }
01349 break;
01350 case 'w':
01351 perm |= S_IWUSR|S_IWGRP|S_IWOTH;
01352 break;
01353 case 'X':
01354 permXbits = (int)(S_IXUSR|S_IXGRP|S_IXOTH);
01355 break;
01356 case 'x':
01357 perm |= S_IXUSR|S_IXGRP|S_IXOTH;
01358 break;
01359 case 'u':
01360 case 'g':
01361 case 'o':
01362
01363
01364
01365
01366
01367 if (perm) {
01368 ADDCMD((int)op, who, perm, (unsigned)mask);
01369 perm = 0;
01370 }
01371 if (op == '=')
01372 equalopdone = 1;
01373 if (op == '+' && permXbits) {
01374 ADDCMD((int)'X', who, permXbits, (unsigned)mask);
01375 permXbits = 0;
01376 }
01377 ADDCMD((int)*p, who, (int)op, (unsigned)mask);
01378 break;
01379
01380 default:
01381
01382
01383
01384
01385 if (perm || (op == '=' && !equalopdone)) {
01386 if (op == '=')
01387 equalopdone = 1;
01388 ADDCMD((int)op, who, perm, (unsigned)mask);
01389 perm = 0;
01390 }
01391 if (permXbits) {
01392 ADDCMD((int)'X', who, permXbits, (unsigned)mask);
01393 permXbits = 0;
01394 }
01395 goto apply;
01396 }
01397 }
01398
01399 apply: if (!*p)
01400 break;
01401 if (*p != ',')
01402 goto getop;
01403 ++p;
01404 }
01405 set->cmd = '\0';
01406 #ifdef SETMODE_DEBUG
01407 (void) printf("Before compress_mode()\n");
01408 dumpmode(saveset);
01409 #endif
01410 compress_mode(saveset);
01411 #ifdef SETMODE_DEBUG
01412 (void) printf("After compress_mode()\n");
01413 dumpmode(saveset);
01414 #endif
01415 return saveset;
01416 }
01417
01418 #endif
01419 #endif
01420 #endif
01421
01422
01423
01424 static void
01425 set(char * t, NODE * ip)
01426
01427
01428 {
01429 char *kw;
01430
01431 for (; (kw = strtok(t, "= \t\n")) != NULL; t = NULL) {
01432 uint32_t needvalue;
01433 enum mtreeKeys_e type = parsekey(kw, &needvalue);
01434 char *val = NULL;
01435 char *ep;
01436
01437 if (needvalue && (val = strtok(NULL, " \t\n")) == NULL)
01438 mtree_error("missing value");
01439 ip->flags |= type;
01440 switch(type) {
01441 case MTREE_KEYS_CKSUM:
01442 ip->cksum = strtoul(val, &ep, 10);
01443 if (*ep != '\0')
01444 mtree_error("invalid checksum %s", val);
01445 break;
01446 case MTREE_KEYS_FLAGS:
01447 #if defined(HAVE_ST_FLAGS)
01448 if (!strcmp(val, "none")) {
01449 ip->sb.st_flags = 0;
01450 break;
01451 }
01452 { unsigned long fset, fclr;
01453 if (strtofflags(&val, &fset, &fclr))
01454 mtree_error("%s", strerror(errno));
01455 ip->sb.st_flags = fset;
01456 }
01457 #endif
01458 break;
01459 case MTREE_KEYS_GID:
01460 ip->sb.st_gid = strtoul(val, &ep, 10);
01461 if (*ep != '\0')
01462 mtree_error("invalid gid %s", val);
01463 break;
01464 case MTREE_KEYS_GNAME:
01465 if (gnameToGid(val, &ip->sb.st_gid) == -1)
01466 mtree_error("unknown group %s", val);
01467 break;
01468 case MTREE_KEYS_IGN:
01469
01470 break;
01471 case MTREE_KEYS_MODE:
01472 { mode_t *m;
01473 if ((m = setmode(val)) == NULL)
01474 mtree_error("invalid file mode %s", val);
01475 ip->sb.st_mode = getmode(m, 0);
01476 free(m);
01477 } break;
01478 case MTREE_KEYS_NLINK:
01479 ip->sb.st_nlink = strtoul(val, &ep, 10);
01480 if (*ep != '\0')
01481 mtree_error("invalid link count %s", val);
01482 break;
01483 case MTREE_KEYS_DIGEST:
01484 (void) argiAdd(&ip->algos, -1, (int)needvalue);
01485 (void) argvAdd(&ip->digests, val);
01486 break;
01487 case MTREE_KEYS_SIZE:
01488
01489 ip->sb.st_size = strtoul(val, &ep, 10);
01490
01491 if (*ep != '\0')
01492 mtree_error("invalid size %s", val);
01493 break;
01494 case MTREE_KEYS_SLINK:
01495 ip->slink = xmalloc(strlen(val) + 1);
01496 if (strunvis(ip->slink, val) == -1) {
01497 fprintf(stderr, _("%s: filename (%s) encoded incorrectly\n"),
01498 __progname, val);
01499
01500 strcpy(ip->slink, val);
01501 }
01502 break;
01503 case MTREE_KEYS_TIME:
01504 #if defined(TIMEVAL_TO_TIMESPEC)
01505 ip->sb.st_mtimespec.tv_sec = strtoul(val, &ep, 10);
01506 if (*ep != '.')
01507 mtree_error("invalid time %s", val);
01508 val = ep + 1;
01509 ip->sb.st_mtimespec.tv_nsec = strtoul(val, &ep, 10);
01510 if (*ep != '\0')
01511 mtree_error("invalid time %s", val);
01512 #else
01513 ip->sb.st_mtime = strtoul(val, &ep, 10);
01514 if (*ep != '.')
01515 mtree_error("invalid time %s", val);
01516 val = ep + 1;
01517 (void) strtoul(val, &ep, 10);
01518 if (*ep != '\0')
01519 mtree_error("invalid time %s", val);
01520 #endif
01521 break;
01522 case MTREE_KEYS_TYPE:
01523 switch(*val) {
01524 case 'b':
01525 if (!strcmp(val, "block"))
01526 ip->type = F_BLOCK;
01527 break;
01528 case 'c':
01529 if (!strcmp(val, "char"))
01530 ip->type = F_CHAR;
01531 break;
01532 case 'd':
01533 if (!strcmp(val, "dir"))
01534 ip->type = F_DIR;
01535 break;
01536 case 'f':
01537 if (!strcmp(val, "file"))
01538 ip->type = F_FILE;
01539 if (!strcmp(val, "fifo"))
01540 ip->type = F_FIFO;
01541 break;
01542 case 'l':
01543 if (!strcmp(val, "link"))
01544 ip->type = F_LINK;
01545 break;
01546 case 's':
01547 if (!strcmp(val, "socket"))
01548 ip->type = F_SOCK;
01549 break;
01550 default:
01551 mtree_error("unknown file type %s", val);
01552 }
01553 break;
01554 case MTREE_KEYS_UID:
01555 ip->sb.st_uid = strtoul(val, &ep, 10);
01556 if (*ep != '\0')
01557 mtree_error("invalid uid %s", val);
01558 break;
01559 case MTREE_KEYS_UNAME:
01560 if (unameToUid(val, &ip->sb.st_uid) == -1)
01561 mtree_error("unknown user %s", val);
01562 break;
01563 case MTREE_KEYS_NONE:
01564 case MTREE_KEYS_DONE:
01565 case MTREE_KEYS_MAGIC:
01566 case MTREE_KEYS_VISIT:
01567 case MTREE_KEYS_NOCHANGE:
01568 case MTREE_KEYS_OPT:
01569 ip->flags &= ~type;
01570 break;
01571 }
01572 }
01573 }
01574
01575 static void
01576 unset(char * t, NODE * ip)
01577
01578
01579 {
01580 char *p;
01581
01582 while ((p = strtok(t, "\n\t ")) != NULL)
01583 ip->flags &= ~parsekey(p, NULL);
01584 }
01585
01586 #define KF_ISSET(_keys, _KEY) ((_keys) & (MTREE_KEYS_##_KEY))
01587
01588
01589 NODE *
01590 mtreeSpec(rpmfts fts, FILE * fp)
01591 {
01592 NODE *centry = NULL;
01593 NODE *last = NULL;
01594 char *p;
01595 NODE ginfo;
01596 NODE *root = NULL;
01597 NODE *forest = NULL;
01598 int c_cur = 0;
01599 int c_next = 0;
01600 char buf[2048];
01601
01602 if (fp == NULL)
01603 fp = stdin;
01604
01605 memset(&ginfo, 0, sizeof(ginfo));
01606 for (fts->lineno = 1; fgets(buf, (int)sizeof(buf), fp) != NULL;
01607 ++fts->lineno, c_cur = c_next, c_next = 0)
01608 {
01609
01610 if (buf[0] == '\n')
01611 continue;
01612
01613
01614 if ((p = strchr(buf, '\n')) == NULL)
01615 mtree_error("line %d too long", fts->lineno);
01616
01617
01618 if (p[-1] == '\\') {
01619 --p;
01620 c_next = 1;
01621 }
01622
01623
01624 *p = '\0';
01625
01626
01627 for (p = buf; *p && isspace(*p); ++p);
01628
01629
01630 if (*p == '\0' || *p == '#')
01631 continue;
01632
01633 #ifdef DEBUG
01634 (void)fprintf(stderr, "line %3d: {%s}\n", fts->lineno, p);
01635 #endif
01636 if (c_cur) {
01637 set(p, centry);
01638 continue;
01639 }
01640
01641
01642 if ((p = strtok(p, "\n\t ")) == NULL)
01643 mtree_error("missing field");
01644
01645 if (p[0] == '/')
01646 switch(p[1]) {
01647 case 's':
01648 if (strcmp(p + 1, "set"))
01649 break;
01650 set(NULL, &ginfo);
01651 continue;
01652 case 'u':
01653 if (strcmp(p + 1, "unset"))
01654 break;
01655 unset(NULL, &ginfo);
01656 continue;
01657 }
01658
01659 #if !defined(_RPMFI_INTERNAL)
01660 if (strchr(p, '/') != NULL)
01661 mtree_error("slash character in file name");
01662 #endif
01663
01664 if (!strcmp(p, "..")) {
01665
01666 if (root == NULL)
01667 goto noparent;
01668 if (last->type != F_DIR || KF_ISSET(last->flags, DONE)) {
01669 if (last == root)
01670 goto noparent;
01671 last = last->parent;
01672 }
01673 last->flags |= MTREE_KEYS_DONE;
01674 continue;
01675
01676 noparent: mtree_error("no parent node");
01677 }
01678
01679
01680 centry = xcalloc(1, sizeof(*centry) + strlen(p));
01681 *centry = ginfo;
01682 #define MAGIC "?*["
01683 if (strpbrk(p, MAGIC) != NULL)
01684 centry->flags |= MTREE_KEYS_MAGIC;
01685 if (strunvis(centry->name, p) == -1) {
01686 fprintf(stderr, _("%s: filename (%s) encoded incorrectly\n"),
01687 __progname, p);
01688 strcpy(centry->name, p);
01689 }
01690 set(NULL, centry);
01691
01692 if (root == NULL) {
01693 last = root = centry;
01694 root->parent = root;
01695 if (forest == NULL)
01696 forest = root;
01697 } else if (centry->name[0] == '.' && centry->name[1] == '\0') {
01698 centry->prev = root;
01699 last = root = root->next = centry;
01700 root->parent = root;
01701 } else if (last->type == F_DIR && !KF_ISSET(last->flags, DONE)) {
01702 centry->parent = last;
01703 last = last->child = centry;
01704 } else {
01705 centry->parent = last->parent;
01706 centry->prev = last;
01707 last = last->next = centry;
01708 }
01709 }
01710 return forest;
01711 }
01712
01713
01714
01715
01716 static const char *
01717 ftype(unsigned type)
01718
01719 {
01720 switch(type) {
01721 case F_BLOCK: return "block";
01722 case F_CHAR: return "char";
01723 case F_DIR: return "dir";
01724 case F_FIFO: return "fifo";
01725 case F_FILE: return "file";
01726 case F_LINK: return "link";
01727 case F_SOCK: return "socket";
01728 default: return "unknown";
01729 }
01730
01731 }
01732
01733
01734 static const char *
01735 inotype(mode_t mode)
01736
01737 {
01738 switch(mode & S_IFMT) {
01739 case S_IFBLK: return "block";
01740 case S_IFCHR: return "char";
01741 case S_IFDIR: return "dir";
01742 case S_IFIFO: return "fifo";
01743 case S_IFREG: return "file";
01744 case S_IFLNK: return "link";
01745
01746 case S_IFSOCK: return "socket";
01747
01748 default: return "unknown";
01749 }
01750
01751 }
01752
01753
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767
01768
01769
01770
01771
01772
01773
01774
01775
01776
01777
01778
01779 #define FF(a, b, c, d) \
01780 (((a)->flags & (c)) && ((b)->flags & (c)) && ((a)->d) != ((b)->d))
01781 #define FS(a, b, c, d) \
01782 (((a)->flags & (c)) && ((b)->flags & (c)) && strcmp((a)->d,(b)->d))
01783 #define FM(a, b, c, d) \
01784 (((a)->flags & (c)) && ((b)->flags & (c)) && memcmp(&(a)->d,&(b)->d, sizeof (a)->d))
01785
01786 static void
01787 shownode(NODE *n, enum mtreeKeys_e keys, const char *path)
01788
01789
01790 {
01791 printf("%s%s %s", path, n->name, ftype((unsigned)n->type));
01792 if (KF_ISSET(keys, CKSUM))
01793 printf(" cksum=%lu", (unsigned long) n->cksum);
01794 if (KF_ISSET(keys, GID))
01795 printf(" gid=%lu", (unsigned long) n->sb.st_gid);
01796 if (KF_ISSET(keys, GNAME)) {
01797 const char * gname = gidToGname(n->sb.st_gid);
01798 if (gname != NULL)
01799 printf(" gname=%s", gname);
01800 else
01801 printf(" gid=%lu", (unsigned long) n->sb.st_gid);
01802 }
01803 if (KF_ISSET(keys, MODE))
01804 printf(" mode=%o", (unsigned) n->sb.st_mode);
01805 if (KF_ISSET(keys, NLINK))
01806 printf(" nlink=%lu", (unsigned long) n->sb.st_nlink);
01807
01808 if (KF_ISSET(keys, SIZE))
01809 printf(" size=%llu", (unsigned long long)n->sb.st_size);
01810
01811 if (KF_ISSET(keys, UID))
01812 printf(" uid=%lu", (unsigned long) n->sb.st_uid);
01813 if (KF_ISSET(keys, UNAME)) {
01814 const char * uname = uidToUname(n->sb.st_uid);
01815 if (uname != NULL)
01816 printf(" uname=%s", uname);
01817 else
01818 printf(" uid=%lu", (unsigned long) n->sb.st_uid);
01819 }
01820
01821
01822 if (KF_ISSET(keys, DIGEST)) {
01823 int i;
01824
01825 if (n->algos != NULL)
01826 for (i = 0; i < (int) n->algos->nvals; i++) {
01827 uint32_t algo = n->algos->vals[i];
01828 const char * tagname = algo2tagname(algo);
01829 if (tagname != NULL)
01830 printf(" %s=%s", tagname, n->digests[i]);
01831 }
01832 }
01833
01834 #if defined(HAVE_ST_FLAGS)
01835 if (KF_ISSET(keys, FLAGS))
01836 printf(" flags=%s", flags_to_string(n->sb.st_flags));
01837 #endif
01838 printf("\n");
01839 }
01840
01841 static int
01842 mismatch(NODE *n1, NODE *n2, enum mtreeKeys_e differ, const char *path)
01843
01844
01845 {
01846 enum mtreeKeys_e keys = _rpmfts->keys;
01847
01848 if (n2 == NULL) {
01849 shownode(n1, differ, path);
01850 return 1;
01851 }
01852 if (n1 == NULL) {
01853 printf("\t");
01854 shownode(n2, differ, path);
01855 return 1;
01856 }
01857 if (!(differ & keys))
01858 return 0;
01859 printf("\t\t");
01860 shownode(n1, differ, path);
01861 printf("\t\t");
01862 shownode(n2, differ, path);
01863 return 1;
01864 }
01865
01866 static int
01867 compare_nodes(NODE *n1, NODE *n2, const char *path)
01868
01869
01870 {
01871 enum mtreeKeys_e differs = MTREE_KEYS_NONE;
01872 int xx;
01873
01874 if (n1 != NULL && n1->type == F_LINK)
01875 n1->flags &= ~MTREE_KEYS_MODE;
01876 if (n2 != NULL && n2->type == F_LINK)
01877 n2->flags &= ~MTREE_KEYS_MODE;
01878 if (n1 == NULL && n2 != NULL) {
01879 differs = n2->flags;
01880 xx = mismatch(n1, n2, differs, path);
01881 return 1;
01882 }
01883 if (n1 != NULL && n2 == NULL) {
01884 differs = n1->flags;
01885 xx = mismatch(n1, n2, differs, path);
01886 return 1;
01887 }
01888 if (n1->type != n2->type) {
01889 differs = MTREE_KEYS_NONE;
01890 xx = mismatch(n1, n2, differs, path);
01891 return 1;
01892 }
01893 if (FF(n1, n2, MTREE_KEYS_CKSUM, cksum))
01894 differs |= MTREE_KEYS_CKSUM;
01895 if (FF(n1, n2, MTREE_KEYS_GID, sb.st_gid))
01896 differs |= MTREE_KEYS_GID;
01897 if (FF(n1, n2, MTREE_KEYS_GNAME, sb.st_gid))
01898 differs |= MTREE_KEYS_GNAME;
01899 if (FF(n1, n2, MTREE_KEYS_MODE, sb.st_mode))
01900 differs |= MTREE_KEYS_MODE;
01901 if (FF(n1, n2, MTREE_KEYS_NLINK, sb.st_nlink))
01902 differs |= MTREE_KEYS_NLINK;
01903 if (FF(n1, n2, MTREE_KEYS_SIZE, sb.st_size))
01904 differs |= MTREE_KEYS_SIZE;
01905
01906 if (FS(n1, n2, MTREE_KEYS_SLINK, slink))
01907 differs |= MTREE_KEYS_SLINK;
01908
01909
01910 if (FM(n1, n2, MTREE_KEYS_TIME, sb.st_mtimespec))
01911 differs |= MTREE_KEYS_TIME;
01912
01913 if (FF(n1, n2, MTREE_KEYS_UID, sb.st_uid))
01914 differs |= MTREE_KEYS_UID;
01915 if (FF(n1, n2, MTREE_KEYS_UNAME, sb.st_uid))
01916 differs |= MTREE_KEYS_UNAME;
01917
01918
01919 if (KF_ISSET(n1->flags, DIGEST) || KF_ISSET(n2->flags, DIGEST)) {
01920 if ((KF_ISSET(n1->flags, DIGEST) != KF_ISSET(n2->flags, DIGEST))
01921 || (n1->algos == NULL || n2->algos == NULL)
01922 || (n1->algos->nvals != n2->algos->nvals))
01923 differs |= MTREE_KEYS_DIGEST;
01924 else {
01925 int i;
01926
01927 for (i = 0; i < (int) n1->algos->nvals; i++) {
01928 if ((n1->algos->vals[i] == n2->algos->vals[i])
01929 && !strcmp(n1->digests[i], n2->digests[i]))
01930 continue;
01931 differs |= MTREE_KEYS_DIGEST;
01932 break;
01933 }
01934 }
01935 }
01936
01937 #if defined(HAVE_ST_FLAGS)
01938 if (FF(n1, n2, MTREE_KEYS_FLAGS, sb.st_flags))
01939 differs |= MTREE_KEYS_FLAGS;
01940 #endif
01941
01942 if (differs) {
01943 xx = mismatch(n1, n2, differs, path);
01944 return 1;
01945 }
01946 return 0;
01947 }
01948
01949 static int
01950 mtreeSWalk(NODE *t1, NODE *t2, const char *path)
01951
01952
01953 {
01954 NODE *c1 = (t1 != NULL ? t1->child : NULL);
01955 NODE *c2 = (t2 != NULL ? t2->child : NULL);
01956 int r = 0;
01957
01958 while (c1 != NULL || c2 != NULL) {
01959 NODE *n1, *n2;
01960 char *np;
01961 int i;
01962
01963 n1 = (c1 != NULL ? c1->next : NULL);
01964 n2 = (c2 != NULL ? c2->next : NULL);
01965 if (c1 != NULL && c2 != NULL) {
01966 if (c1->type != F_DIR && c2->type == F_DIR) {
01967 n2 = c2;
01968 c2 = NULL;
01969 } else if (c1->type == F_DIR && c2->type != F_DIR) {
01970 n1 = c1;
01971 c1 = NULL;
01972 } else {
01973 i = strcmp(c1->name, c2->name);
01974 if (i > 0) {
01975 n1 = c1;
01976 c1 = NULL;
01977 } else if (i < 0) {
01978 n2 = c2;
01979 c2 = NULL;
01980 }
01981 }
01982 }
01983
01984 if (c1 == NULL && c2->type == F_DIR) {
01985 if (asprintf(&np, "%s%s/", path, c2->name)) {
01986 perror("asprintf");
01987 }
01988 i = mtreeSWalk(c1, c2, np);
01989 free(np);
01990 i += compare_nodes(c1, c2, path);
01991 } else if (c2 == NULL && c1->type == F_DIR) {
01992 if (asprintf(&np, "%s%s/", path, c1->name)) {
01993 perror("asprintf");
01994 }
01995 i = mtreeSWalk(c1, c2, np);
01996 free(np);
01997 i += compare_nodes(c1, c2, path);
01998 } else if (c1 == NULL || c2 == NULL) {
01999 i = compare_nodes(c1, c2, path);
02000 } else if (c1->type == F_DIR && c2->type == F_DIR) {
02001 if (asprintf(&np, "%s%s/", path, c1->name)) {
02002 perror("asprintf");
02003 }
02004 i = mtreeSWalk(c1, c2, np);
02005 free(np);
02006 i += compare_nodes(c1, c2, path);
02007 } else {
02008 i = compare_nodes(c1, c2, path);
02009 }
02010
02011 r += i;
02012 c1 = n1;
02013 c2 = n2;
02014 }
02015 return r;
02016 }
02017
02018 int
02019 mtreeVSpec(rpmfts fts)
02020 {
02021 NODE * root1 = mtreeSpec(fts, fts->spec1);
02022 NODE * root2 = mtreeSpec(fts, fts->spec2);
02023 int rval = 0;
02024
02025 rval = mtreeSWalk(root1, root2, "");
02026 rval += compare_nodes(root1, root2, "");
02027 return (rval > 0 ? MISMATCHEXIT : 0);
02028 }
02029
02030
02031
02032
02033 static const char *
02034 rlink(const char * name)
02035
02036
02037
02038 {
02039 static char lbuf[MAXPATHLEN];
02040 int len;
02041
02042 if ((len = Readlink(name, lbuf, sizeof(lbuf)-1)) == -1)
02043 mtree_error("%s: %s", name, strerror(errno));
02044 lbuf[len] = '\0';
02045 return lbuf;
02046 }
02047
02048 #define SKIPDOTSLASH(_f) ((_f)[0] == '.' && (_f)[1] == '/' ? (_f) + 2 : (_f))
02049
02050 #define COMPAREINDENTNAMELEN 8
02051 #define LABEL \
02052 if (!label++) { \
02053 (void) printf(_("%s changed\n"), SKIPDOTSLASH(p->fts_path)); \
02054 tab = "\t"; \
02055 }
02056
02057
02058 static const char * algo2name(uint32_t algo)
02059
02060 {
02061 switch (algo) {
02062 case PGPHASHALGO_MD5: return "MD5";
02063 case PGPHASHALGO_SHA1: return "SHA1";
02064 case PGPHASHALGO_RIPEMD160: return "RIPEMD160";
02065 case PGPHASHALGO_MD2: return "MD2";
02066 case PGPHASHALGO_TIGER192: return "TIGER192";
02067 case PGPHASHALGO_HAVAL_5_160: return "HAVAL-5-160";
02068 case PGPHASHALGO_SHA256: return "SHA256";
02069 case PGPHASHALGO_SHA384: return "SHA384";
02070 case PGPHASHALGO_SHA512: return "SHA512";
02071
02072 case PGPHASHALGO_MD4: return "MD4";
02073 case PGPHASHALGO_RIPEMD128: return "RIPEMD128";
02074 case PGPHASHALGO_CRC32: return "CRC32";
02075 case PGPHASHALGO_ADLER32: return "ADLER32";
02076 case PGPHASHALGO_CRC64: return "CRC64";
02077 case PGPHASHALGO_JLU32: return "JLU32";
02078 case PGPHASHALGO_SHA224: return "SHA224";
02079 case PGPHASHALGO_RIPEMD256: return "RIPEMD256";
02080 case PGPHASHALGO_RIPEMD320: return "RIPEMD320";
02081 case PGPHASHALGO_SALSA10: return "SALSA10";
02082 case PGPHASHALGO_SALSA20: return "SALSA20";
02083
02084 default: return "Unknown";
02085 }
02086
02087 }
02088
02089 static int
02090 compare(rpmfts fts, NODE *const s)
02091
02092
02093
02094 {
02095 const char * name = s->name;
02096 FTSENT *const p = fts->p;
02097 const char * fts_accpath = p->fts_accpath;
02098 struct stat *const st = p->fts_statp;
02099 enum mtreeKeys_e keys = s->flags;
02100 int label = 0;
02101 const char *cp;
02102 const char *tab = "";
02103
02104 switch(s->type) {
02105 case F_BLOCK:
02106 if (!S_ISBLK(st->st_mode))
02107 goto typeerr;
02108 break;
02109 case F_CHAR:
02110 if (!S_ISCHR(st->st_mode))
02111 goto typeerr;
02112 break;
02113 case F_DIR:
02114 if (!S_ISDIR(st->st_mode))
02115 goto typeerr;
02116 break;
02117 case F_FIFO:
02118 if (!S_ISFIFO(st->st_mode))
02119 goto typeerr;
02120 break;
02121 case F_FILE:
02122 if (!S_ISREG(st->st_mode))
02123 goto typeerr;
02124 break;
02125 case F_LINK:
02126 if (!S_ISLNK(st->st_mode))
02127 goto typeerr;
02128 break;
02129 case F_SOCK:
02130
02131 if (!S_ISSOCK(st->st_mode)) {
02132 typeerr: LABEL;
02133 (void) printf(_("\ttype expected %s found %s)\n"),
02134 ftype((unsigned)s->type), inotype(st->st_mode));
02135 }
02136
02137 break;
02138 }
02139
02140
02141 if ((KF_ISSET(keys, UID) || KF_ISSET(keys, UNAME)) && s->sb.st_uid != st->st_uid) {
02142 LABEL;
02143 (void) printf(_("%s%s expected %lu found %lu"), tab, "user",
02144 (unsigned long)s->sb.st_uid, (unsigned long)st->st_uid);
02145 if (MF_ISSET(UPDATE)) {
02146 if (Chown(fts_accpath, s->sb.st_uid, -1))
02147 (void) printf(_(" not modified: %s)\n"), strerror(errno));
02148 else
02149 (void) printf(_(" modified)\n"));
02150 } else
02151 (void) printf("\n");
02152 tab = "\t";
02153 }
02154 if ((KF_ISSET(keys, GID) || KF_ISSET(keys, GNAME)) && s->sb.st_gid != st->st_gid) {
02155 LABEL;
02156 (void) printf(_("%s%s expected %lu found %lu"), tab, "gid",
02157 (unsigned long)s->sb.st_gid, (unsigned long)st->st_gid);
02158 if (MF_ISSET(UPDATE)) {
02159 if (Chown(fts_accpath, -1, s->sb.st_gid))
02160 (void) printf(_(" not modified: %s)\n"), strerror(errno));
02161 else
02162 (void) printf(_(" modified)\n"));
02163 } else
02164 (void) printf("\n");
02165 tab = "\t";
02166 }
02167 if (KF_ISSET(keys, MODE) && s->sb.st_mode != (st->st_mode & MBITS)) {
02168 if (MF_ISSET(LOOSE)) {
02169 mode_t tmode = s->sb.st_mode;
02170 mode_t mode = (st->st_mode & MBITS);
02171
02172
02173
02174
02175
02176
02177 if (!((tmode & ~(S_IRWXU|S_IRWXG|S_IRWXO))
02178 || (mode & ~(S_IRWXU|S_IRWXG|S_IRWXO))))
02179 if ((mode | tmode) == tmode)
02180 goto skip;
02181 }
02182 LABEL;
02183 (void) printf(_("%s%s expected %#o found %#o"), tab, "permissions",
02184 (unsigned)s->sb.st_mode, (unsigned)(st->st_mode & MBITS));
02185 if (MF_ISSET(UPDATE)) {
02186 if (Chmod(fts_accpath, s->sb.st_mode))
02187 (void) printf(_(" not modified: %s)\n"), strerror(errno));
02188 else
02189 (void) printf(_(" modified)\n"));
02190 } else
02191 (void) printf("\n");
02192 tab = "\t";
02193 skip:
02194 ;
02195 }
02196 if (KF_ISSET(keys, NLINK) && s->type != F_DIR &&
02197 s->sb.st_nlink != st->st_nlink)
02198 {
02199 LABEL;
02200 (void) printf(_("%s%s expected %lu found %lu)\n"), tab, "link_count",
02201 (unsigned long)s->sb.st_nlink, (unsigned long)st->st_nlink);
02202 tab = "\t";
02203 }
02204 if (KF_ISSET(keys, SIZE) && s->sb.st_size != st->st_size) {
02205 LABEL;
02206
02207 (void) printf(_("%s%s expected %llu found %llu\n"), tab, "size",
02208 (unsigned long long)s->sb.st_size,
02209 (unsigned long long)st->st_size);
02210
02211 tab = "\t";
02212 }
02213
02214
02215
02216
02217
02218
02219
02220
02221 if (KF_ISSET(keys, TIME)) {
02222 struct timeval tv[2];
02223
02224
02225 #if defined(TIMESPEC_TO_TIMEVAL)
02226 TIMESPEC_TO_TIMEVAL(&tv[0], &s->sb.st_mtimespec);
02227 TIMESPEC_TO_TIMEVAL(&tv[1], &st->st_mtimespec);
02228 #else
02229 tv[0].tv_sec = (long)s->sb.st_mtime;
02230 tv[0].tv_usec = 0L;
02231 tv[1].tv_sec = (long)st->st_mtime;
02232 tv[1].tv_usec = 0L;
02233 #endif
02234
02235 if (tv[0].tv_sec != tv[1].tv_sec || tv[0].tv_usec != tv[1].tv_usec) {
02236 time_t t1 = (time_t)tv[0].tv_sec;
02237 time_t t2 = (time_t)tv[1].tv_sec;
02238 LABEL;
02239 (void) printf(_("%s%s expected %.24s "), tab, "modification time", ctime(&t1));
02240 (void) printf(_("found %.24s"), ctime(&t2));
02241 if (MF_ISSET(TOUCH)) {
02242 tv[1] = tv[0];
02243 if (Utimes(fts_accpath, tv))
02244 (void) printf(_(" not modified: %s)\n"), strerror(errno));
02245 else
02246 (void) printf(_(" modified\n"));
02247 } else
02248 (void) printf("\n");
02249 tab = "\t";
02250 }
02251 }
02252
02253
02254 if (KF_ISSET(keys, CKSUM) || s->algos != NULL) {
02255 FD_t fd = Fopen(fts_accpath, "r.ufdio");
02256 uint32_t vlen, val;
02257 int i;
02258
02259 if (fd == NULL || Ferror(fd)) {
02260 LABEL;
02261 (void) printf("%scksum: %s: %s\n", tab, fts_accpath, Fstrerror(fd));
02262 goto cleanup;
02263 }
02264
02265
02266 if (s->algos != NULL)
02267 for (i = s->algos->nvals; i-- > 0;)
02268 fdInitDigest(fd, s->algos->vals[i], 0);
02269
02270
02271 if (KF_ISSET(keys, CKSUM))
02272 i = crc(fd, &val, &vlen);
02273 else {
02274 char buffer[16 * 1024];
02275 while (Fread(buffer, sizeof(buffer[0]), sizeof(buffer), fd) > 0)
02276 {};
02277 i = (Ferror(fd) ? 1 : 0);
02278 }
02279 if (i) {
02280 LABEL;
02281 (void) printf("%scksum: %s: %s\n", tab, fts_accpath, Fstrerror(fd));
02282 goto cleanup;
02283 }
02284
02285
02286 if (KF_ISSET(keys, CKSUM)) {
02287 if (s->cksum != val) {
02288 LABEL;
02289 (void) printf(_("%s%s expected %lu found %lu\n"), tab, "cksum",
02290 (unsigned long) s->cksum, (unsigned long) val);
02291 tab = "\t";
02292 }
02293 }
02294
02295
02296 if (s->algos != NULL)
02297 for (i = 0; i < (int) s->algos->nvals; i++) {
02298 static int asAscii = 1;
02299 uint32_t algo = s->algos->vals[i];
02300 const char * digest = NULL;
02301 size_t digestlen = 0;
02302
02303 fdFiniDigest(fd, algo, &digest, &digestlen, asAscii);
02304 assert(digest != NULL);
02305 if (strcmp(digest, s->digests[i])) {
02306 LABEL;
02307 printf(_("%s%s expected %s found %s\n"), tab, algo2name(algo),
02308 s->digests[i], digest);
02309 tab = "\t";
02310 }
02311 digest = _free(digest);
02312 digestlen = 0;
02313 }
02314
02315
02316 cleanup:
02317 if (fd != NULL) {
02318 (void) rpmswAdd(&dc_readops, fdstat_op(fd, FDSTAT_READ));
02319 (void) rpmswAdd(&dc_digestops, fdstat_op(fd, FDSTAT_DIGEST));
02320 (void) Fclose(fd);
02321 fd = NULL;
02322 }
02323 }
02324
02325 if (KF_ISSET(keys, SLINK) && strcmp(cp = rlink(name), s->slink)) {
02326 LABEL;
02327 (void) printf(_("%s%s expected %s found %s\n"), tab, "link_ref",
02328 cp, s->slink);
02329 }
02330 #if defined(HAVE_ST_FLAGS)
02331 if (KF_ISSET(keys, FLAGS) && s->sb.st_flags != st->st_flags) {
02332 char *fflags;
02333
02334 LABEL;
02335 fflags = fflagstostr(s->sb.st_flags);
02336 (void) printf(_("%s%s expected \"%s\""), tab, "flags", fflags);
02337 fflags = _free(fflags);
02338
02339 fflags = fflagstostr(st->st_flags);
02340 (void) printf(_(" found \"%s\""), fflags);
02341 fflags = _free(fflags);
02342
02343 if (MF_ISSET(UPDATE)) {
02344 if (chflags(fts_accpath, s->sb.st_flags))
02345 (void) printf(" not modified: %s)\n", strerror(errno));
02346 else
02347 (void) printf(" modified)\n");
02348 }
02349 } else {
02350 (void) printf("\n");
02351 tab = "\t";
02352 }
02353 #endif
02354 return label;
02355 }
02356
02357
02358
02359 #define _FTSCALLOC(_p, _n) \
02360 if ((_n) > 0) { \
02361 (_p) = _free(_p); (_p) = xcalloc((_n), sizeof(*(_p))); \
02362 }
02363
02364 static int
02365 mtreeVisitD(rpmfts fts)
02366
02367
02368 {
02369 enum mtreeKeys_e keys = fts->keys;
02370 const FTSENT *const parent = fts->p;
02371 const FTSENT * p;
02372 struct stat sb;
02373 gid_t maxgid = 0;
02374 uid_t maxuid = 0;
02375 mode_t maxmode = 0;
02376 #if defined(HAVE_ST_FLAGS)
02377 unsigned long maxflags = 0;
02378 #endif
02379
02380
02381 if ((p = Fts_children(fts->t, 0)) == NULL) {
02382 if (errno)
02383 mtree_error("%s: %s", SKIPDOTSLASH(parent->fts_path),
02384 strerror(errno));
02385 return 1;
02386 }
02387
02388 sb = fts->sb;
02389 _FTSCALLOC(fts->g, fts->maxg);
02390 _FTSCALLOC(fts->m, fts->maxm);
02391 _FTSCALLOC(fts->u, fts->maxu);
02392 #if defined(HAVE_ST_FLAGS)
02393 _FTSCALLOC(fts->f, fts->maxf);
02394 #endif
02395
02396
02397 for (; p != NULL; p = p->fts_link) {
02398 struct stat *const st = p->fts_statp;
02399
02400 if (MF_ISSET(DIRSONLY) || !S_ISDIR(st->st_mode))
02401 continue;
02402
02403 if (fts->m != NULL)
02404 { mode_t st_mode = st->st_mode & MBITS;
02405 if (st_mode < fts->maxm && ++fts->m[st_mode] > maxmode) {
02406 sb.st_mode = st_mode;
02407 maxmode = fts->m[st_mode];
02408 }
02409 }
02410 if (fts->g != NULL)
02411 if (st->st_gid < fts->maxg && ++fts->g[st->st_gid] > maxgid) {
02412 sb.st_gid = st->st_gid;
02413 maxgid = fts->g[st->st_gid];
02414 }
02415 if (fts->u != NULL)
02416 if (st->st_uid < fts->maxu && ++fts->u[st->st_uid] > maxuid) {
02417 sb.st_uid = st->st_uid;
02418 maxuid = fts->u[st->st_uid];
02419 }
02420 #if defined(HAVE_ST_FLAGS)
02421
02422
02423
02424
02425
02426
02427 #define FLAGS2IDX(f) ((f & 0xf) | ((f >> 12) & 0xf0))
02428 if (fts->f != NULL)
02429 { unsigned long st_flags = FLAGS2IDX(st->st_flags);
02430 if (st_flags < fts->maxf && ++fts->f[st_flags] > maxflags) {
02431
02432 sb.st_flags = st->st_flags;
02433 maxflags = fts->f[st_flags];
02434 }
02435 }
02436 #endif
02437 }
02438
02439
02440
02441
02442
02443
02444 if (((KF_ISSET(keys, UNAME) || KF_ISSET(keys, UID)) && (fts->sb.st_uid != sb.st_uid))
02445 || ((KF_ISSET(keys, GNAME) || KF_ISSET(keys, GID)) && (fts->sb.st_gid != sb.st_gid))
02446 || (KF_ISSET(keys, MODE) && (fts->sb.st_mode != sb.st_mode))
02447 #if defined(HAVE_ST_FLAGS)
02448 || (KF_ISSET(keys, FLAGS) && (fts->sb.st_flags != sb.st_flags))
02449 #endif
02450 || fts->sb_is_valid == 0)
02451 {
02452 fts->sb_is_valid = 1;
02453 if (MF_ISSET(DIRSONLY))
02454 (void) printf("/set type=dir");
02455 else
02456 (void) printf("/set type=file");
02457 if (KF_ISSET(keys, UNAME)) {
02458 const char * uname = uidToUname(sb.st_uid);
02459 if (uname != NULL)
02460 (void) printf(" uname=%s", uname);
02461 else if (MF_ISSET(WARN))
02462 fprintf(stderr, _("%s: Could not get uname for uid=%lu\n"),
02463 __progname, (unsigned long) sb.st_uid);
02464 else
02465 mtree_error("could not get uname for uid=%lu",
02466 (unsigned long)sb.st_uid);
02467 }
02468 if (KF_ISSET(keys, UID))
02469 (void) printf(" uid=%lu", (unsigned long)sb.st_uid);
02470 if (KF_ISSET(keys, GNAME)) {
02471 const char * gname = gidToGname(sb.st_gid);
02472 if (gname != NULL)
02473 (void) printf(" gname=%s", gname);
02474 else if (MF_ISSET(WARN))
02475 fprintf(stderr, _("%s: Could not get gname for gid=%lu\n"),
02476 __progname, (unsigned long) sb.st_gid);
02477 else
02478 mtree_error("could not get gname for gid=%lu",
02479 (unsigned long) sb.st_gid);
02480 }
02481 if (KF_ISSET(keys, GID))
02482 (void) printf(" gid=%lu", (unsigned long)sb.st_gid);
02483 if (KF_ISSET(keys, MODE))
02484 (void) printf(" mode=%#o", (unsigned)sb.st_mode);
02485 if (KF_ISSET(keys, NLINK))
02486 (void) printf(" nlink=1");
02487 #if defined(HAVE_ST_FLAGS)
02488 if (KF_ISSET(keys, FLAGS)) {
02489 const char * fflags = flags_to_string(sb.st_flags);
02490 (void) printf(" flags=%s", fflags);
02491 fflags = _free(fflags);
02492 }
02493 #endif
02494 (void) printf("\n");
02495 fts->sb = sb;
02496 }
02497 return (0);
02498 }
02499
02500 #define CWALKINDENTNAMELEN 15
02501 #define MAXLINELEN 80
02502
02503
02504 static void
02505 output(int indent, int * offset, const char * fmt, ...)
02506
02507
02508 {
02509 char buf[1024];
02510 va_list ap;
02511
02512 va_start(ap, fmt);
02513 (void) vsnprintf(buf, sizeof(buf), fmt, ap);
02514 va_end(ap);
02515
02516 if (*offset + strlen(buf) > MAXLINELEN - 3) {
02517 (void)printf(" \\\n%*s", CWALKINDENTNAMELEN + indent, "");
02518 *offset = CWALKINDENTNAMELEN + indent;
02519 }
02520 *offset += printf(" %s", buf) + 1;
02521 }
02522
02523 static void
02524 mtreeVisitF(rpmfts fts)
02525
02526
02527 {
02528 enum mtreeKeys_e keys = fts->keys;
02529 const char * fts_accpath = fts->p->fts_accpath;
02530 unsigned short fts_info = fts->p->fts_info;
02531 struct stat *const st = fts->p->fts_statp;
02532 int indent = (MF_ISSET(INDENT) ? fts->p->fts_level * 4 : 0);
02533 int offset;
02534
02535 { const char * fts_name = fts->p->fts_name;
02536 size_t fts_namelen = fts->p->fts_namelen;
02537 char * escname;
02538
02539
02540 if (fts->p->fts_level == 0 && fts_namelen == 0) {
02541 fts_name = ".";
02542 fts_namelen = sizeof(".") - 1;
02543 }
02544
02545 escname = xmalloc(fts_namelen * 4 + 1);
02546
02547 (void) strvis(escname, fts_name, VIS_WHITE | VIS_OCTAL);
02548
02549 if (MF_ISSET(INDENT) || S_ISDIR(st->st_mode))
02550 offset = printf("%*s%s", indent, "", escname);
02551 else
02552 offset = printf("%*s %s", indent, "", escname);
02553 escname = _free(escname);
02554 }
02555
02556 if (offset > (CWALKINDENTNAMELEN + indent))
02557 offset = MAXLINELEN;
02558 else
02559 offset += printf("%*s", (CWALKINDENTNAMELEN + indent) - offset, "");
02560
02561 if (!S_ISREG(st->st_mode) && !MF_ISSET(DIRSONLY))
02562 output(indent, &offset, "type=%s", inotype(st->st_mode));
02563 if (st->st_uid != fts->sb.st_uid) {
02564 if (KF_ISSET(keys, UNAME)) {
02565 const char * uname = uidToUname(st->st_uid);
02566 if (uname != NULL)
02567 output(indent, &offset, "uname=%s", uname);
02568 else if (MF_ISSET(WARN))
02569 fprintf(stderr, _("%s: Could not get uname for uid=%lu\n"),
02570 __progname, (unsigned long) st->st_uid);
02571 else
02572 mtree_error("could not get uname for uid=%lu",
02573 (unsigned long)st->st_uid);
02574 }
02575 if (KF_ISSET(keys, UID))
02576 output(indent, &offset, "uid=%u", st->st_uid);
02577 }
02578 if (st->st_gid != fts->sb.st_gid) {
02579 if (KF_ISSET(keys, GNAME)) {
02580 const char * gname = gidToGname(st->st_gid);
02581 if (gname != NULL)
02582 output(indent, &offset, "gname=%s", gname);
02583 else if (MF_ISSET(WARN))
02584 fprintf(stderr, _("%s: Could not get gname for gid=%lu\n"),
02585 __progname, (unsigned long) st->st_gid);
02586 else
02587 mtree_error("Could not get gname for gid=%lu",
02588 (unsigned long) st->st_gid);
02589 }
02590 if (KF_ISSET(keys, GID))
02591 output(indent, &offset, "gid=%lu", (unsigned long)st->st_gid);
02592 }
02593 if (KF_ISSET(keys, MODE) && (st->st_mode & MBITS) != fts->sb.st_mode)
02594 output(indent, &offset, "mode=%#o", (st->st_mode & MBITS));
02595 if (KF_ISSET(keys, NLINK) && st->st_nlink != 1)
02596 output(indent, &offset, "nlink=%lu", (unsigned long)st->st_nlink);
02597 if (KF_ISSET(keys, SIZE) && S_ISREG(st->st_mode))
02598 output(indent, &offset, "size=%llu", (unsigned long long)st->st_size);
02599 if (KF_ISSET(keys, TIME)) {
02600 struct timeval tv;
02601 #if defined(TIMESPEC_TO_TIMEVAL)
02602 TIMESPEC_TO_TIMEVAL(&tv, &st->st_mtimespec);
02603 #else
02604 tv.tv_sec = (long)st->st_mtime;
02605 tv.tv_usec = 0L;
02606 #endif
02607 output(indent, &offset, "time=%lu.%lu",
02608 (unsigned long) tv.tv_sec,
02609 (unsigned long) tv.tv_usec);
02610 }
02611
02612
02613 if (S_ISREG(st->st_mode)) {
02614
02615
02616 if (KF_ISSET(keys, CKSUM) || fts->algos != NULL) {
02617 FD_t fd = Fopen(fts_accpath, "r.ufdio");
02618 uint32_t len, val;
02619 int i;
02620
02621 if (fd == NULL || Ferror(fd)) {
02622 #ifdef NOTYET
02623 (void) fprintf(stderr, _("%s: %s: cksum: %s\n"),
02624 __progname, fts_accpath, Fstrerror(fd));
02625 goto cleanup;
02626 #else
02627 mtree_error("%s: %s", fts_accpath, Fstrerror(fd));
02628
02629 #endif
02630 }
02631
02632
02633 if (fts->algos != NULL)
02634 for (i = fts->algos->nvals; i-- > 0;)
02635 fdInitDigest(fd, fts->algos->vals[i], 0);
02636
02637
02638 if (KF_ISSET(keys, CKSUM))
02639 i = crc(fd, &val, &len);
02640 else {
02641 char buffer[16 * 1024];
02642 while (Fread(buffer, sizeof(buffer[0]), sizeof(buffer), fd) > 0)
02643 {};
02644 i = (Ferror(fd) ? 1 : 0);
02645 }
02646 if (i) {
02647 #ifdef NOTYET
02648 (void) fprintf(stderr, _("%s: %s: cksum: %s\n"),
02649 __progname, fts_accpath, Fstrerror(fd));
02650 #else
02651 mtree_error("%s: %s", fts_accpath, Fstrerror(fd));
02652
02653 #endif
02654 goto cleanup;
02655 }
02656
02657
02658 if (KF_ISSET(keys, CKSUM)) {
02659 output(indent, &offset, "cksum=%lu", (unsigned long)val);
02660 }
02661
02662
02663 if (fts->algos != NULL)
02664 for (i = 0; i < (int) fts->algos->nvals; i++) {
02665 static int asAscii = 1;
02666 const char * digest = NULL;
02667 size_t digestlen = 0;
02668 uint32_t algo;
02669
02670 algo = fts->algos->vals[i];
02671 fdFiniDigest(fd, algo, &digest, &digestlen, asAscii);
02672 #ifdef NOTYET
02673 assert(digest != NULL);
02674 #else
02675 if (digest == NULL)
02676 mtree_error("%s: %s", fts_accpath, Fstrerror(fd));
02677 #endif
02678 { const char * tagname = algo2tagname(algo);
02679 if (tagname != NULL)
02680 output(indent, &offset, "%s=%s", tagname, digest);
02681 }
02682 digest = _free(digest);
02683 digestlen = 0;
02684 }
02685
02686 cleanup:
02687 if (fd != NULL) {
02688 (void) rpmswAdd(&dc_readops, fdstat_op(fd, FDSTAT_READ));
02689 (void) rpmswAdd(&dc_digestops, fdstat_op(fd, FDSTAT_DIGEST));
02690 (void) Fclose(fd);
02691 fd = NULL;
02692 }
02693 }
02694 }
02695
02696 if (KF_ISSET(keys, SLINK) && (fts_info == FTS_SL || fts_info == FTS_SLNONE))
02697 {
02698 const char * name = rlink(fts_accpath);
02699 char * escname = xmalloc(strlen(name) * 4 + 1);
02700 (void) strvis(escname, name, VIS_WHITE | VIS_OCTAL);
02701 output(indent, &offset, "link=%s", escname);
02702 escname = _free(escname);
02703 }
02704
02705 if (KF_ISSET(keys, FLAGS) && !S_ISLNK(st->st_mode)) {
02706 #if defined(HAVE_ST_FLAGS)
02707 char * fflags = fflagstostr(st->st_flags);
02708
02709 if (fflags != NULL && fflags[0] != '\0')
02710 output(indent, &offset, "flags=%s", fflags);
02711 else
02712 output(indent, &offset, "flags=none");
02713 free(fflags);
02714 #else
02715 output(indent, &offset, "flags=none");
02716 #endif
02717 }
02718 (void) putchar('\n');
02719 }
02720
02721
02722
02723
02724
02725
02726
02727
02728
02729
02730
02731
02732
02733
02734
02735
02736
02737
02738
02739
02740
02741
02742
02743
02744
02745
02746
02747
02748
02749
02750
02751
02752
02753
02754
02755
02756
02757
02758 static void
02759 mtreeReadExcludes(const char * fn)
02760
02761
02762 {
02763 FD_t fd = Fopen(fn, "r.fpio");
02764 FILE *fp;
02765 char buffer[16 * 1024];
02766
02767 if (fd == NULL || Ferror(fd) || (fp = fdGetFILE(fd)) == NULL) {
02768 fprintf(stderr, _("%s: open of %s failed: %s\n"), __progname,
02769 fn, Fstrerror(fd));
02770 if (fd != NULL) (void) Fclose(fd);
02771 exit(EXIT_FAILURE);
02772 }
02773
02774 while (fgets(buffer, (int)sizeof(buffer), fp) != NULL) {
02775 struct exclude *e;
02776 char * line;
02777 size_t len;
02778
02779 buffer[sizeof(buffer)-1] = '\0';
02780 for (line = buffer; *line != '\0'; line++)
02781 if (strchr(" \t\n\r", line[1]) == NULL) break;
02782 if (*line == '\0' || *line == '#')
02783 continue;
02784 for (len = strlen(line); len > 0; len--)
02785 if (strchr(" \t\n\r", line[len-1]) == NULL) break;
02786 if (len == 0)
02787 continue;
02788
02789 e = xmalloc(sizeof(*e));
02790 e->glob = xstrdup(line);
02791 e->pathname = (strchr(line, '/') != NULL ? 1 : 0);
02792
02793 RPM_LIST_INSERT_HEAD(&excludes, e, link);
02794
02795 }
02796 if (fd != NULL)
02797 (void) Fclose(fd);
02798
02799 return;
02800
02801 }
02802
02803 static int
02804 mtreeCheckExcludes(const char *fname, const char *path)
02805
02806 {
02807 struct exclude *e;
02808
02809
02810 #define MATCH(g, n) (fnmatch((g), (n), FNM_PATHNAME) == 0)
02811
02812
02813 RPM_LIST_FOREACH(e, &excludes, link) {
02814 if ((e->pathname && MATCH(e->glob, path)) || MATCH(e->glob, fname))
02815 return 1;
02816 }
02817
02818 return 0;
02819 }
02820
02821
02822
02823 static int
02824 dsort(const FTSENT ** a, const FTSENT ** b)
02825
02826 {
02827 if (S_ISDIR((*a)->fts_statp->st_mode)) {
02828 if (!S_ISDIR((*b)->fts_statp->st_mode))
02829 return 1;
02830 } else if (S_ISDIR((*b)->fts_statp->st_mode))
02831 return -1;
02832 return strcmp((*a)->fts_name, (*b)->fts_name);
02833 }
02834
02835 #if defined(_RPMFI_INTERNAL)
02836
02842 static int chkSuffix(const char * fn, const char * suffix)
02843
02844 {
02845 size_t flen = strlen(fn);
02846 size_t slen = strlen(suffix);
02847 return (flen > slen && !strcmp(fn + flen - slen, suffix));
02848 }
02849
02850 static int _rpmfiStat(const char * path, struct stat * st)
02851
02852
02853 {
02854 rpmfts fts = _rpmfts;
02855 rpmfi fi = _rpmfts->fi;
02856 size_t len = strlen(fts->paths[0]);
02857 int rc;
02858
02859 rc = rpmfiStat(fi, path+len, st);
02860
02861 if (_fts_debug)
02862 fprintf(stderr, "*** _rpmfiStat(%s, %p) fi %p rc %d\n", path+len, st, fi, rc);
02863
02864 return rc;
02865 }
02866
02867 static int _rpmfiClosedir( DIR * dir)
02868
02869
02870 {
02871 rpmfi fi = _rpmfts->fi;
02872
02873 if (_fts_debug)
02874 fprintf(stderr, "*** _rpmfiClosedir(%p) fi %p\n", dir, fi);
02875
02876 return avClosedir(dir);
02877 }
02878
02879 static struct dirent * _rpmfiReaddir(DIR * dir)
02880
02881
02882 {
02883 rpmfi fi = _rpmfts->fi;
02884 struct dirent * dp = (struct dirent *) avReaddir(dir);
02885
02886 if (_fts_debug)
02887 fprintf(stderr, "*** _rpmfiReaddir(%p) fi %p %p \"%s\"\n", dir, fi, dp, (dp != NULL ? dp->d_name : ""));
02888
02889
02890 return dp;
02891
02892 }
02893
02894 static
02895 uint8_t * rpmfiParentDirNotWithin(rpmfi fi)
02896
02897 {
02898 size_t * dnlens = xmalloc(fi->dc * sizeof(*dnlens));
02899 uint8_t * noparent = memset(xmalloc(fi->dc), 1, fi->dc);
02900 int i, j;
02901
02902 for (i = 0; i < (int)fi->dc; i++)
02903 dnlens[i] = strlen(fi->dnl[i]);
02904
02905
02906 for (i = 0; i < (int)fi->fc; i++) {
02907 size_t dnlen, bnlen;
02908
02909 if (!S_ISDIR(fi->fmodes[i]))
02910 continue;
02911
02912 dnlen = dnlens[fi->dil[i]];
02913 bnlen = strlen(fi->bnl[i]);
02914
02915 for (j = 0; j < (int)fi->dc; j++) {
02916
02917 if (!noparent[j] || j == (int)fi->dil[i])
02918 continue;
02919 if (dnlens[j] != (dnlen+bnlen+1))
02920 continue;
02921 if (strncmp(fi->dnl[j], fi->dnl[fi->dil[i]], dnlen))
02922 continue;
02923 if (strncmp(fi->dnl[j]+dnlen, fi->bnl[i], bnlen))
02924 continue;
02925 if (fi->dnl[j][dnlen+bnlen] != '/' || fi->dnl[j][dnlen+bnlen+1] != '\0')
02926 continue;
02927
02928
02929 noparent[j] = (uint8_t)0;
02930 break;
02931 }
02932 }
02933 dnlens = _free(dnlens);
02934 return noparent;
02935 }
02936
02937 static Header rpmftsReadHeader(rpmfts fts, const char * path)
02938
02939
02940 {
02941 FD_t fd = Fopen(path, "r.ufdio");
02942 Header h = NULL;
02943
02944 if (fd != NULL) {
02945
02946 rpmRC rpmrc = rpmReadPackageFile(fts->ts, fd, path, &h);
02947
02948 (void) Fclose(fd);
02949
02950 switch (rpmrc) {
02951 case RPMRC_NOTFOUND:
02952
02953 case RPMRC_FAIL:
02954 default:
02955 (void)headerFree(h);
02956 h = NULL;
02957 break;
02958 case RPMRC_NOTTRUSTED:
02959 case RPMRC_NOKEY:
02960 case RPMRC_OK:
02961 break;
02962 }
02963 }
02964 return h;
02965 }
02966
02967 static rpmfi rpmftsLoadFileInfo(rpmfts fts, const char * path)
02968
02969
02970 {
02971 char * fn = xstrdup(path);
02972 size_t nb = strlen(fn);
02973 Header h = NULL;
02974
02975 fn[nb-1] = '\0';
02976 h = rpmftsReadHeader(fts, fn);
02977 fn = _free(fn);
02978
02979 if (h != NULL) {
02980 fts->fi = rpmfiNew(fts->ts, h, RPMTAG_BASENAMES, 0);
02981 (void)headerFree(h);
02982 h = NULL;
02983 }
02984 return fts->fi;
02985 }
02986
02987 static DIR * _rpmfiOpendir(const char * path)
02988
02989
02990
02991
02992 {
02993 rpmfts fts = _rpmfts;
02994 DIR * dir = NULL;
02995
02996 if (fts->ts == NULL)
02997 fts->ts = rpmtsCreate();
02998
02999 if (fts->fi == NULL) {
03000 rpmfi fi = rpmftsLoadFileInfo(fts, path);
03001 uint8_t * noparent = rpmfiParentDirNotWithin(fi);
03002 uint16_t * fmodes = xcalloc(rpmfiFC(fi)+1, sizeof(*fmodes));
03003 const char ** fnames = NULL;
03004 int ac = 0;
03005 int i;
03006
03007
03008 fi = rpmfiInit(fi, 0);
03009 while ((i = rpmfiNext(fi)) >= 0) {
03010 int xx;
03011 if (!S_ISDIR(fi->fmodes[i]) && !noparent[fi->dil[i]])
03012 continue;
03013 xx = argvAdd(&fnames, rpmfiFN(fi));
03014 fmodes[ac++] = fi->fmodes[i];
03015 }
03016
03017 dir = (DIR *) avOpendir(path, fnames, fmodes);
03018
03019 fnames = argvFree(fnames);
03020 fmodes = _free(fmodes);
03021 noparent = _free(noparent);
03022
03023 } else {
03024 const char * dn = path + strlen(fts->paths[0]);
03025
03026 dir = rpmfiOpendir(fts->fi, dn);
03027 }
03028
03029 if (_fts_debug)
03030 fprintf(stderr, "*** _rpmfiOpendir(%s) dir %p\n", path, dir);
03031
03032 return dir;
03033 }
03034
03035 #define ALIGNBYTES (__alignof__ (long double) - 1)
03036 #define ALIGN(p) (((unsigned long int) (p) + ALIGNBYTES) & ~ALIGNBYTES)
03037
03038 static FTSENT *
03039 fts_alloc(FTS * sp, const char * name, int namelen)
03040
03041 {
03042 register FTSENT *p;
03043 size_t len;
03044
03045
03046
03047
03048
03049
03050
03051
03052
03053 len = sizeof(*p) + namelen;
03054
03055 if (!(sp->fts_options & FTS_NOSTAT))
03056 len += sizeof(*p->fts_statp) + ALIGNBYTES;
03057
03058 p = xmalloc(len);
03059
03060
03061 memmove(p->fts_name, name, namelen);
03062 p->fts_name[namelen] = '\0';
03063
03064
03065 if (!(sp->fts_options & FTS_NOSTAT))
03066 p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2);
03067
03068 p->fts_namelen = namelen;
03069 p->fts_path = sp->fts_path;
03070 p->fts_errno = 0;
03071 p->fts_flags = 0;
03072 p->fts_instr = FTS_NOINSTR;
03073 p->fts_number = 0;
03074 p->fts_pointer = NULL;
03075 return (p);
03076 }
03077
03078 static void _rpmfiSetFts(rpmfts fts)
03079
03080
03081 {
03082 char *const * argv = (char *const *) fts->paths;
03083 FTS * sp = fts->t;
03084 #ifdef NOTYET
03085 int (*compar) (const FTSENT **, const FTSENT **) = sp->compar;
03086 #endif
03087 register FTSENT *p, *root;
03088 register int nitems;
03089 FTSENT *parent = NULL;
03090 FTSENT *tmp = NULL;
03091 size_t len;
03092
03093 if (_fts_debug)
03094 fprintf(stderr, "*** _rpmfiSetFts(%p)\n", fts);
03095
03096
03097 sp->fts_opendir = _rpmfiOpendir;
03098 sp->fts_readdir = _rpmfiReaddir;
03099 sp->fts_closedir = _rpmfiClosedir;
03100 sp->fts_stat = _rpmfiStat;
03101 sp->fts_lstat = _rpmfiStat;
03102
03103
03104
03105 if (*argv != NULL) {
03106 parent = fts_alloc(sp, "", 0);
03107 parent->fts_level = FTS_ROOTPARENTLEVEL;
03108 }
03109
03110
03111 for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
03112 len = strlen(*argv);
03113
03114 p = fts_alloc(sp, *argv, (int)len);
03115 p->fts_level = FTS_ROOTLEVEL;
03116 p->fts_parent = parent;
03117 p->fts_accpath = p->fts_name;
03118 #ifdef NOTYET
03119 p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
03120
03121
03122 if (p->fts_info == FTS_DOT)
03123 p->fts_info = FTS_D;
03124
03125 #else
03126 p->fts_name[len-1] = '\0';
03127 { struct stat * st = p->fts_statp;
03128 int xx = Stat(p->fts_accpath, st);
03129 xx = xx;
03130 st->st_mode &= ~S_IFMT;
03131 st->st_mode |= S_IFDIR;
03132 p->fts_dev = st->st_dev;
03133 p->fts_ino = st->st_ino;
03134 p->fts_nlink = st->st_nlink;
03135 }
03136 p->fts_name[len-1] = '/';
03137 p->fts_info = FTS_D;
03138 #endif
03139
03140 #ifdef NOTYET
03141
03142
03143
03144
03145 if (compar) {
03146 p->fts_link = root;
03147 root = p;
03148 } else
03149 #endif
03150 {
03151 p->fts_link = NULL;
03152 if (root == NULL)
03153 tmp = root = p;
03154 else {
03155 if (tmp != NULL)
03156 tmp->fts_link = p;
03157 tmp = p;
03158 }
03159 }
03160 }
03161 #ifdef NOTYET
03162 if (compar && nitems > 1)
03163 root = fts_sort(sp, root, nitems);
03164 #endif
03165
03166
03167
03168
03169
03170
03171 sp->fts_cur = _free(sp->fts_cur);
03172 sp->fts_cur = fts_alloc(sp, "", 0);
03173 sp->fts_cur->fts_link = root;
03174 sp->fts_cur->fts_info = FTS_INIT;
03175
03176 return;
03177 }
03178 #endif
03179
03180 int
03181 mtreeCWalk(rpmfts fts)
03182 {
03183 #if defined(_RPMFI_INTERNAL)
03184 int isrpm = chkSuffix(fts->paths[0], ".rpm/");
03185 #else
03186 int isrpm = 0;
03187 #endif
03188 const char * empty = NULL;
03189 char *const * paths = (char *const *) (isrpm ? &empty : fts->paths);
03190 int ftsoptions = fts->ftsoptions | (isrpm ? (FTS_NOCHDIR|FTS_COMFOLLOW) : 0);
03191 int rval = 0;
03192
03193 fts->t = Fts_open(paths, ftsoptions, dsort);
03194 if (fts->t == NULL)
03195 mtree_error("Fts_open: %s", strerror(errno));
03196
03197 #if defined(_RPMFI_INTERNAL)
03198 if (isrpm) {
03199 fts->keys &= ~MTREE_KEYS_SLINK;
03200 _rpmfiSetFts(fts);
03201 }
03202 #endif
03203
03204 while ((fts->p = Fts_read(fts->t)) != NULL) {
03205 int indent = 0;
03206 if (MF_ISSET(INDENT))
03207 indent = fts->p->fts_level * 4;
03208 if (mtreeCheckExcludes(fts->p->fts_name, fts->p->fts_path)) {
03209 (void) Fts_set(fts->t, fts->p, FTS_SKIP);
03210 continue;
03211 }
03212 switch(fts->p->fts_info) {
03213 case FTS_D:
03214 if (!MF_ISSET(DIRSONLY))
03215 (void) printf("\n");
03216 if (!MF_ISSET(NOCOMMENT))
03217 (void) printf("# %s\n", fts->p->fts_path);
03218 (void) mtreeVisitD(fts);
03219 mtreeVisitF(fts);
03220 break;
03221 case FTS_DP:
03222 if (!MF_ISSET(NOCOMMENT) && (fts->p->fts_level > 0))
03223 (void) printf("%*s# %s\n", indent, "", fts->p->fts_path);
03224 (void) printf("%*s..\n", indent, "");
03225 if (!MF_ISSET(DIRSONLY))
03226 (void) printf("\n");
03227 break;
03228 case FTS_DNR:
03229 case FTS_ERR:
03230 case FTS_NS:
03231 (void) fprintf(stderr, "%s: %s: %s\n", __progname,
03232 fts->p->fts_path, strerror(fts->p->fts_errno));
03233 break;
03234 default:
03235 if (!MF_ISSET(DIRSONLY))
03236 mtreeVisitF(fts);
03237 break;
03238 }
03239 }
03240 (void) Fts_close(fts->t);
03241 fts->p = NULL;
03242 fts->t = NULL;
03243 return rval;
03244 }
03245
03246
03247
03248 void
03249 mtreeMiss(rpmfts fts, NODE * p, char * tail)
03250 {
03251 int create;
03252 char *tp;
03253 const char *type;
03254
03255 for (; p != NULL; p = p->next) {
03256
03257 if (KF_ISSET(p->flags, OPT) && !KF_ISSET(p->flags, VISIT))
03258 continue;
03259 if (p->type != F_DIR && (MF_ISSET(DIRSONLY) || KF_ISSET(p->flags, VISIT)))
03260 continue;
03261 (void) strcpy(tail, p->name);
03262 if (!KF_ISSET(p->flags, VISIT)) {
03263
03264
03265 struct stat sb;
03266
03267 if (MF_ISSET(QUIET) && Stat(fts->path, &sb) == 0)
03268 p->flags |= MTREE_KEYS_VISIT;
03269 else
03270 (void) printf(_("missing: %s"), fts->path);
03271 }
03272 if (p->type != F_DIR && p->type != F_LINK) {
03273 (void) putchar('\n');
03274 continue;
03275 }
03276
03277 create = 0;
03278 type = (p->type == F_LINK ? "symlink" : "directory");
03279 if (!KF_ISSET(p->flags, VISIT) && MF_ISSET(UPDATE)) {
03280 if (!(KF_ISSET(p->flags, UID) && KF_ISSET(p->flags, UNAME)))
03281 (void) printf(_(" (%s not created: user not specified)"), type);
03282 else if (!(KF_ISSET(p->flags, GID) || KF_ISSET(p->flags, GNAME)))
03283 (void) printf(_(" (%s not created: group not specified))"), type);
03284 else if (p->type == F_LINK) {
03285 if (Symlink(p->slink, fts->path))
03286 (void) printf(_(" (%s not created: %s)\n"), type,
03287 strerror(errno));
03288 else
03289 (void) printf(_(" (%s created)\n"), type);
03290 if (lchown(fts->path, p->sb.st_uid, p->sb.st_gid) == -1) {
03291 const char * what;
03292 int serr = errno;
03293
03294 if (p->sb.st_uid == (uid_t)-1)
03295 what = "group";
03296 else if (lchown(fts->path, (uid_t)-1, p->sb.st_gid) == -1)
03297 what = "user & group";
03298 else {
03299 what = "user";
03300 errno = serr;
03301 }
03302 (void) printf(_("%s: %s not modified: %s\n"),
03303 fts->path, what, strerror(errno));
03304 }
03305 continue;
03306 } else if (!KF_ISSET(p->flags, MODE))
03307 (void) printf(_(" (%s not created: mode not specified)"), type);
03308 else if (Mkdir(fts->path, S_IRWXU))
03309 (void) printf(_(" (%s not created: %s)"),type, strerror(errno));
03310 else {
03311 create = 1;
03312 (void) printf(_(" (%s created)"), type);
03313 }
03314 }
03315
03316 if (!KF_ISSET(p->flags, VISIT))
03317 (void) putchar('\n');
03318
03319 for (tp = tail; *tp != '\0'; ++tp);
03320 *tp = '/';
03321 mtreeMiss(fts, p->child, tp + 1);
03322 *tp = '\0';
03323
03324 if (!create)
03325 continue;
03326 if (Chown(fts->path, p->sb.st_uid, p->sb.st_gid)) {
03327 const char * what;
03328 int serr = errno;
03329
03330 if (p->sb.st_uid == (uid_t)-1)
03331 what = "group";
03332 else if (Chown(fts->path, (uid_t)-1, p->sb.st_gid) == -1)
03333 what = "user & group";
03334 else {
03335 what = "user";
03336 errno = serr;
03337 }
03338 (void) printf(_("%s: %s not modified: %s\n"),
03339 fts->path, what, strerror(errno));
03340 continue;
03341 }
03342 if (Chmod(fts->path, p->sb.st_mode))
03343 (void) printf(_("%s: permissions not set: %s\n"),
03344 fts->path, strerror(errno));
03345 #if defined(HAVE_ST_FLAGS)
03346 if (KF_ISSET(p->flags, FLAGS) && p->sb.st_flags != 0 &&
03347 chflags(fts->path, p->sb.st_flags))
03348 (void) printf(_("%s: file flags not set: %s\n"),
03349 fts->path, strerror(errno));
03350 #endif
03351 }
03352 }
03353
03354 int
03355 mtreeVWalk(rpmfts fts)
03356 {
03357 #if defined(_RPMFI_INTERNAL)
03358 int isrpm = chkSuffix(fts->paths[0], ".rpm/");
03359 #else
03360 int isrpm = 0;
03361 #endif
03362 const char * empty = NULL;
03363 char *const * paths = (char *const *) (isrpm ? &empty : fts->paths);
03364 int ftsoptions = fts->ftsoptions | (isrpm ? (FTS_NOCHDIR|FTS_COMFOLLOW) : 0);
03365 NODE * level = NULL;
03366 NODE * root = NULL;
03367 int specdepth = 0;
03368 int rval = 0;
03369
03370 fts->t = Fts_open((char *const *)paths, ftsoptions, NULL);
03371 if (fts->t == NULL)
03372 mtree_error("Fts_open: %s", strerror(errno));
03373
03374 #if defined(_RPMFI_INTERNAL)
03375 if (isrpm) {
03376 fts->keys &= ~MTREE_KEYS_SLINK;
03377 _rpmfiSetFts(fts);
03378 }
03379 #endif
03380
03381 while ((fts->p = Fts_read(fts->t)) != NULL) {
03382 const char * fts_name = fts->p->fts_name;
03383 size_t fts_namelen = fts->p->fts_namelen;
03384
03385 #if 0
03386 fprintf(stderr, "==> level %d info 0x%x name %p[%d] \"%s\" accpath \"%s\" path \"%s\"\n", fts->p->fts_level, fts->p->fts_info, fts_name, fts_namelen, fts_name, fts->p->fts_accpath, fts->p->fts_path);
03387 #endif
03388
03389 if (fts->p->fts_level == 0 && fts_namelen == 0) {
03390 fts_name = ".";
03391 fts_namelen = sizeof(".") - 1;
03392 }
03393
03394 if (mtreeCheckExcludes(fts_name, fts->p->fts_path)) {
03395 (void) Fts_set(fts->t, fts->p, FTS_SKIP);
03396 continue;
03397 }
03398 switch(fts->p->fts_info) {
03399 case FTS_D:
03400 case FTS_SL:
03401 if (fts->p->fts_level == 0) {
03402 assert(specdepth == 0);
03403 if (root == NULL)
03404 level = root = fts->root;
03405 else if (root->next != fts->root)
03406 level = root = root->next;
03407 assert(level == level->parent);
03408 }
03409 break;
03410 case FTS_DP:
03411 if (specdepth > fts->p->fts_level) {
03412 for (level = level->parent; level->prev != NULL; level = level->prev);
03413 --specdepth;
03414 }
03415 continue;
03416 case FTS_DNR:
03417 case FTS_ERR:
03418 case FTS_NS:
03419 (void) fprintf(stderr, "%s: %s: %s\n", __progname,
03420 SKIPDOTSLASH(fts->p->fts_path),
03421 strerror(fts->p->fts_errno));
03422 continue;
03423 default:
03424 if (MF_ISSET(DIRSONLY))
03425 continue;
03426 }
03427
03428 if (specdepth == fts->p->fts_level) {
03429 NODE *ep;
03430 for (ep = level; ep != NULL; ep = ep->next)
03431 if ((KF_ISSET(ep->flags, MAGIC) &&
03432
03433 !fnmatch(ep->name, fts_name, FNM_PATHNAME)) ||
03434
03435 !strcmp(ep->name, fts_name))
03436 {
03437 ep->flags |= MTREE_KEYS_VISIT;
03438 if (!KF_ISSET(ep->flags, NOCHANGE) &&
03439 compare(fts, ep))
03440 rval = MISMATCHEXIT;
03441 if (KF_ISSET(ep->flags, IGN))
03442 (void) Fts_set(fts->t, fts->p, FTS_SKIP);
03443 else
03444 if (ep->child && ep->type == F_DIR && fts->p->fts_info == FTS_D)
03445 {
03446 level = ep->child;
03447 ++specdepth;
03448 }
03449 break;
03450 }
03451 if (ep != NULL)
03452 continue;
03453 }
03454
03455 if (!MF_ISSET(IGNORE)) {
03456 (void) printf("%s extra", SKIPDOTSLASH(fts->p->fts_path));
03457 if (MF_ISSET(REMOVE)) {
03458 if ((S_ISDIR(fts->p->fts_statp->st_mode)
03459 ? Rmdir : Unlink)(fts->p->fts_accpath)) {
03460 (void) printf(_(", not removed: %s"), strerror(errno));
03461 } else
03462 (void) printf(_(", removed"));
03463 }
03464 (void) putchar('\n');
03465 }
03466 (void) Fts_set(fts->t, fts->p, FTS_SKIP);
03467 }
03468 (void) Fts_close(fts->t);
03469 fts->p = NULL;
03470 fts->t = NULL;
03471 return rval;
03472 }
03473
03474
03475
03478 static void mtreeArgCallback(poptContext con,
03479 enum poptCallbackReason reason,
03480 const struct poptOption * opt, const char * arg,
03481 void * data)
03482
03483
03484 {
03485 char * p;
03486
03487
03488 if (opt->arg == NULL)
03489 switch (opt->val) {
03490
03491 case 'f':
03492 if (_rpmfts->spec1 == NULL) {
03493 if ((_rpmfts->spec1 = fopen(arg, "r")) != NULL)
03494 mtree_error("%s: %s", arg, strerror(errno));
03495 } else if (_rpmfts->spec2 == NULL) {
03496 if ((_rpmfts->spec2 = fopen(arg, "r")) != NULL)
03497 mtree_error("%s: %s", arg, strerror(errno));
03498 } else {
03499
03500 poptPrintUsage(con, stderr, 0);
03501 exit(EXIT_FAILURE);
03502
03503 }
03504 break;
03505 case 'k':
03506
03507 _rpmfts->keys = MTREE_KEYS_TYPE;
03508
03509 case 'K':
03510
03511 while ((p = strsep((char **)&arg, " \t,")) != NULL) {
03512 uint32_t needvalue;
03513 enum mtreeKeys_e type = parsekey(p, &needvalue);
03514 if (type == 0) {
03515
03516 continue;
03517 }
03518 _rpmfts->keys |= type;
03519
03520 if (KF_ISSET(_rpmfts->keys, DIGEST) && needvalue)
03521 (void) argiAdd(&_rpmfts->algos, -1, (int)needvalue);
03522 }
03523
03524 break;
03525
03526
03527 case 'L':
03528 rpmioFtsOpts &= ~FTS_PHYSICAL;
03529 rpmioFtsOpts |= FTS_LOGICAL;
03530 break;
03531
03532 case 'P':
03533 rpmioFtsOpts &= ~FTS_LOGICAL;
03534 rpmioFtsOpts |= FTS_PHYSICAL;
03535 break;
03536 case 'X':
03537 mtreeReadExcludes(arg);
03538 break;
03539
03540 case '?':
03541 default:
03542 fprintf(stderr, _("%s: Unknown option -%c\n"), __progname, opt->val);
03543 poptPrintUsage(con, stderr, 0);
03544 exit(EXIT_FAILURE);
03545 break;
03546 }
03547 }
03548
03549
03550 static struct poptOption optionsTable[] = {
03551
03552 { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA | POPT_CBFLAG_CONTINUE,
03553 mtreeArgCallback, 0, NULL, NULL },
03554
03555
03556
03557 { NULL,'L', POPT_ARG_NONE, NULL, (int)'L',
03558 N_("Follow symlinks"), NULL },
03559
03560 { NULL,'P', POPT_ARG_NONE, NULL, (int)'P',
03561 N_("Don't follow symlinks"), NULL },
03562 { NULL,'X', POPT_ARG_NONE, NULL, (int)'X',
03563 N_("Read fnmatch(3) exclude patterns from <file>"), N_("<file>") },
03564
03565 { "create",'c', POPT_BIT_SET, &mtreeFlags, MTREE_FLAGS_CREATE,
03566 N_("Print file tree specification to stdout"), NULL },
03567 { "dirs",'d', POPT_BIT_SET, &mtreeFlags, MTREE_FLAGS_DIRSONLY,
03568 N_("Directories only"), NULL },
03569 { "ignore",'e', POPT_BIT_SET, &mtreeFlags, MTREE_FLAGS_IGNORE,
03570 N_("Don't complain about files not in the specification"), NULL },
03571 { "file",'f', POPT_ARG_STRING, NULL, (int)'f',
03572 N_("Read file tree <spec>"), N_("<spec>") },
03573 { "indent",'i', POPT_BIT_SET, &mtreeFlags, MTREE_FLAGS_INDENT,
03574 N_("Indent sub-directories"), NULL },
03575 { "add",'K', POPT_ARG_STRING, NULL, (int)'K',
03576 N_("Add <key> to specification"), N_("<key>") },
03577 { "key",'k', POPT_ARG_STRING, NULL, (int)'k',
03578 N_("Use \"type\" keywords instead"), N_("<key>") },
03579 { "loose",'l', POPT_BIT_SET, &mtreeFlags, MTREE_FLAGS_LOOSE,
03580 N_("Loose permissions check"), NULL },
03581 { "nocomment",'n', POPT_BIT_SET, &mtreeFlags, MTREE_FLAGS_NOCOMMENT,
03582 N_("Don't include sub-directory comments"), NULL },
03583 { "path",'p', POPT_ARG_ARGV, &__rpmfts.paths, 0,
03584 N_("Use <path> rather than current directory"), N_("<path>") },
03585
03586 { "quiet",'q', POPT_BIT_SET, &mtreeFlags, MTREE_FLAGS_QUIET,
03587 N_("Quiet mode"), NULL },
03588 { "remove",'r', POPT_BIT_SET, &mtreeFlags, MTREE_FLAGS_REMOVE,
03589 N_("Remove files not in specification"), NULL },
03590 { "seed",'s', POPT_ARG_INT, &__rpmfts.crc_total, 0,
03591 N_("Display crc for file(s) with <seed>"), N_("<seed>") },
03592 { "touch",'t', POPT_BIT_SET, &mtreeFlags, MTREE_FLAGS_TOUCH,
03593 N_("Touch files iff timestamp differs"), NULL },
03594 { "update",'u', POPT_BIT_SET, &mtreeFlags, MTREE_FLAGS_UPDATE,
03595 N_("Update owner/group/permissions to match specification"), NULL },
03596 { "mismatch",'U', POPT_BIT_SET, &mtreeFlags, (MTREE_FLAGS_UPDATE|MTREE_FLAGS_MISMATCHOK),
03597 N_("Same as -u, but ignore match status on exit"), NULL },
03598 { "warn",'w', POPT_BIT_SET, &mtreeFlags, MTREE_FLAGS_WARN,
03599 N_("Treat missing uid/gid as warning"), NULL },
03600
03601 { "xdev",'x', POPT_BIT_SET, &rpmioFtsOpts, FTS_XDEV,
03602 N_("Don't cross mount points"), NULL },
03603
03604 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioFtsPoptTable, 0,
03605 N_("Fts(3) traversal options:"), NULL },
03606
03607 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioDigestPoptTable, 0,
03608 N_("Available digests:"), NULL },
03609
03610 { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioAllPoptTable, 0,
03611 N_("Common options for all rpmio executables:"),
03612 NULL },
03613
03614 POPT_AUTOALIAS
03615 POPT_AUTOHELP
03616
03617 { NULL, (char)-1, POPT_ARG_INCLUDE_TABLE, NULL, 0,
03618 "\
03619 Usage: mtree [-cdeilnqrtUux] [-f spec] [-K key] [-k key] [-p path] [-s seed]\n\
03620 ", NULL },
03621
03622 POPT_TABLEEND
03623 };
03624
03625 #if defined(__linux__)
03626
03627 static const char *my_getlogin(void)
03628
03629
03630 {
03631 const char *s = getlogin();
03632
03633 if (s && *s) {
03634 return (char *) s;
03635 } else {
03636 struct passwd *pw = getpwuid(geteuid());
03637 char *ss = NULL;
03638
03639 if (pw != NULL && pw->pw_name != NULL && pw->pw_name[0] != '\0') {
03640 if (asprintf(&ss, _("(no controlling terminal) %s"), pw->pw_name) < 0) {
03641 perror("asprintf");
03642 return NULL;
03643 }
03644 } else {
03645 if (asprintf(&ss, _("(no controlling terminal) #%d"), geteuid()) < 0) {
03646 perror("asprintf");
03647 return NULL;
03648 }
03649 }
03650
03651 return ss;
03652 }
03653 }
03654 #define __getlogin my_getlogin
03655 #else
03656 #define __getlogin getlogin
03657 #endif
03658
03659 int
03660 main(int argc, char *argv[])
03661
03662
03663
03664
03665 {
03666 rpmfts fts = _rpmfts;
03667 poptContext optCon;
03668 int rc = 1;
03669 int i;
03670
03671 __progname = "rpmmtree";
03672
03673 RPM_LIST_INIT(&excludes);
03674 fts->keys = KEYDEFAULT;
03675 fts->maxg = 5000;
03676 fts->maxu = 5000;
03677 fts->maxm = (MBITS + 1);
03678 #if defined(HAVE_ST_FLAGS)
03679 fts->maxf = 256;
03680 fts->sb.st_flags = 0xffffffff;
03681 #endif
03682
03683
03684 optCon = rpmioInit(argc, argv, optionsTable);
03685
03686
03687 argv = (char **) poptGetArgs(optCon);
03688 if (!(argv == NULL || argv[0] == NULL)) {
03689 poptPrintUsage(optCon, stderr, 0);
03690 goto exit;
03691 }
03692
03693 if (MF_ISSET(LOOSE) && MF_ISSET(UPDATE))
03694 mtree_error("-l and -u flags are mutually exclusive");
03695
03696
03697
03698
03699
03700 fts->ftsoptions = rpmioFtsOpts;
03701 switch (fts->ftsoptions & (FTS_LOGICAL|FTS_PHYSICAL)) {
03702 case (FTS_LOGICAL|FTS_PHYSICAL):
03703 mtree_error("-L and -P flags are mutually exclusive");
03704 break;
03705 case 0:
03706 fts->ftsoptions |= FTS_PHYSICAL;
03707 break;
03708 }
03709
03710 if (fts->paths == NULL || fts->paths[0] == NULL) {
03711 fts->paths = xcalloc(2, sizeof(fts->paths[0]));
03712 fts->paths[0] = xstrdup(".");
03713 }
03714
03715
03716 for (i = 0; fts->paths[i] != NULL; i++) {
03717 char fullpath[MAXPATHLEN];
03718 struct stat sb;
03719 const char * rpath;
03720 const char * lpath = NULL;
03721 int ut = urlPath(fts->paths[i], &lpath);
03722 size_t nb = (size_t)(lpath - fts->paths[i]);
03723 int isdir = (lpath[strlen(lpath)-1] == '/');
03724
03725
03726 if (lpath[0] != '/') {
03727
03728 rpath = Realpath(lpath, NULL);
03729 if (rpath == NULL)
03730 rpath = Realpath(lpath, fullpath);
03731 if (rpath == NULL)
03732 mtree_error("Realpath(%s): %s", lpath, strerror(errno));
03733 lpath = rpmGetPath(rpath, NULL);
03734 if (rpath != fullpath)
03735 rpath = _free(rpath);
03736 } else
03737 lpath = rpmGetPath(lpath, NULL);
03738
03739
03740
03741 switch (ut) {
03742 case URL_IS_DASH:
03743 case URL_IS_UNKNOWN:
03744 rpath = lpath;
03745 lpath = NULL;
03746 break;
03747 default:
03748 strncpy(fullpath, fts->paths[i], nb);
03749 fullpath[nb] = '\0';
03750 rpath = rpmGenPath(fullpath, lpath, NULL);
03751 lpath = _free(lpath);
03752 break;
03753 }
03754
03755
03756 lpath = (isdir || (!Stat(rpath, &sb) && S_ISDIR(sb.st_mode))
03757 ? "/" : NULL);
03758 fts->paths[i] = _free(fts->paths[i]);
03759 fts->paths[i] = rpmExpand(rpath, lpath, NULL);
03760 fts->fullpath = xstrdup(fts->paths[i]);
03761 rpath = _free(rpath);
03762 }
03763
03764
03765 if (fts->crc_total)
03766 mtreeFlags |= MTREE_FLAGS_SEEDED;
03767 fts->crc_total ^= 0xffffffff;
03768
03769 (void) rpmswEnter(&dc_totalops, -1);
03770
03771 if (MF_ISSET(CREATE)) {
03772 if (!MF_ISSET(NOCOMMENT)) {
03773 time_t clock;
03774 char host[MAXHOSTNAMELEN];
03775
03776 (void) time(&clock);
03777 (void) gethostname(host, sizeof(host));
03778 (void) printf("#\t user: %s\n", __getlogin());
03779 (void) printf("#\tmachine: %s\n", host);
03780 for (i = 0; fts->paths[i] != NULL; i++)
03781 (void) printf("#\t tree: %s\n", fts->paths[i]);
03782 (void) printf("#\t date: %s", ctime(&clock));
03783 }
03784 rc = mtreeCWalk(fts);
03785 if (MF_ISSET(SEEDED) && KF_ISSET(fts->keys, CKSUM))
03786 (void) fprintf(stderr, _("%s: %s checksum: %u\n"), __progname,
03787 fts->fullpath, (unsigned)fts->crc_total);
03788
03789 } else {
03790 if (fts->spec2 != NULL) {
03791 rc = mtreeVSpec(fts);
03792 } else {
03793
03794 fts->root = mtreeSpec(fts, fts->spec1);
03795
03796 fts->path = xmalloc(MAXPATHLEN);
03797 rc = mtreeVWalk(fts);
03798 mtreeMiss(fts, fts->root, fts->path);
03799 fts->path = _free(fts->path);
03800 if (MF_ISSET(SEEDED))
03801 (void) fprintf(stderr, _("%s: %s checksum: %u\n"), __progname,
03802 fts->fullpath, (unsigned) fts->crc_total);
03803 }
03804 }
03805 if (MF_ISSET(MISMATCHOK) && (rc == MISMATCHEXIT))
03806 rc = 0;
03807
03808 (void) rpmswExit(&dc_totalops, 0);
03809 if (_rpmsw_stats) {
03810 rpmswPrint(" total:", &dc_totalops);
03811 rpmswPrint(" read:", &dc_readops);
03812 rpmswPrint("digest:", &dc_digestops);
03813 }
03814
03815 exit:
03816 #if defined(_RPMFI_INTERNAL)
03817 (void)rpmtsFree(fts->ts);
03818 fts->ts = NULL;
03819 fts->fi = rpmfiFree(fts->fi);
03820 tagClean(NULL);
03821 #endif
03822 if (fts->spec1 != NULL && fileno(fts->spec1) > 2) {
03823 (void) fclose(fts->spec1);
03824 fts->spec1 = NULL;
03825 }
03826 if (fts->spec2 != NULL && fileno(fts->spec2) > 2) {
03827 (void) fclose(fts->spec2);
03828 fts->spec2 = NULL;
03829 }
03830 fts->paths = argvFree(fts->paths);
03831 #if defined(HAVE_ST_FLAGS)
03832 fts->f = _free(fts->f);
03833 #endif
03834 fts->g = _free(fts->g);
03835 fts->m = _free(fts->m);
03836 fts->u = _free(fts->u);
03837 fts->fullpath = _free(fts->fullpath);
03838
03839
03840 optCon = rpmioFini(optCon);
03841
03842 return rc;
03843 }