00001
00005 #include "system.h"
00006
00007 #include <rpmlib.h>
00008 #include <rpmurl.h>
00009 #include <rpmmacro.h>
00010
00011 #include "depends.h"
00012 #include "install.h"
00013 #include "misc.h"
00014 #include "debug.h"
00015
00016
00017
00018 static char * SCRIPT_PATH = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin";
00019
00020 #define SUFFIX_RPMSAVE ".rpmsave"
00021
00027 static const char * tag2sln(int tag)
00028 {
00029 switch (tag) {
00030 case RPMTAG_PREIN: return "%pre";
00031 case RPMTAG_POSTIN: return "%post";
00032 case RPMTAG_PREUN: return "%preun";
00033 case RPMTAG_POSTUN: return "%postun";
00034 case RPMTAG_VERIFYSCRIPT: return "%verify";
00035 }
00036 return "%unknownscript";
00037 }
00038
00047 static int removeFile(const char * file, rpmfileAttrs fileAttrs, short mode,
00048 enum fileActions action)
00049 {
00050 int rc = 0;
00051 char * newfile;
00052
00053 switch (action) {
00054
00055 case FA_BACKUP:
00056 newfile = alloca(strlen(file) + sizeof(SUFFIX_RPMSAVE));
00057 (void)stpcpy(stpcpy(newfile, file), SUFFIX_RPMSAVE);
00058
00059 if (rename(file, newfile)) {
00060 rpmError(RPMERR_RENAME, _("rename of %s to %s failed: %s\n"),
00061 file, newfile, strerror(errno));
00062 rc = 1;
00063 }
00064 break;
00065
00066 case FA_REMOVE:
00067 if (S_ISDIR(mode)) {
00068
00069 if (rmdir(file)) {
00070 switch (errno) {
00071 case ENOENT:
00072 case ENOTEMPTY:
00073 rpmError(RPMERR_RMDIR,
00074 _("cannot remove %s - directory not empty\n"),
00075 file);
00076 break;
00077 default:
00078 rpmError(RPMERR_RMDIR, _("rmdir of %s failed: %s\n"),
00079 file, strerror(errno));
00080 break;
00081 }
00082 rc = 1;
00083 }
00084 } else {
00085 if (unlink(file)) {
00086 if (errno != ENOENT || !(fileAttrs & RPMFILE_MISSINGOK)) {
00087 rpmError(RPMERR_UNLINK,
00088 _("removal of %s failed: %s\n"),
00089 file, strerror(errno));
00090 }
00091 rc = 1;
00092 }
00093 }
00094 break;
00095 case FA_UNKNOWN:
00096 case FA_CREATE:
00097 case FA_SAVE:
00098 case FA_ALTNAME:
00099 case FA_SKIP:
00100 case FA_SKIPNSTATE:
00101 case FA_SKIPNETSHARED:
00102 case FA_SKIPMULTILIB:
00103 break;
00104 }
00105
00106 return 0;
00107 }
00108
00109 int removeBinaryPackage(const rpmTransactionSet ts, unsigned int offset,
00110 Header h, const void * pkgKey, enum fileActions * actions)
00111 {
00112 rpmtransFlags transFlags = ts->transFlags;
00113 const char * name, * version, * release;
00114 const char ** baseNames;
00115 int scriptArg;
00116 int rc = 0;
00117 int fileCount;
00118 int i;
00119
00120 if (transFlags & RPMTRANS_FLAG_JUSTDB)
00121 transFlags |= RPMTRANS_FLAG_NOSCRIPTS;
00122
00123 headerNVR(h, &name, &version, &release);
00124
00125
00126
00127
00128
00129 if ((scriptArg = rpmdbCountPackages(ts->rpmdb, name)) < 0)
00130 return 1;
00131 scriptArg -= 1;
00132
00133 if (!(transFlags & RPMTRANS_FLAG_NOTRIGGERS)) {
00134
00135
00136 if (runImmedTriggers(ts, RPMSENSE_TRIGGERUN, h, -1))
00137 return 2;
00138
00139
00140 if (runTriggers(ts, RPMSENSE_TRIGGERUN, h, -1))
00141 return 1;
00142 }
00143
00144 if (!(transFlags & RPMTRANS_FLAG_TEST)) {
00145 rc = runInstScript(ts, h, RPMTAG_PREUN, RPMTAG_PREUNPROG, scriptArg,
00146 (transFlags & RPMTRANS_FLAG_NOSCRIPTS));
00147 if (rc)
00148 return 1;
00149 }
00150
00151 rpmMessage(RPMMESS_DEBUG, _("will remove files test = %d\n"),
00152 transFlags & RPMTRANS_FLAG_TEST);
00153
00154 if (!(transFlags & RPMTRANS_FLAG_JUSTDB) &&
00155 headerGetEntry(h, RPMTAG_BASENAMES, NULL, (void **) &baseNames,
00156 &fileCount)) {
00157 const char ** fileMd5List;
00158 uint_32 * fileFlagsList;
00159 int_16 * fileModesList;
00160 const char ** dirNames;
00161 int_32 * dirIndexes;
00162 int type;
00163 char * fileName;
00164 int fnmaxlen;
00165 int rdlen = (ts->rootDir && !(ts->rootDir[0] == '/' && ts->rootDir[1] == '\0'))
00166 ? strlen(ts->rootDir) : 0;
00167
00168 headerGetEntry(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
00169 headerGetEntry(h, RPMTAG_DIRNAMES, NULL, (void **) &dirNames, NULL);
00170
00171
00172 fnmaxlen = 0;
00173 for (i = 0; i < fileCount; i++) {
00174 size_t fnlen;
00175 fnlen = strlen(baseNames[i]) +
00176 strlen(dirNames[dirIndexes[i]]);
00177 if (fnlen > fnmaxlen)
00178 fnmaxlen = fnlen;
00179 }
00180 fnmaxlen += rdlen + sizeof("/");
00181
00182 fileName = alloca(fnmaxlen);
00183
00184 if (rdlen) {
00185 strcpy(fileName, ts->rootDir);
00186 (void)rpmCleanPath(fileName);
00187 rdlen = strlen(fileName);
00188 } else
00189 *fileName = '\0';
00190
00191 headerGetEntry(h, RPMTAG_FILEMD5S, &type, (void **) &fileMd5List,
00192 &fileCount);
00193 headerGetEntry(h, RPMTAG_FILEFLAGS, &type, (void **) &fileFlagsList,
00194 &fileCount);
00195 headerGetEntry(h, RPMTAG_FILEMODES, &type, (void **) &fileModesList,
00196 &fileCount);
00197
00198 if (ts->notify) {
00199 (void)ts->notify(h, RPMCALLBACK_UNINST_START, fileCount, fileCount,
00200 pkgKey, ts->notifyData);
00201 }
00202
00203
00204 for (i = fileCount - 1; i >= 0; i--) {
00205
00206
00207 (void)stpcpy(stpcpy(fileName+rdlen, dirNames[dirIndexes[i]]), baseNames[i]);
00208
00209 rpmMessage(RPMMESS_DEBUG, _(" file: %s action: %s\n"),
00210 fileName, fileActionString(actions[i]));
00211
00212 if (!(transFlags & RPMTRANS_FLAG_TEST)) {
00213 if (ts->notify) {
00214 (void)ts->notify(h, RPMCALLBACK_UNINST_PROGRESS,
00215 i, actions[i], fileName, ts->notifyData);
00216 }
00217 removeFile(fileName, fileFlagsList[i], fileModesList[i],
00218 actions[i]);
00219 }
00220 }
00221
00222 if (ts->notify) {
00223 (void)ts->notify(h, RPMCALLBACK_UNINST_STOP, 0, fileCount,
00224 pkgKey, ts->notifyData);
00225 }
00226
00227 free(baseNames);
00228 free(dirNames);
00229 free(fileMd5List);
00230 }
00231
00232 if (!(transFlags & RPMTRANS_FLAG_TEST)) {
00233 rpmMessage(RPMMESS_DEBUG, _("running postuninstall script (if any)\n"));
00234 rc = runInstScript(ts, h, RPMTAG_POSTUN, RPMTAG_POSTUNPROG,
00235 scriptArg, (transFlags & RPMTRANS_FLAG_NOSCRIPTS));
00236
00237 }
00238
00239 if (!(transFlags & RPMTRANS_FLAG_NOTRIGGERS)) {
00240
00241 rc = runTriggers(ts, RPMSENSE_TRIGGERPOSTUN, h, -1);
00242 if (rc)
00243 return 2;
00244 }
00245
00246 if (!(transFlags & RPMTRANS_FLAG_TEST))
00247 rpmdbRemove(ts->rpmdb, ts->id, offset);
00248
00249 return 0;
00250 }
00251
00263 static int runScript(const rpmTransactionSet ts, Header h,
00264 const char * sln,
00265 int progArgc, const char ** progArgv,
00266 const char * script, int arg1, int arg2)
00267 {
00268 const char ** argv = NULL;
00269 int argc = 0;
00270 const char ** prefixes = NULL;
00271 int numPrefixes;
00272 const char * oldPrefix;
00273 int maxPrefixLength;
00274 int len;
00275 char * prefixBuf = NULL;
00276 pid_t child;
00277 int status = 0;
00278 const char * fn = NULL;
00279 int i;
00280 int freePrefixes = 0;
00281 FD_t out;
00282 int rc = 0;
00283 const char *n, *v, *r;
00284
00285 if (!progArgv && !script)
00286 return 0;
00287 else if (!progArgv) {
00288 argv = alloca(5 * sizeof(char *));
00289 argv[0] = "/bin/sh";
00290 argc = 1;
00291 } else {
00292 argv = alloca((progArgc + 4) * sizeof(char *));
00293 memcpy(argv, progArgv, progArgc * sizeof(char *));
00294 argc = progArgc;
00295 }
00296
00297 headerNVR(h, &n, &v, &r);
00298 if (headerGetEntry(h, RPMTAG_INSTPREFIXES, NULL, (void **) &prefixes,
00299 &numPrefixes)) {
00300 freePrefixes = 1;
00301 } else if (headerGetEntry(h, RPMTAG_INSTALLPREFIX, NULL,
00302 (void **) &oldPrefix,
00303 NULL)) {
00304 prefixes = &oldPrefix;
00305 numPrefixes = 1;
00306 } else {
00307 numPrefixes = 0;
00308 }
00309
00310 maxPrefixLength = 0;
00311 for (i = 0; i < numPrefixes; i++) {
00312 len = strlen(prefixes[i]);
00313 if (len > maxPrefixLength) maxPrefixLength = len;
00314 }
00315 prefixBuf = alloca(maxPrefixLength + 50);
00316
00317 if (script) {
00318 FD_t fd;
00319 if (makeTempFile((!ts->chrootDone ? ts->rootDir : "/"), &fn, &fd)) {
00320 if (freePrefixes) free(prefixes);
00321 return 1;
00322 }
00323
00324 if (rpmIsDebug() &&
00325 (!strcmp(argv[0], "/bin/sh") || !strcmp(argv[0], "/bin/bash")))
00326 (void)Fwrite("set -x\n", sizeof(char), 7, fd);
00327
00328 (void)Fwrite(script, sizeof(script[0]), strlen(script), fd);
00329 Fclose(fd);
00330
00331 { const char * sn = fn;
00332 if (!ts->chrootDone &&
00333 !(ts->rootDir[0] == '/' && ts->rootDir[1] == '\0'))
00334 {
00335 sn += strlen(ts->rootDir)-1;
00336 }
00337 argv[argc++] = sn;
00338 }
00339
00340 if (arg1 >= 0) {
00341 char *av = alloca(20);
00342 sprintf(av, "%d", arg1);
00343 argv[argc++] = av;
00344 }
00345 if (arg2 >= 0) {
00346 char *av = alloca(20);
00347 sprintf(av, "%d", arg2);
00348 argv[argc++] = av;
00349 }
00350 }
00351
00352 argv[argc] = NULL;
00353
00354 if (ts->scriptFd != NULL) {
00355 if (rpmIsVerbose()) {
00356 out = fdDup(Fileno(ts->scriptFd));
00357 } else {
00358 out = Fopen("/dev/null", "w.fdio");
00359 if (Ferror(out)) {
00360 out = fdDup(Fileno(ts->scriptFd));
00361 }
00362 }
00363 } else {
00364 out = fdDup(STDOUT_FILENO);
00365 out = fdLink(out, "runScript persist");
00366 }
00367
00368 if (!(child = fork())) {
00369 const char * rootDir;
00370 int pipes[2];
00371
00372 pipes[0] = pipes[1] = 0;
00373
00374 pipe(pipes);
00375 close(pipes[1]);
00376 dup2(pipes[0], STDIN_FILENO);
00377 close(pipes[0]);
00378
00379 if (ts->scriptFd != NULL) {
00380 if (Fileno(ts->scriptFd) != STDERR_FILENO)
00381 dup2(Fileno(ts->scriptFd), STDERR_FILENO);
00382 if (Fileno(out) != STDOUT_FILENO)
00383 dup2(Fileno(out), STDOUT_FILENO);
00384
00385 if (Fileno(out) > STDERR_FILENO && Fileno(out) != Fileno(ts->scriptFd)) {
00386 Fclose (out);
00387 }
00388 if (Fileno(ts->scriptFd) > STDERR_FILENO) {
00389 Fclose (ts->scriptFd);
00390 }
00391 }
00392
00393 { const char *ipath = rpmExpand("PATH=%{_install_script_path}", NULL);
00394 const char *path = SCRIPT_PATH;
00395
00396 if (ipath && ipath[5] != '%')
00397 path = ipath;
00398 doputenv(path);
00399 if (ipath) free((void *)ipath);
00400 }
00401
00402 for (i = 0; i < numPrefixes; i++) {
00403 sprintf(prefixBuf, "RPM_INSTALL_PREFIX%d=%s", i, prefixes[i]);
00404 doputenv(prefixBuf);
00405
00406
00407 if (i == 0) {
00408 sprintf(prefixBuf, "RPM_INSTALL_PREFIX=%s", prefixes[i]);
00409 doputenv(prefixBuf);
00410 }
00411 }
00412
00413 rootDir = ts->rootDir;
00414 switch(urlIsURL(rootDir)) {
00415 case URL_IS_PATH:
00416 rootDir += sizeof("file://") - 1;
00417 rootDir = strchr(rootDir, '/');
00418
00419 case URL_IS_UNKNOWN:
00420 if (!ts->chrootDone && !(rootDir[0] == '/' && rootDir[1] == '\0')) {
00421 chroot(rootDir);
00422 }
00423 chdir("/");
00424 execv(argv[0], (char *const *)argv);
00425 break;
00426 default:
00427 break;
00428 }
00429
00430 _exit(-1);
00431
00432 }
00433
00434 if (waitpid(child, &status, 0) < 0) {
00435 rpmError(RPMERR_SCRIPT,
00436 _("retrieval of return code of %s scriptlet from %s-%s-%s failed, waitpid returned %s\n"),
00437 sln, n, v, r, strerror (errno));
00438
00439 rc = 0;
00440 } else {
00441 if (!WIFEXITED(status) || WEXITSTATUS(status)) {
00442 rpmError(RPMERR_SCRIPT,
00443 _("execution of %s scriptlet from %s-%s-%s failed, exit status %d\n"),
00444 sln, n, v, r, WEXITSTATUS(status));
00445 rc = 1;
00446 }
00447 }
00448
00449 if (freePrefixes) free(prefixes);
00450
00451 Fclose(out);
00452
00453 if (script) {
00454 if (!rpmIsDebug()) unlink(fn);
00455 free((void *)fn);
00456 }
00457
00458 return rc;
00459 }
00460
00461 int runInstScript(const rpmTransactionSet ts, Header h,
00462 int scriptTag, int progTag, int arg, int norunScripts)
00463 {
00464 void ** programArgv;
00465 int programArgc;
00466 const char ** argv;
00467 int programType;
00468 char * script;
00469 int rc;
00470
00471 if (norunScripts) return 0;
00472
00473
00474
00475 headerGetEntry(h, progTag, &programType, (void **) &programArgv,
00476 &programArgc);
00477 headerGetEntry(h, scriptTag, NULL, (void **) &script, NULL);
00478
00479 if (programArgv && programType == RPM_STRING_TYPE) {
00480 argv = alloca(sizeof(char *));
00481 *argv = (const char *) programArgv;
00482 } else {
00483 argv = (const char **) programArgv;
00484 }
00485
00486 rc = runScript(ts, h, tag2sln(scriptTag), programArgc, argv, script,
00487 arg, -1);
00488 headerFreeData(programArgv, programType);
00489 return rc;
00490 }
00491
00502 static int handleOneTrigger(const rpmTransactionSet ts, int sense,
00503 Header sourceH, Header triggeredH,
00504 int arg1correction, int arg2,
00505 char * triggersAlreadyRun)
00506 {
00507 const char ** triggerNames;
00508 const char ** triggerEVR;
00509 const char ** triggerScripts;
00510 const char ** triggerProgs;
00511 int_32 * triggerFlags;
00512 int_32 * triggerIndices;
00513 const char * triggerPackageName;
00514 const char * sourceName;
00515 int numTriggers;
00516 int rc = 0;
00517 int i;
00518 int skip;
00519
00520 if (!headerGetEntry(triggeredH, RPMTAG_TRIGGERNAME, NULL,
00521 (void **) &triggerNames, &numTriggers)) {
00522 return 0;
00523 }
00524
00525 headerNVR(sourceH, &sourceName, NULL, NULL);
00526
00527 headerGetEntry(triggeredH, RPMTAG_TRIGGERFLAGS, NULL,
00528 (void **) &triggerFlags, NULL);
00529 headerGetEntry(triggeredH, RPMTAG_TRIGGERVERSION, NULL,
00530 (void **) &triggerEVR, NULL);
00531
00532 for (i = 0; i < numTriggers; i++) {
00533
00534 if (!(triggerFlags[i] & sense)) continue;
00535 if (strcmp(triggerNames[i], sourceName)) continue;
00536
00537
00538
00539
00540 skip = strlen(triggerNames[i]);
00541 if (!strncmp(triggerEVR[i], triggerNames[i], skip) &&
00542 (triggerEVR[i][skip] == '-'))
00543 skip++;
00544 else
00545 skip = 0;
00546
00547 if (!headerMatchesDepFlags(sourceH, triggerNames[i],
00548 triggerEVR[i] + skip, triggerFlags[i]))
00549 continue;
00550
00551 headerGetEntry(triggeredH, RPMTAG_TRIGGERINDEX, NULL,
00552 (void **) &triggerIndices, NULL);
00553 headerGetEntry(triggeredH, RPMTAG_TRIGGERSCRIPTS, NULL,
00554 (void **) &triggerScripts, NULL);
00555 headerGetEntry(triggeredH, RPMTAG_TRIGGERSCRIPTPROG, NULL,
00556 (void **) &triggerProgs, NULL);
00557
00558 headerNVR(triggeredH, &triggerPackageName, NULL, NULL);
00559
00560 { int arg1;
00561 int index;
00562
00563 if ((arg1 = rpmdbCountPackages(ts->rpmdb, triggerPackageName)) < 0) {
00564 rc = 1;
00565 } else {
00566 arg1 += arg1correction;
00567 index = triggerIndices[i];
00568 if (!triggersAlreadyRun || !triggersAlreadyRun[index]) {
00569 rc = runScript(ts, triggeredH, "%trigger", 1,
00570 triggerProgs + index, triggerScripts[index],
00571 arg1, arg2);
00572 if (triggersAlreadyRun) triggersAlreadyRun[index] = 1;
00573 }
00574 }
00575 }
00576
00577 free(triggerScripts);
00578 free(triggerProgs);
00579
00580
00581
00582 break;
00583 }
00584
00585 free(triggerNames);
00586
00587 return rc;
00588 }
00589
00590 int runTriggers(const rpmTransactionSet ts, int sense, Header h,
00591 int countCorrection)
00592 {
00593 const char * name;
00594 int numPackage;
00595 int rc = 0;
00596
00597 headerNVR(h, &name, NULL, NULL);
00598
00599 numPackage = rpmdbCountPackages(ts->rpmdb, name) + countCorrection;
00600 if (numPackage < 0)
00601 return 1;
00602
00603 { Header triggeredH;
00604 rpmdbMatchIterator mi;
00605
00606 mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_TRIGGERNAME, name, 0);
00607 while((triggeredH = rpmdbNextIterator(mi)) != NULL) {
00608 rc |= handleOneTrigger(ts, sense, h, triggeredH, 0, numPackage,
00609 NULL);
00610 }
00611
00612 rpmdbFreeIterator(mi);
00613 }
00614
00615 return rc;
00616 }
00617
00618 int runImmedTriggers(const rpmTransactionSet ts, int sense, Header h,
00619 int countCorrection)
00620 {
00621 const char ** triggerNames;
00622 int numTriggers;
00623 int_32 * triggerIndices;
00624 int numTriggerIndices;
00625 char * triggersRun;
00626 int rc = 0;
00627
00628 if (!headerGetEntry(h, RPMTAG_TRIGGERNAME, NULL, (void **) &triggerNames,
00629 &numTriggers))
00630 return 0;
00631 headerGetEntry(h, RPMTAG_TRIGGERINDEX, NULL, (void **) &triggerIndices,
00632 &numTriggerIndices);
00633 triggersRun = alloca(sizeof(*triggersRun) * numTriggerIndices);
00634 memset(triggersRun, 0, sizeof(*triggersRun) * numTriggerIndices);
00635
00636 { Header sourceH = NULL;
00637 int i;
00638
00639 for (i = 0; i < numTriggers; i++) {
00640 rpmdbMatchIterator mi;
00641 const char * name = triggerNames[i];
00642
00643 if (triggersRun[triggerIndices[i]]) continue;
00644
00645 mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, name, 0);
00646
00647 while((sourceH = rpmdbNextIterator(mi)) != NULL) {
00648 rc |= handleOneTrigger(ts, sense, sourceH, h,
00649 countCorrection, rpmdbGetIteratorCount(mi),
00650 triggersRun);
00651 }
00652
00653 rpmdbFreeIterator(mi);
00654 }
00655 }
00656 return rc;
00657 }