Bug Summary

File:lib/fsm.c
Warning:line 1007, column 2
Value stored to 'rc' is never read

Annotated Source Code

1/** \ingroup payload
2 * \file lib/fsm.c
3 * File state machine to handle a payload from a package.
4 */
5
6#include "system.h"
7
8#include <utime.h>
9#include <errno(*__errno_location ()).h>
10#if WITH_CAP
11#include <sys/capability.h>
12#endif
13
14#include <rpm/rpmte.h>
15#include <rpm/rpmts.h>
16#include <rpm/rpmlog.h>
17
18#include "rpmio/rpmio_internal.h" /* fdInit/FiniDigest */
19#include "lib/fsm.h"
20#include "lib/rpmte_internal.h" /* XXX rpmfs */
21#include "lib/rpmplugins.h" /* rpm plugins hooks */
22#include "lib/rpmug.h"
23
24#include "debug.h"
25
26#define _FSM_DEBUG0 0
27int _fsm_debug = _FSM_DEBUG0;
28
29/* XXX Failure to remove is not (yet) cause for failure. */
30static int strict_erasures = 0;
31
32#define SUFFIX_RPMORIG".rpmorig" ".rpmorig"
33#define SUFFIX_RPMSAVE".rpmsave" ".rpmsave"
34#define SUFFIX_RPMNEW".rpmnew" ".rpmnew"
35
36/* Default directory and file permissions if not mapped */
37#define _dirPerms0755 0755
38#define _filePerms0644 0644
39
40/*
41 * XXX Forward declarations for previously exported functions to avoid moving
42 * things around needlessly
43 */
44static const char * fileActionString(rpmFileAction a);
45
46/** \ingroup payload
47 * Build path to file from file info, optionally ornamented with suffix.
48 * @param fi file info iterator
49 * @param suffix suffix to use (NULL disables)
50 * @retval path to file (malloced)
51 */
52static char * fsmFsPath(rpmfi fi, const char * suffix)
53{
54 return rstrscat(NULL((void*)0), rpmfiDN(fi), rpmfiBN(fi), suffix ? suffix : "", NULL((void*)0));
55}
56
57/** \ingroup payload
58 * Directory name iterator.
59 */
60typedef struct dnli_s {
61 rpmfiles fi;
62 char * active;
63 int reverse;
64 int isave;
65 int i;
66} * DNLI_t;
67
68/** \ingroup payload
69 * Destroy directory name iterator.
70 * @param dnli directory name iterator
71 * @retval NULL always
72 */
73static DNLI_t dnlFreeIterator(DNLI_t dnli)
74{
75 if (dnli) {
76 if (dnli->active) free(dnli->active);
77 free(dnli);
78 }
79 return NULL((void*)0);
80}
81
82/** \ingroup payload
83 * Create directory name iterator.
84 * @param fi file info set
85 * @param fs file state set
86 * @param reverse traverse directory names in reverse order?
87 * @return directory name iterator
88 */
89static DNLI_t dnlInitIterator(rpmfiles fi, rpmfs fs, int reverse)
90{
91 DNLI_t dnli;
92 int i, j;
93 int dc;
94
95 if (fi == NULL((void*)0))
96 return NULL((void*)0);
97 dc = rpmfilesDC(fi);
98 dnli = xcalloc(1, sizeof(*dnli))rcalloc((1), (sizeof(*dnli)));
99 dnli->fi = fi;
100 dnli->reverse = reverse;
101 dnli->i = (reverse ? dc : 0);
102
103 if (dc) {
104 dnli->active = xcalloc(dc, sizeof(*dnli->active))rcalloc((dc), (sizeof(*dnli->active)));
105 int fc = rpmfilesFC(fi);
106
107 /* Identify parent directories not skipped. */
108 for (i = 0; i < fc; i++)
109 if (!XFA_SKIPPING(rpmfsGetAction(fs, i))((rpmfsGetAction(fs, i)) == FA_SKIP || (rpmfsGetAction(fs, i)
) == FA_SKIPNSTATE || (rpmfsGetAction(fs, i)) == FA_SKIPNETSHARED
|| (rpmfsGetAction(fs, i)) == FA_SKIPCOLOR)
)
110 dnli->active[rpmfilesDI(fi, i)] = 1;
111
112 /* Exclude parent directories that are explicitly included. */
113 for (i = 0; i < fc; i++) {
114 int dil;
115 size_t dnlen, bnlen;
116
117 if (!S_ISDIR(rpmfilesFMode(fi, i))((((rpmfilesFMode(fi, i))) & 0170000) == (0040000)))
118 continue;
119
120 dil = rpmfilesDI(fi, i);
121 dnlen = strlen(rpmfilesDN(fi, dil));
122 bnlen = strlen(rpmfilesBN(fi, i));
123
124 for (j = 0; j < dc; j++) {
125 const char * dnl;
126 size_t jlen;
127
128 if (!dnli->active[j] || j == dil)
129 continue;
130 dnl = rpmfilesDN(fi, j);
131 jlen = strlen(dnl);
132 if (jlen != (dnlen+bnlen+1))
133 continue;
134 if (!rstreqn(dnl, rpmfilesDN(fi, dil), dnlen))
135 continue;
136 if (!rstreqn(dnl+dnlen, rpmfilesBN(fi, i), bnlen))
137 continue;
138 if (dnl[dnlen+bnlen] != '/' || dnl[dnlen+bnlen+1] != '\0')
139 continue;
140 /* This directory is included in the package. */
141 dnli->active[j] = 0;
142 break;
143 }
144 }
145
146 /* Print only once per package. */
147 if (!reverse) {
148 j = 0;
149 for (i = 0; i < dc; i++) {
150 if (!dnli->active[i]) continue;
151 if (j == 0) {
152 j = 1;
153 rpmlog(RPMLOG_DEBUG,
154 "========== Directories not explicitly included in package:\n");
155 }
156 rpmlog(RPMLOG_DEBUG, "%10d %s\n", i, rpmfilesDN(fi, i));
157 }
158 if (j)
159 rpmlog(RPMLOG_DEBUG, "==========\n");
160 }
161 }
162 return dnli;
163}
164
165/** \ingroup payload
166 * Return next directory name (from file info).
167 * @param dnli directory name iterator
168 * @return next directory name
169 */
170static
171const char * dnlNextIterator(DNLI_t dnli)
172{
173 const char * dn = NULL((void*)0);
174
175 if (dnli) {
176 rpmfiles fi = dnli->fi;
177 int dc = rpmfilesDC(fi);
178 int i = -1;
179
180 if (dnli->active)
181 do {
182 i = (!dnli->reverse ? dnli->i++ : --dnli->i);
183 } while (i >= 0 && i < dc && !dnli->active[i]);
184
185 if (i >= 0 && i < dc)
186 dn = rpmfilesDN(fi, i);
187 else
188 i = -1;
189 dnli->isave = i;
190 }
191 return dn;
192}
193
194static int fsmSetFCaps(const char *path, const char *captxt)
195{
196 int rc = 0;
197#if WITH_CAP
198 if (captxt && *captxt != '\0') {
199 cap_t fcaps = cap_from_text(captxt);
200 if (fcaps == NULL((void*)0) || cap_set_file(path, fcaps) != 0) {
201 rc = RPMERR_SETCAP_FAILED;
202 }
203 cap_free(fcaps);
204 }
205#endif
206 return rc;
207}
208
209/** \ingroup payload
210 * Create file from payload stream.
211 * @return 0 on success
212 */
213static int expandRegular(rpmfi fi, const char *dest, rpmpsm psm, int nodigest, int nocontent)
214{
215 FD_t wfd = NULL((void*)0);
216 int rc = 0;
217
218 /* Create the file with 0200 permissions (write by owner). */
219 {
220 mode_t old_umask = umask(0577);
221 wfd = Fopen(dest, "w.ufdio");
222 umask(old_umask);
223 }
224 if (Ferror(wfd)) {
225 rc = RPMERR_OPEN_FAILED;
226 goto exit;
227 }
228
229 if (!nocontent)
230 rc = rpmfiArchiveReadToFilePsm(fi, wfd, nodigest, psm);
231exit:
232 if (wfd) {
233 int myerrno = errno(*__errno_location ());
234 Fclose(wfd);
235 errno(*__errno_location ()) = myerrno;
236 }
237 return rc;
238}
239
240static int fsmMkfile(rpmfi fi, const char *dest, rpmfiles files,
241 rpmpsm psm, int nodigest, int *setmeta,
242 int * firsthardlink)
243{
244 int rc = 0;
245 int numHardlinks = rpmfiFNlink(fi);
246
247 if (numHardlinks > 1) {
248 /* Create first hardlinked file empty */
249 if (*firsthardlink < 0) {
250 *firsthardlink = rpmfiFX(fi);
251 rc = expandRegular(fi, dest, psm, nodigest, 1);
252 } else {
253 /* Create hard links for others */
254 char *fn = rpmfilesFN(files, *firsthardlink);
255 rc = link(fn, dest);
256 if (rc < 0) {
257 rc = RPMERR_LINK_FAILED;
258 }
259 free(fn);
260 }
261 }
262 /* Write normal files or fill the last hardlinked (already
263 existing) file with content */
264 if (numHardlinks<=1) {
265 if (!rc)
266 rc = expandRegular(fi, dest, psm, nodigest, 0);
267 } else if (rpmfiArchiveHasContent(fi)) {
268 if (!rc)
269 rc = expandRegular(fi, dest, psm, nodigest, 0);
270 *firsthardlink = -1;
271 } else {
272 *setmeta = 0;
273 }
274
275 return rc;
276}
277
278static int fsmReadLink(const char *path,
279 char *buf, size_t bufsize, size_t *linklen)
280{
281 ssize_t llen = readlink(path, buf, bufsize - 1);
282 int rc = RPMERR_READLINK_FAILED;
283
284 if (_fsm_debug) {
285 rpmlog(RPMLOG_DEBUG, " %8s (%s, buf, %d) %s\n",
286 __func__,
287 path, (int)(bufsize -1), (llen < 0 ? strerror(errno(*__errno_location ())) : ""));
288 }
289
290 if (llen >= 0) {
291 buf[llen] = '\0';
292 rc = 0;
293 *linklen = llen;
294 }
295 return rc;
296}
297
298static int fsmStat(const char *path, int dolstat, struct stat *sb)
299{
300 int rc;
301 if (dolstat){
302 rc = lstat(path, sb);
303 } else {
304 rc = stat(path, sb);
305 }
306 if (_fsm_debug && rc && errno(*__errno_location ()) != ENOENT2)
307 rpmlog(RPMLOG_DEBUG, " %8s (%s, ost) %s\n",
308 __func__,
309 path, (rc < 0 ? strerror(errno(*__errno_location ())) : ""));
310 if (rc < 0) {
311 rc = (errno(*__errno_location ()) == ENOENT2 ? RPMERR_ENOENT : RPMERR_LSTAT_FAILED);
312 /* Ensure consistent struct content on failure */
313 memset(sb, 0, sizeof(*sb));
314 }
315 return rc;
316}
317
318static int fsmRmdir(const char *path)
319{
320 int rc = rmdir(path);
321 if (_fsm_debug)
322 rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", __func__,
323 path, (rc < 0 ? strerror(errno(*__errno_location ())) : ""));
324 if (rc < 0)
325 switch (errno(*__errno_location ())) {
326 case ENOENT2: rc = RPMERR_ENOENT; break;
327 case ENOTEMPTY39: rc = RPMERR_ENOTEMPTY; break;
328 default: rc = RPMERR_RMDIR_FAILED; break;
329 }
330 return rc;
331}
332
333static int fsmMkdir(const char *path, mode_t mode)
334{
335 int rc = mkdir(path, (mode & 07777));
336 if (_fsm_debug)
337 rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", __func__,
338 path, (unsigned)(mode & 07777),
339 (rc < 0 ? strerror(errno(*__errno_location ())) : ""));
340 if (rc < 0) rc = RPMERR_MKDIR_FAILED;
341 return rc;
342}
343
344static int fsmMkfifo(const char *path, mode_t mode)
345{
346 int rc = mkfifo(path, (mode & 07777));
347
348 if (_fsm_debug) {
349 rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n",
350 __func__, path, (unsigned)(mode & 07777),
351 (rc < 0 ? strerror(errno(*__errno_location ())) : ""));
352 }
353
354 if (rc < 0)
355 rc = RPMERR_MKFIFO_FAILED;
356
357 return rc;
358}
359
360static int fsmMknod(const char *path, mode_t mode, dev_t dev)
361{
362 /* FIX: check S_IFIFO or dev != 0 */
363 int rc = mknod(path, (mode & ~07777), dev);
364
365 if (_fsm_debug) {
366 rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%o, 0x%x) %s\n",
367 __func__, path, (unsigned)(mode & ~07777),
368 (unsigned)dev, (rc < 0 ? strerror(errno(*__errno_location ())) : ""));
369 }
370
371 if (rc < 0)
372 rc = RPMERR_MKNOD_FAILED;
373
374 return rc;
375}
376
377/**
378 * Create (if necessary) directories not explicitly included in package.
379 * @param files file data
380 * @param fs file states
381 * @param plugins rpm plugins handle
382 * @return 0 on success
383 */
384static int fsmMkdirs(rpmfiles files, rpmfs fs, rpmPlugins plugins)
385{
386 DNLI_t dnli = dnlInitIterator(files, fs, 0);
387 struct stat sb;
388 const char *dpath;
389 int dc = rpmfilesDC(files);
390 int rc = 0;
391 int i;
392 int ldnlen = 0;
393 int ldnalloc = 0;
394 char * ldn = NULL((void*)0);
395 short * dnlx = NULL((void*)0);
396
397 dnlx = (dc ? xcalloc(dc, sizeof(*dnlx))rcalloc((dc), (sizeof(*dnlx))) : NULL((void*)0));
398
399 if (dnlx != NULL((void*)0))
400 while ((dpath = dnlNextIterator(dnli)) != NULL((void*)0)) {
401 size_t dnlen = strlen(dpath);
402 char * te, dn[dnlen+1];
403
404 dc = dnli->isave;
405 if (dc < 0) continue;
406 dnlx[dc] = dnlen;
407 if (dnlen <= 1)
408 continue;
409
410 if (dnlen <= ldnlen && rstreq(dpath, ldn))
411 continue;
412
413 /* Copy as we need to modify the string */
414 (void) stpcpy(dn, dpath);
415
416 /* Assume '/' directory exists, "mkdir -p" for others if non-existent */
417 for (i = 1, te = dn + 1; *te != '\0'; te++, i++) {
418 if (*te != '/')
419 continue;
420
421 *te = '\0';
422
423 /* Already validated? */
424 if (i < ldnlen &&
425 (ldn[i] == '/' || ldn[i] == '\0') && rstreqn(dn, ldn, i))
426 {
427 *te = '/';
428 /* Move pre-existing path marker forward. */
429 dnlx[dc] = (te - dn);
430 continue;
431 }
432
433 /* Validate next component of path. */
434 rc = fsmStat(dn, 1, &sb); /* lstat */
435 *te = '/';
436
437 /* Directory already exists? */
438 if (rc == 0 && S_ISDIR(sb.st_mode)((((sb.st_mode)) & 0170000) == (0040000))) {
439 /* Move pre-existing path marker forward. */
440 dnlx[dc] = (te - dn);
441 } else if (rc == RPMERR_ENOENT) {
442 *te = '\0';
443 mode_t mode = S_IFDIR0040000 | (_dirPerms0755 & 07777);
444 rpmFsmOp op = (FA_CREATE|FAF_UNOWNED);
445
446 /* Run fsm file pre hook for all plugins */
447 rc = rpmpluginsCallFsmFilePre(plugins, NULL((void*)0), dn, mode, op);
448
449 if (!rc)
450 rc = fsmMkdir(dn, mode);
451
452 if (!rc) {
453 rc = rpmpluginsCallFsmFilePrepare(plugins, NULL((void*)0), dn, dn,
454 mode, op);
455 }
456
457 /* Run fsm file post hook for all plugins */
458 rpmpluginsCallFsmFilePost(plugins, NULL((void*)0), dn, mode, op, rc);
459
460 if (!rc) {
461 rpmlog(RPMLOG_DEBUG,
462 "%s directory created with perms %04o\n",
463 dn, (unsigned)(mode & 07777));
464 }
465 *te = '/';
466 }
467 if (rc)
468 break;
469 }
470 if (rc) break;
471
472 /* Save last validated path. */
473 if (ldnalloc < (dnlen + 1)) {
474 ldnalloc = dnlen + 100;
475 ldn = xrealloc(ldn, ldnalloc)rrealloc((ldn), (ldnalloc));
476 }
477 if (ldn != NULL((void*)0)) { /* XXX can't happen */
478 strcpy(ldn, dn);
479 ldnlen = dnlen;
480 }
481 }
482 free(dnlx);
483 free(ldn);
484 dnlFreeIterator(dnli);
485
486 return rc;
487}
488
489static void removeSBITS(const char *path)
490{
491 struct stat stb;
492 if (lstat(path, &stb) == 0 && S_ISREG(stb.st_mode)((((stb.st_mode)) & 0170000) == (0100000))) {
493 if ((stb.st_mode & 06000) != 0) {
494 (void) chmod(path, stb.st_mode & 0777);
495 }
496#if WITH_CAP
497 if (stb.st_mode & (S_IXUSR0100|S_IXGRP(0100 >> 3)|S_IXOTH((0100 >> 3) >> 3))) {
498 (void) cap_set_file(path, NULL((void*)0));
499 }
500#endif
501 }
502}
503
504static void fsmDebug(const char *fpath, rpmFileAction action,
505 const struct stat *st)
506{
507 rpmlog(RPMLOG_DEBUG, "%-10s %06o%3d (%4d,%4d)%6d %s\n",
508 fileActionString(action), (int)st->st_mode,
509 (int)st->st_nlink, (int)st->st_uid,
510 (int)st->st_gid, (int)st->st_size,
511 (fpath ? fpath : ""));
512}
513
514static int fsmSymlink(const char *opath, const char *path)
515{
516 int rc = symlink(opath, path);
517
518 if (_fsm_debug) {
519 rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__,
520 opath, path, (rc < 0 ? strerror(errno(*__errno_location ())) : ""));
521 }
522
523 if (rc < 0)
524 rc = RPMERR_SYMLINK_FAILED;
525 return rc;
526}
527
528static int fsmUnlink(const char *path)
529{
530 int rc = 0;
531 removeSBITS(path);
532 rc = unlink(path);
533 if (_fsm_debug)
534 rpmlog(RPMLOG_DEBUG, " %8s (%s) %s\n", __func__,
535 path, (rc < 0 ? strerror(errno(*__errno_location ())) : ""));
536 if (rc < 0)
537 rc = (errno(*__errno_location ()) == ENOENT2 ? RPMERR_ENOENT : RPMERR_UNLINK_FAILED);
538 return rc;
539}
540
541static int fsmRename(const char *opath, const char *path)
542{
543 removeSBITS(path);
544 int rc = rename(opath, path);
545#if defined(ETXTBSY26) && defined(__HPUX__)
546 /* XXX HP-UX (and other os'es) don't permit rename to busy files. */
547 if (rc && errno(*__errno_location ()) == ETXTBSY26) {
548 char *rmpath = NULL((void*)0);
549 rstrscat(&rmpath, path, "-RPMDELETE", NULL((void*)0));
550 rc = rename(path, rmpath);
551 if (!rc) rc = rename(opath, path);
552 free(rmpath);
553 }
554#endif
555 if (_fsm_debug)
556 rpmlog(RPMLOG_DEBUG, " %8s (%s, %s) %s\n", __func__,
557 opath, path, (rc < 0 ? strerror(errno(*__errno_location ())) : ""));
558 if (rc < 0)
559 rc = (errno(*__errno_location ()) == EISDIR21 ? RPMERR_EXIST_AS_DIR : RPMERR_RENAME_FAILED);
560 return rc;
561}
562
563static int fsmRemove(const char *path, mode_t mode)
564{
565 return S_ISDIR(mode)((((mode)) & 0170000) == (0040000)) ? fsmRmdir(path) : fsmUnlink(path);
566}
567
568static int fsmChown(const char *path, mode_t mode, uid_t uid, gid_t gid)
569{
570 int rc = S_ISLNK(mode)((((mode)) & 0170000) == (0120000)) ? lchown(path, uid, gid) : chown(path, uid, gid);
571 if (rc < 0) {
572 struct stat st;
573 if (lstat(path, &st) == 0 && st.st_uid == uid && st.st_gid == gid)
574 rc = 0;
575 }
576 if (_fsm_debug)
577 rpmlog(RPMLOG_DEBUG, " %8s (%s, %d, %d) %s\n", __func__,
578 path, (int)uid, (int)gid,
579 (rc < 0 ? strerror(errno(*__errno_location ())) : ""));
580 if (rc < 0) rc = RPMERR_CHOWN_FAILED;
581 return rc;
582}
583
584static int fsmChmod(const char *path, mode_t mode)
585{
586 int rc = chmod(path, (mode & 07777));
587 if (rc < 0) {
588 struct stat st;
589 if (lstat(path, &st) == 0 && (st.st_mode & 07777) == (mode & 07777))
590 rc = 0;
591 }
592 if (_fsm_debug)
593 rpmlog(RPMLOG_DEBUG, " %8s (%s, 0%04o) %s\n", __func__,
594 path, (unsigned)(mode & 07777),
595 (rc < 0 ? strerror(errno(*__errno_location ())) : ""));
596 if (rc < 0) rc = RPMERR_CHMOD_FAILED;
597 return rc;
598}
599
600static int fsmUtime(const char *path, mode_t mode, time_t mtime)
601{
602 int rc = 0;
603 struct timeval stamps[2] = {
604 { .tv_sec = mtime, .tv_usec = 0 },
605 { .tv_sec = mtime, .tv_usec = 0 },
606 };
607
608#if HAVE_LUTIMES1
609 rc = lutimes(path, stamps);
610#else
611 if (!S_ISLNK(mode)((((mode)) & 0170000) == (0120000)))
612 rc = utimes(path, stamps);
613#endif
614
615 if (_fsm_debug)
616 rpmlog(RPMLOG_DEBUG, " %8s (%s, 0x%x) %s\n", __func__,
617 path, (unsigned)mtime, (rc < 0 ? strerror(errno(*__errno_location ())) : ""));
618 if (rc < 0) rc = RPMERR_UTIME_FAILED;
619 /* ...but utime error is not critical for directories */
620 if (rc && S_ISDIR(mode)((((mode)) & 0170000) == (0040000)))
621 rc = 0;
622 return rc;
623}
624
625static int fsmVerify(const char *path, rpmfi fi)
626{
627 int rc;
628 int saveerrno = errno(*__errno_location ());
629 struct stat dsb;
630 mode_t mode = rpmfiFMode(fi);
631
632 rc = fsmStat(path, 1, &dsb);
633 if (rc)
634 return rc;
635
636 if (S_ISREG(mode)((((mode)) & 0170000) == (0100000))) {
637 /* HP-UX (and other os'es) don't permit unlink on busy files. */
638 char *rmpath = rstrscat(NULL((void*)0), path, "-RPMDELETE", NULL((void*)0));
639 rc = fsmRename(path, rmpath);
640 /* XXX shouldn't we take unlink return code here? */
641 if (!rc)
642 (void) fsmUnlink(rmpath);
643 else
644 rc = RPMERR_UNLINK_FAILED;
645 free(rmpath);
646 return (rc ? rc : RPMERR_ENOENT); /* XXX HACK */
647 } else if (S_ISDIR(mode)((((mode)) & 0170000) == (0040000))) {
648 if (S_ISDIR(dsb.st_mode)((((dsb.st_mode)) & 0170000) == (0040000))) return 0;
649 if (S_ISLNK(dsb.st_mode)((((dsb.st_mode)) & 0170000) == (0120000))) {
650 rc = fsmStat(path, 0, &dsb);
651 if (rc == RPMERR_ENOENT) rc = 0;
652 if (rc) return rc;
653 errno(*__errno_location ()) = saveerrno;
654 if (S_ISDIR(dsb.st_mode)((((dsb.st_mode)) & 0170000) == (0040000))) return 0;
655 }
656 } else if (S_ISLNK(mode)((((mode)) & 0170000) == (0120000))) {
657 if (S_ISLNK(dsb.st_mode)((((dsb.st_mode)) & 0170000) == (0120000))) {
658 char buf[8 * BUFSIZ8192];
659 size_t len;
660 rc = fsmReadLink(path, buf, 8 * BUFSIZ8192, &len);
661 errno(*__errno_location ()) = saveerrno;
662 if (rc) return rc;
663 if (rstreq(rpmfiFLink(fi), buf)) return 0;
664 }
665 } else if (S_ISFIFO(mode)((((mode)) & 0170000) == (0010000))) {
666 if (S_ISFIFO(dsb.st_mode)((((dsb.st_mode)) & 0170000) == (0010000))) return 0;
667 } else if (S_ISCHR(mode)((((mode)) & 0170000) == (0020000)) || S_ISBLK(mode)((((mode)) & 0170000) == (0060000))) {
668 if ((S_ISCHR(dsb.st_mode)((((dsb.st_mode)) & 0170000) == (0020000)) || S_ISBLK(dsb.st_mode)((((dsb.st_mode)) & 0170000) == (0060000))) &&
669 (dsb.st_rdev == rpmfiFRdev(fi))) return 0;
670 } else if (S_ISSOCK(mode)((((mode)) & 0170000) == (0140000))) {
671 if (S_ISSOCK(dsb.st_mode)((((dsb.st_mode)) & 0170000) == (0140000))) return 0;
672 }
673 /* XXX shouldn't do this with commit/undo. */
674 rc = fsmUnlink(path);
675 if (rc == 0) rc = RPMERR_ENOENT;
676 return (rc ? rc : RPMERR_ENOENT); /* XXX HACK */
677}
678
679#define IS_DEV_LOG(_x)((_x) != ((void*)0) && strlen(_x) >= (sizeof("/dev/log"
)-1) && rstreqn((_x), "/dev/log", sizeof("/dev/log")-
1) && ((_x)[sizeof("/dev/log")-1] == '\0' || (_x)[sizeof
("/dev/log")-1] == ';'))
\
680 ((_x) != NULL((void*)0) && strlen(_x) >= (sizeof("/dev/log")-1) && \
681 rstreqn((_x), "/dev/log", sizeof("/dev/log")-1) && \
682 ((_x)[sizeof("/dev/log")-1] == '\0' || \
683 (_x)[sizeof("/dev/log")-1] == ';'))
684
685
686
687/* Rename pre-existing modified or unmanaged file. */
688static int fsmBackup(rpmfi fi, rpmFileAction action)
689{
690 int rc = 0;
691 const char *suffix = NULL((void*)0);
692
693 if (!(rpmfiFFlags(fi) & RPMFILE_GHOST)) {
694 switch (action) {
695 case FA_SAVE:
696 suffix = SUFFIX_RPMSAVE".rpmsave";
697 break;
698 case FA_BACKUP:
699 suffix = SUFFIX_RPMORIG".rpmorig";
700 break;
701 default:
702 break;
703 }
704 }
705
706 if (suffix) {
707 char * opath = fsmFsPath(fi, NULL((void*)0));
708 char * path = fsmFsPath(fi, suffix);
709 rc = fsmRename(opath, path);
710 if (!rc) {
711 rpmlog(RPMLOG_WARNING, _("%s saved as %s\n")dcgettext ("rpm", "%s saved as %s\n", 5), opath, path);
712 }
713 free(path);
714 free(opath);
715 }
716 return rc;
717}
718
719static int fsmSetmeta(const char *path, rpmfi fi, rpmPlugins plugins,
720 rpmFileAction action, const struct stat * st,
721 int nofcaps)
722{
723 int rc = 0;
724 const char *dest = rpmfiFN(fi);
725
726 if (!rc && !getuid()) {
727 rc = fsmChown(path, st->st_mode, st->st_uid, st->st_gid);
728 }
729 if (!rc && !S_ISLNK(st->st_mode)((((st->st_mode)) & 0170000) == (0120000))) {
730 rc = fsmChmod(path, st->st_mode);
731 }
732 /* Set file capabilities (if enabled) */
733 if (!rc && !nofcaps && S_ISREG(st->st_mode)((((st->st_mode)) & 0170000) == (0100000)) && !getuid()) {
734 rc = fsmSetFCaps(path, rpmfiFCaps(fi));
735 }
736 if (!rc) {
737 rc = fsmUtime(path, st->st_mode, rpmfiFMtime(fi));
738 }
739 if (!rc) {
740 rc = rpmpluginsCallFsmFilePrepare(plugins, fi,
741 path, dest, st->st_mode, action);
742 }
743
744 return rc;
745}
746
747static int fsmCommit(char **path, rpmfi fi, rpmFileAction action, const char *suffix)
748{
749 int rc = 0;
750
751 /* XXX Special case /dev/log, which shouldn't be packaged anyways */
752 if (!(S_ISSOCK(rpmfiFMode(fi))((((rpmfiFMode(fi))) & 0170000) == (0140000)) && IS_DEV_LOG(*path)((*path) != ((void*)0) && strlen(*path) >= (sizeof
("/dev/log")-1) && rstreqn((*path), "/dev/log", sizeof
("/dev/log")-1) && ((*path)[sizeof("/dev/log")-1] == '\0'
|| (*path)[sizeof("/dev/log")-1] == ';'))
)) {
753 const char *nsuffix = (action == FA_ALTNAME) ? SUFFIX_RPMNEW".rpmnew" : NULL((void*)0);
754 char *dest = *path;
755 /* Construct final destination path (nsuffix is usually NULL) */
756 if (suffix)
757 dest = fsmFsPath(fi, nsuffix);
758
759 /* Rename temporary to final file name if needed. */
760 if (dest != *path) {
761 rc = fsmRename(*path, dest);
762 if (!rc && nsuffix) {
763 char * opath = fsmFsPath(fi, NULL((void*)0));
764 rpmlog(RPMLOG_WARNING, _("%s created as %s\n")dcgettext ("rpm", "%s created as %s\n", 5),
765 opath, dest);
766 free(opath);
767 }
768 free(*path);
769 *path = dest;
770 }
771 }
772
773 return rc;
774}
775
776/**
777 * Return formatted string representation of file disposition.
778 * @param a file disposition
779 * @return formatted string
780 */
781static const char * fileActionString(rpmFileAction a)
782{
783 switch (a) {
784 case FA_UNKNOWN: return "unknown";
785 case FA_CREATE: return "create";
786 case FA_BACKUP: return "backup";
787 case FA_SAVE: return "save";
788 case FA_SKIP: return "skip";
789 case FA_ALTNAME: return "altname";
790 case FA_ERASE: return "erase";
791 case FA_SKIPNSTATE: return "skipnstate";
792 case FA_SKIPNETSHARED: return "skipnetshared";
793 case FA_SKIPCOLOR: return "skipcolor";
794 case FA_TOUCH: return "touch";
795 default: return "???";
796 }
797}
798
799/* Remember any non-regular file state for recording in the rpmdb */
800static void setFileState(rpmfs fs, int i)
801{
802 switch (rpmfsGetAction(fs, i)) {
803 case FA_SKIPNSTATE:
804 rpmfsSetState(fs, i, RPMFILE_STATE_NOTINSTALLED);
805 break;
806 case FA_SKIPNETSHARED:
807 rpmfsSetState(fs, i, RPMFILE_STATE_NETSHARED);
808 break;
809 case FA_SKIPCOLOR:
810 rpmfsSetState(fs, i, RPMFILE_STATE_WRONGCOLOR);
811 break;
812 case FA_TOUCH:
813 rpmfsSetState(fs, i, RPMFILE_STATE_NORMAL);
814 break;
815 default:
816 break;
817 }
818}
819
820int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
821 rpmpsm psm, char ** failedFile)
822{
823 FD_t payload = rpmtePayload(te);
824 rpmfi fi = rpmfiNewArchiveReader(payload, files, RPMFI_ITER_READ_ARCHIVE);
825 rpmfs fs = rpmteGetFileStates(te);
826 rpmPlugins plugins = rpmtsPlugins(ts);
827 struct stat sb;
828 int saveerrno = errno(*__errno_location ());
829 int rc = 0;
830 int nodigest = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOFILEDIGEST) ? 1 : 0;
831 int nofcaps = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCAPS) ? 1 : 0;
832 int firsthardlink = -1;
833 int skip;
834 rpmFileAction action;
835 char *tid = NULL((void*)0);
836 const char *suffix;
837 char *fpath = NULL((void*)0);
838
839 if (fi == NULL((void*)0)) {
840 rc = RPMERR_BAD_MAGIC;
841 goto exit;
842 }
843
844 /* transaction id used for temporary path suffix while installing */
845 rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts));
846
847 /* Detect and create directories not explicitly in package. */
848 rc = fsmMkdirs(files, fs, plugins);
849
850 while (!rc) {
851 /* Read next payload header. */
852 rc = rpmfiNext(fi);
853
854 if (rc < 0) {
855 if (rc == RPMERR_ITER_END)
856 rc = 0;
857 break;
858 }
859
860 action = rpmfsGetAction(fs, rpmfiFX(fi));
861 skip = XFA_SKIPPING(action)((action) == FA_SKIP || (action) == FA_SKIPNSTATE || (action)
== FA_SKIPNETSHARED || (action) == FA_SKIPCOLOR)
;
862 suffix = S_ISDIR(rpmfiFMode(fi))((((rpmfiFMode(fi))) & 0170000) == (0040000)) ? NULL((void*)0) : tid;
863 if (action != FA_TOUCH) {
864 fpath = fsmFsPath(fi, suffix);
865 } else {
866 fpath = fsmFsPath(fi, "");
867 }
868
869 /* Remap file perms, owner, and group. */
870 rc = rpmfiStat(fi, 1, &sb);
871
872 fsmDebug(fpath, action, &sb);
873
874 /* Exit on error. */
875 if (rc)
876 break;
877
878 /* Run fsm file pre hook for all plugins */
879 rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath,
880 sb.st_mode, action);
881 if (rc) {
882 skip = 1;
883 } else {
884 setFileState(fs, rpmfiFX(fi));
885 }
886
887 if (!skip) {
888 int setmeta = 1;
889
890 /* Directories replacing something need early backup */
891 if (!suffix) {
892 rc = fsmBackup(fi, action);
893 }
894 /* Assume file does't exist when tmp suffix is in use */
895 if (!suffix) {
896 rc = fsmVerify(fpath, fi);
897 } else {
898 rc = (action == FA_TOUCH) ? 0 : RPMERR_ENOENT;
899 }
900
901 if (S_ISREG(sb.st_mode)((((sb.st_mode)) & 0170000) == (0100000))) {
902 if (rc == RPMERR_ENOENT) {
903 rc = fsmMkfile(fi, fpath, files, psm, nodigest,
904 &setmeta, &firsthardlink);
905 }
906 } else if (S_ISDIR(sb.st_mode)((((sb.st_mode)) & 0170000) == (0040000))) {
907 if (rc == RPMERR_ENOENT) {
908 mode_t mode = sb.st_mode;
909 mode &= ~07777;
910 mode |= 00700;
911 rc = fsmMkdir(fpath, mode);
912 }
913 } else if (S_ISLNK(sb.st_mode)((((sb.st_mode)) & 0170000) == (0120000))) {
914 if (rc == RPMERR_ENOENT) {
915 rc = fsmSymlink(rpmfiFLink(fi), fpath);
916 }
917 } else if (S_ISFIFO(sb.st_mode)((((sb.st_mode)) & 0170000) == (0010000))) {
918 /* This mimics cpio S_ISSOCK() behavior but probably isn't right */
919 if (rc == RPMERR_ENOENT) {
920 rc = fsmMkfifo(fpath, 0000);
921 }
922 } else if (S_ISCHR(sb.st_mode)((((sb.st_mode)) & 0170000) == (0020000)) ||
923 S_ISBLK(sb.st_mode)((((sb.st_mode)) & 0170000) == (0060000)) ||
924 S_ISSOCK(sb.st_mode)((((sb.st_mode)) & 0170000) == (0140000)))
925 {
926 if (rc == RPMERR_ENOENT) {
927 rc = fsmMknod(fpath, sb.st_mode, sb.st_rdev);
928 }
929 } else {
930 /* XXX Special case /dev/log, which shouldn't be packaged anyways */
931 if (!IS_DEV_LOG(fpath)((fpath) != ((void*)0) && strlen(fpath) >= (sizeof
("/dev/log")-1) && rstreqn((fpath), "/dev/log", sizeof
("/dev/log")-1) && ((fpath)[sizeof("/dev/log")-1] == '\0'
|| (fpath)[sizeof("/dev/log")-1] == ';'))
)
932 rc = RPMERR_UNKNOWN_FILETYPE;
933 }
934 /* Set permissions, timestamps etc for non-hardlink entries */
935 if (!rc && setmeta) {
936 rc = fsmSetmeta(fpath, fi, plugins, action, &sb, nofcaps);
937 }
938 } else if (firsthardlink >= 0 && rpmfiArchiveHasContent(fi)) {
939 /* we skip the hard linked file containing the content */
940 /* write the content to the first used instead */
941 char *fn = rpmfilesFN(files, firsthardlink);
942 rc = expandRegular(fi, fn, psm, nodigest, 0);
943 firsthardlink = -1;
944 free(fn);
945 }
946
947 if (rc) {
948 if (!skip) {
949 /* XXX only erase if temp fn w suffix is in use */
950 if (suffix && (action != FA_TOUCH)) {
951 (void) fsmRemove(fpath, sb.st_mode);
952 }
953 errno(*__errno_location ()) = saveerrno;
954 }
955 } else {
956 /* Notify on success. */
957 rpmpsmNotify(psm, RPMCALLBACK_INST_PROGRESS, rpmfiArchiveTell(fi));
958
959 if (!skip) {
960 /* Backup file if needed. Directories are handled earlier */
961 if (suffix)
962 rc = fsmBackup(fi, action);
963
964 if (!rc)
965 rc = fsmCommit(&fpath, fi, action, suffix);
966 }
967 }
968
969 if (rc)
970 *failedFile = xstrdup(fpath)rstrdup((fpath));
971
972 /* Run fsm file post hook for all plugins */
973 rpmpluginsCallFsmFilePost(plugins, fi, fpath,
974 sb.st_mode, action, rc);
975 fpath = _free(fpath)rfree((fpath));
976 }
977
978 rpmswAdd(rpmtsOp(ts, RPMTS_OP_UNCOMPRESS), fdOp(payload, FDSTAT_READ));
979 rpmswAdd(rpmtsOp(ts, RPMTS_OP_DIGEST), fdOp(payload, FDSTAT_DIGEST));
980
981exit:
982
983 /* No need to bother with close errors on read */
984 rpmfiArchiveClose(fi);
985 rpmfiFree(fi);
986 Fclose(payload);
987 free(tid);
988 free(fpath);
989
990 return rc;
991}
992
993
994int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files,
995 rpmpsm psm, char ** failedFile)
996{
997 rpmfi fi = rpmfilesIter(files, RPMFI_ITER_BACK);
998 rpmfs fs = rpmteGetFileStates(te);
999 rpmPlugins plugins = rpmtsPlugins(ts);
1000 struct stat sb;
1001 int rc = 0;
1002 char *fpath = NULL((void*)0);
1003
1004 while (!rc && rpmfiNext(fi) >= 0) {
1005 rpmFileAction action = rpmfsGetAction(fs, rpmfiFX(fi));
1006 fpath = fsmFsPath(fi, NULL((void*)0));
1007 rc = fsmStat(fpath, 1, &sb);
Value stored to 'rc' is never read
1008
1009 fsmDebug(fpath, action, &sb);
1010
1011 /* Run fsm file pre hook for all plugins */
1012 rc = rpmpluginsCallFsmFilePre(plugins, fi, fpath,
1013 sb.st_mode, action);
1014
1015 if (!XFA_SKIPPING(action)((action) == FA_SKIP || (action) == FA_SKIPNSTATE || (action)
== FA_SKIPNETSHARED || (action) == FA_SKIPCOLOR)
)
1016 rc = fsmBackup(fi, action);
1017
1018 /* Remove erased files. */
1019 if (action == FA_ERASE) {
1020 int missingok = (rpmfiFFlags(fi) & (RPMFILE_MISSINGOK | RPMFILE_GHOST));
1021
1022 rc = fsmRemove(fpath, sb.st_mode);
1023
1024 /*
1025 * Missing %ghost or %missingok entries are not errors.
1026 * XXX: Are non-existent files ever an actual error here? Afterall
1027 * that's exactly what we're trying to accomplish here,
1028 * and complaining about job already done seems like kinderkarten
1029 * level "But it was MY turn!" whining...
1030 */
1031 if (rc == RPMERR_ENOENT && missingok) {
1032 rc = 0;
1033 }
1034
1035 /*
1036 * Dont whine on non-empty directories for now. We might be able
1037 * to track at least some of the expected failures though,
1038 * such as when we knowingly left config file backups etc behind.
1039 */
1040 if (rc == RPMERR_ENOTEMPTY) {
1041 rc = 0;
1042 }
1043
1044 if (rc) {
1045 int lvl = strict_erasures ? RPMLOG_ERR : RPMLOG_WARNING;
1046 rpmlog(lvl, _("%s %s: remove failed: %s\n")dcgettext ("rpm", "%s %s: remove failed: %s\n", 5),
1047 S_ISDIR(sb.st_mode)((((sb.st_mode)) & 0170000) == (0040000)) ? _("directory")dcgettext ("rpm", "directory", 5) : _("file")dcgettext ("rpm", "file", 5),
1048 fpath, strerror(errno(*__errno_location ())));
1049 }
1050 }
1051
1052 /* Run fsm file post hook for all plugins */
1053 rpmpluginsCallFsmFilePost(plugins, fi, fpath,
1054 sb.st_mode, action, rc);
1055
1056 /* XXX Failure to remove is not (yet) cause for failure. */
1057 if (!strict_erasures) rc = 0;
1058
1059 if (rc)
1060 *failedFile = xstrdup(fpath)rstrdup((fpath));
1061
1062 if (rc == 0) {
1063 /* Notify on success. */
1064 /* On erase we're iterating backwards, fixup for progress */
1065 rpm_loff_t amount = rpmfiFC(fi) - rpmfiFX(fi);
1066 rpmpsmNotify(psm, RPMCALLBACK_UNINST_PROGRESS, amount);
1067 }
1068 fpath = _free(fpath)rfree((fpath));
1069 }
1070
1071 free(fpath);
1072 rpmfiFree(fi);
1073
1074 return rc;
1075}
1076
1077