1996-01-06 02:12:55 +08:00
|
|
|
#include <alloca.h>
|
1996-01-09 04:21:22 +08:00
|
|
|
#include <errno.h>
|
1996-01-09 03:19:53 +08:00
|
|
|
#include <fcntl.h>
|
1996-01-06 02:12:55 +08:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
1996-01-09 04:21:22 +08:00
|
|
|
#include <sys/stat.h>
|
1996-01-09 03:19:53 +08:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <unistd.h>
|
1996-01-06 02:12:55 +08:00
|
|
|
|
1996-01-09 03:19:53 +08:00
|
|
|
#include "install.h"
|
|
|
|
#include "messages.h"
|
1996-01-09 04:21:22 +08:00
|
|
|
#include "md5.h"
|
1996-01-09 03:19:53 +08:00
|
|
|
#include "misc.h"
|
1996-01-06 02:12:55 +08:00
|
|
|
#include "rpmerr.h"
|
|
|
|
#include "rpmlib.h"
|
|
|
|
|
1996-03-01 09:59:03 +08:00
|
|
|
static char * SCRIPT_PATH = "export PATH=/sbin:/bin:/usr/sbin:/usr/bin:"
|
|
|
|
"/usr/X11R6/bin\n";
|
|
|
|
|
1996-01-09 03:19:53 +08:00
|
|
|
enum fileActions { REMOVE, BACKUP, KEEP };
|
|
|
|
|
|
|
|
static int sharedFileCmp(const void * one, const void * two);
|
|
|
|
static int handleSharedFiles(rpmdb db, int offset, char ** fileList,
|
|
|
|
char ** fileMd5List, int fileCount,
|
|
|
|
enum fileActions * fileActions);
|
|
|
|
static int removeFile(char * file, char state, unsigned int flags, char * md5,
|
1996-01-09 04:21:22 +08:00
|
|
|
short mode, enum fileActions action, char * rmmess,
|
|
|
|
int test);
|
1996-01-09 03:19:53 +08:00
|
|
|
|
|
|
|
static int sharedFileCmp(const void * one, const void * two) {
|
1996-02-20 08:12:50 +08:00
|
|
|
if (((struct sharedFile *) one)->secRecOffset <
|
|
|
|
((struct sharedFile *) two)->secRecOffset)
|
1996-01-09 03:19:53 +08:00
|
|
|
return -1;
|
1996-02-20 08:12:50 +08:00
|
|
|
else if (((struct sharedFile *) one)->secRecOffset ==
|
|
|
|
((struct sharedFile *) two)->secRecOffset)
|
1996-01-09 03:19:53 +08:00
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int findSharedFiles(rpmdb db, int offset, char ** fileList, int fileCount,
|
|
|
|
struct sharedFile ** listPtr, int * listCountPtr) {
|
|
|
|
int i, j;
|
|
|
|
struct sharedFile * list = NULL;
|
|
|
|
int itemsUsed = 0;
|
|
|
|
int itemsAllocated = 0;
|
|
|
|
dbIndexSet matches;
|
|
|
|
|
|
|
|
itemsAllocated = 5;
|
|
|
|
list = malloc(sizeof(struct sharedFile) * itemsAllocated);
|
|
|
|
|
|
|
|
for (i = 0; i < fileCount; i++) {
|
|
|
|
if (!rpmdbFindByFile(db, fileList[i], &matches)) {
|
|
|
|
for (j = 0; j < matches.count; j++) {
|
|
|
|
if (matches.recs[j].recOffset != offset) {
|
|
|
|
if (itemsUsed == itemsAllocated) {
|
|
|
|
itemsAllocated += 10;
|
|
|
|
list = realloc(list, sizeof(struct sharedFile) *
|
|
|
|
itemsAllocated);
|
|
|
|
}
|
|
|
|
list[itemsUsed].mainFileNumber = i;
|
|
|
|
list[itemsUsed].secRecOffset = matches.recs[j].recOffset;
|
|
|
|
list[itemsUsed].secFileNumber = matches.recs[j].fileNumber;
|
|
|
|
itemsUsed++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
qsort(list, itemsUsed, sizeof(struct sharedFile), sharedFileCmp);
|
|
|
|
|
|
|
|
*listPtr = list;
|
|
|
|
*listCountPtr = itemsUsed;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int handleSharedFiles(rpmdb db, int offset, char ** fileList,
|
|
|
|
char ** fileMd5List, int fileCount,
|
|
|
|
enum fileActions * fileActions) {
|
1996-02-20 08:12:50 +08:00
|
|
|
Header sech = NULL;
|
1996-01-09 03:19:53 +08:00
|
|
|
int secOffset = 0;
|
|
|
|
struct sharedFile * sharedList;
|
|
|
|
int sharedCount;
|
|
|
|
char * name, * version, * release;
|
|
|
|
int secFileCount;
|
|
|
|
char ** secFileMd5List, ** secFileList;
|
|
|
|
char * secFileStatesList;
|
|
|
|
int type;
|
|
|
|
int i;
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
if (findSharedFiles(db, offset, fileList, fileCount, &sharedList,
|
|
|
|
&sharedCount)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sharedCount) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < sharedCount; i++) {
|
|
|
|
if (secOffset != sharedList[i].secRecOffset) {
|
|
|
|
if (secOffset) {
|
1996-02-20 08:12:50 +08:00
|
|
|
freeHeader(sech);
|
1996-01-09 03:19:53 +08:00
|
|
|
free(secFileMd5List);
|
|
|
|
free(secFileList);
|
|
|
|
}
|
|
|
|
|
|
|
|
secOffset = sharedList[i].secRecOffset;
|
|
|
|
sech = rpmdbGetRecord(db, secOffset);
|
|
|
|
if (!sech) {
|
|
|
|
error(RPMERR_DBCORRUPT, "cannot read header at %d for "
|
|
|
|
"uninstall", offset);
|
|
|
|
rc = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
getEntry(sech, RPMTAG_NAME, &type, (void **) &name,
|
|
|
|
&secFileCount);
|
|
|
|
getEntry(sech, RPMTAG_VERSION, &type, (void **) &version,
|
|
|
|
&secFileCount);
|
|
|
|
getEntry(sech, RPMTAG_RELEASE, &type, (void **) &release,
|
|
|
|
&secFileCount);
|
|
|
|
|
|
|
|
message(MESS_DEBUG, "package %s-%s-%s contain shared files\n",
|
|
|
|
name, version, release);
|
|
|
|
|
|
|
|
if (!getEntry(sech, RPMTAG_FILENAMES, &type,
|
|
|
|
(void **) &secFileList, &secFileCount)) {
|
|
|
|
error(RPMERR_DBCORRUPT, "package %s contains no files\n",
|
|
|
|
name);
|
|
|
|
freeHeader(sech);
|
|
|
|
rc = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
getEntry(sech, RPMTAG_FILESTATES, &type,
|
|
|
|
(void **) &secFileStatesList, &secFileCount);
|
|
|
|
getEntry(sech, RPMTAG_FILEMD5S, &type,
|
|
|
|
(void **) &secFileMd5List, &secFileCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
message(MESS_DEBUG, "file %s is shared\n",
|
|
|
|
fileList[sharedList[i].mainFileNumber]);
|
|
|
|
|
|
|
|
switch (secFileStatesList[sharedList[i].secFileNumber]) {
|
|
|
|
case RPMFILE_STATE_REPLACED:
|
|
|
|
message(MESS_DEBUG, " file has already been replaced\n");
|
|
|
|
break;
|
1996-03-30 04:51:20 +08:00
|
|
|
|
|
|
|
case RPMFILE_STATE_NOTINSTALLED:
|
|
|
|
message(MESS_DEBUG, " file was never installed\n");
|
|
|
|
break;
|
1996-01-09 03:19:53 +08:00
|
|
|
|
|
|
|
case RPMFILE_STATE_NORMAL:
|
|
|
|
if (!strcmp(fileMd5List[sharedList[i].mainFileNumber],
|
|
|
|
secFileMd5List[sharedList[i].secFileNumber])) {
|
|
|
|
message(MESS_DEBUG, " file is truely shared - saving\n");
|
|
|
|
}
|
|
|
|
fileActions[sharedList[i].mainFileNumber] = KEEP;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1996-01-23 05:13:55 +08:00
|
|
|
if (secOffset) {
|
1996-02-20 08:12:50 +08:00
|
|
|
freeHeader(sech);
|
1996-01-23 05:13:55 +08:00
|
|
|
free(secFileMd5List);
|
|
|
|
free(secFileList);
|
|
|
|
}
|
1996-01-09 03:19:53 +08:00
|
|
|
free(sharedList);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
1996-04-16 06:23:46 +08:00
|
|
|
int rpmRemovePackage(char * prefix, rpmdb db, unsigned int offset, int flags) {
|
1996-01-06 02:12:55 +08:00
|
|
|
Header h;
|
|
|
|
int i;
|
1996-01-09 03:19:53 +08:00
|
|
|
int fileCount;
|
1996-01-06 02:12:55 +08:00
|
|
|
char * rmmess;
|
|
|
|
char * fnbuffer = NULL;
|
|
|
|
int fnbuffersize = 0;
|
|
|
|
int prefixLength = strlen(prefix);
|
1996-01-09 03:19:53 +08:00
|
|
|
char ** fileList, ** fileMd5List;
|
1996-01-06 02:12:55 +08:00
|
|
|
int type;
|
1996-01-09 03:19:53 +08:00
|
|
|
uint_32 * fileFlagsList;
|
1996-01-09 04:21:22 +08:00
|
|
|
int_16 * fileModesList;
|
1996-01-06 02:12:55 +08:00
|
|
|
char * fileStatesList;
|
1996-01-09 03:19:53 +08:00
|
|
|
enum { REMOVE, BACKUP, KEEP } * fileActions;
|
1996-01-06 02:12:55 +08:00
|
|
|
|
|
|
|
h = rpmdbGetRecord(db, offset);
|
|
|
|
if (!h) {
|
|
|
|
error(RPMERR_DBCORRUPT, "cannot read header at %d for uninstall",
|
|
|
|
offset);
|
1996-01-09 03:19:53 +08:00
|
|
|
return 1;
|
1996-01-06 02:12:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* dependency checking should go in here */
|
|
|
|
|
1996-04-16 06:23:46 +08:00
|
|
|
if (flags & UNINSTALL_TEST) {
|
1996-01-06 02:12:55 +08:00
|
|
|
rmmess = "would remove";
|
|
|
|
} else {
|
|
|
|
rmmess = "removing";
|
|
|
|
}
|
1996-01-09 03:19:53 +08:00
|
|
|
|
|
|
|
message(MESS_DEBUG, "running preuninstall script (if any)\n");
|
1996-04-16 06:23:46 +08:00
|
|
|
runScript(prefix, h, RPMTAG_PREUN, flags & UNINSTALL_NOSCRIPTS);
|
1996-01-06 02:12:55 +08:00
|
|
|
|
1996-04-16 06:23:46 +08:00
|
|
|
message(MESS_DEBUG, "%s files test = %d\n", rmmess, flags & UNINSTALL_TEST);
|
1996-01-06 02:12:55 +08:00
|
|
|
if (!getEntry(h, RPMTAG_FILENAMES, &type, (void **) &fileList,
|
1996-01-09 03:19:53 +08:00
|
|
|
&fileCount)) {
|
1996-01-06 02:12:55 +08:00
|
|
|
puts("(contains no files)");
|
|
|
|
} else {
|
|
|
|
if (prefix[0]) {
|
|
|
|
fnbuffersize = 1024;
|
|
|
|
fnbuffer = alloca(fnbuffersize);
|
|
|
|
}
|
|
|
|
|
1996-01-09 03:19:53 +08:00
|
|
|
getEntry(h, RPMTAG_FILESTATES, &type, (void **) &fileStatesList,
|
|
|
|
&fileCount);
|
|
|
|
getEntry(h, RPMTAG_FILEMD5S, &type, (void **) &fileMd5List,
|
|
|
|
&fileCount);
|
|
|
|
getEntry(h, RPMTAG_FILEFLAGS, &type, (void **) &fileFlagsList,
|
|
|
|
&fileCount);
|
1996-01-09 04:21:22 +08:00
|
|
|
getEntry(h, RPMTAG_FILEMODES, &type, (void **) &fileModesList,
|
|
|
|
&fileCount);
|
1996-01-09 03:19:53 +08:00
|
|
|
|
1996-03-30 04:51:20 +08:00
|
|
|
fileActions = alloca(sizeof(*fileActions) * fileCount);
|
|
|
|
for (i = 0; i < fileCount; i++)
|
|
|
|
if (fileStatesList[i] == RPMFILE_STATE_NOTINSTALLED)
|
|
|
|
fileActions[i] = KEEP;
|
|
|
|
else
|
|
|
|
fileActions[i] = REMOVE;
|
|
|
|
|
1996-01-09 03:19:53 +08:00
|
|
|
handleSharedFiles(db, offset, fileList, fileMd5List, fileCount, fileActions);
|
|
|
|
|
1996-01-30 03:37:28 +08:00
|
|
|
/* go through the filelist backwards to help insure that rmdir()
|
|
|
|
will work */
|
|
|
|
for (i = fileCount - 1; i >= 0; i--) {
|
1996-01-09 05:28:20 +08:00
|
|
|
if (strcmp(prefix, "/")) {
|
1996-01-06 02:12:55 +08:00
|
|
|
if ((strlen(fileList[i]) + prefixLength + 1) > fnbuffersize) {
|
|
|
|
fnbuffersize = (strlen(fileList[i]) + prefixLength) * 2;
|
|
|
|
fnbuffer = alloca(fnbuffersize);
|
|
|
|
}
|
1996-01-09 05:28:20 +08:00
|
|
|
strcpy(fnbuffer, prefix);
|
1996-01-06 02:12:55 +08:00
|
|
|
strcat(fnbuffer, "/");
|
1996-01-09 05:28:20 +08:00
|
|
|
strcat(fnbuffer, fileList[i]);
|
1996-01-06 02:12:55 +08:00
|
|
|
} else {
|
|
|
|
fnbuffer = fileList[i];
|
|
|
|
}
|
|
|
|
|
1996-01-09 03:19:53 +08:00
|
|
|
removeFile(fnbuffer, fileStatesList[i], fileFlagsList[i],
|
1996-01-09 04:21:22 +08:00
|
|
|
fileMd5List[i], fileModesList[i], fileActions[i],
|
1996-04-16 06:23:46 +08:00
|
|
|
rmmess, flags & UNINSTALL_TEST);
|
1996-01-06 02:12:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
free(fileList);
|
1996-01-09 03:19:53 +08:00
|
|
|
free(fileMd5List);
|
1996-01-06 02:12:55 +08:00
|
|
|
}
|
|
|
|
|
1996-01-09 03:19:53 +08:00
|
|
|
message(MESS_DEBUG, "running postuninstall script (if any)\n");
|
1996-04-16 06:23:46 +08:00
|
|
|
runScript(prefix, h, RPMTAG_POSTUN, flags & UNINSTALL_NOSCRIPTS);
|
1996-01-09 03:19:53 +08:00
|
|
|
|
|
|
|
freeHeader(h);
|
|
|
|
|
1996-01-06 02:12:55 +08:00
|
|
|
message(MESS_DEBUG, "%s database entry\n", rmmess);
|
1996-04-16 06:23:46 +08:00
|
|
|
if (!(flags & UNINSTALL_TEST))
|
1996-01-06 02:12:55 +08:00
|
|
|
rpmdbRemove(db, offset, 0);
|
|
|
|
|
1996-01-09 03:19:53 +08:00
|
|
|
return 0;
|
1996-01-06 02:12:55 +08:00
|
|
|
}
|
|
|
|
|
1996-04-16 06:23:46 +08:00
|
|
|
int runScript(char * prefix, Header h, int tag, int norunScripts) {
|
1996-01-09 03:19:53 +08:00
|
|
|
int count, type;
|
|
|
|
char * script;
|
|
|
|
char * fn;
|
|
|
|
int fd;
|
|
|
|
int isdebug = isDebug();
|
|
|
|
int child;
|
|
|
|
int status;
|
|
|
|
|
1996-05-07 09:49:06 +08:00
|
|
|
if (norunScripts) return 0;
|
1996-04-16 06:23:46 +08:00
|
|
|
|
1996-01-09 03:19:53 +08:00
|
|
|
if (getEntry(h, tag, &type, (void **) &script, &count)) {
|
|
|
|
fn = tmpnam(NULL);
|
|
|
|
message(MESS_DEBUG, "script found - running from file %s\n", fn);
|
|
|
|
fd = open(fn, O_CREAT | O_RDWR);
|
|
|
|
unlink(fn);
|
|
|
|
if (fd < 0) {
|
1996-04-16 06:23:46 +08:00
|
|
|
error(RPMERR_SCRIPT, "error creating file for (un)install script");
|
1996-01-09 03:19:53 +08:00
|
|
|
return 1;
|
|
|
|
}
|
1996-03-01 09:59:03 +08:00
|
|
|
write(fd, SCRIPT_PATH, strlen(SCRIPT_PATH));
|
1996-01-09 03:19:53 +08:00
|
|
|
write(fd, script, strlen(script));
|
|
|
|
|
|
|
|
/* run the script via /bin/sh - just feed the commands to the
|
|
|
|
shell as stdin */
|
|
|
|
child = fork();
|
|
|
|
if (!child) {
|
|
|
|
lseek(fd, 0, SEEK_SET);
|
|
|
|
close(0);
|
|
|
|
dup2(fd, 0);
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
if (strcmp(prefix, "/")) {
|
|
|
|
message(MESS_DEBUG, "performing chroot(%s)\n", prefix);
|
|
|
|
chroot(prefix);
|
1996-01-09 05:28:20 +08:00
|
|
|
chdir("/");
|
1996-01-09 03:19:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (isdebug)
|
|
|
|
execl("/bin/sh", "/bin/sh", "-x", NULL);
|
|
|
|
else
|
|
|
|
execl("/bin/sh", "/bin/sh", NULL);
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
waitpid(child, &status, 0);
|
|
|
|
|
|
|
|
if (!WIFEXITED(status) || WEXITSTATUS(status)) {
|
|
|
|
error(RPMERR_SCRIPT, "execution of script failed\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int removeFile(char * file, char state, unsigned int flags, char * md5,
|
1996-01-09 04:21:22 +08:00
|
|
|
short mode, enum fileActions action, char * rmmess,
|
|
|
|
int test) {
|
|
|
|
char currentMd5[40];
|
|
|
|
int rc = 0;
|
|
|
|
char * newfile;
|
1996-01-09 03:19:53 +08:00
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
case RPMFILE_STATE_REPLACED:
|
|
|
|
message(MESS_DEBUG, "%s has already been replaced\n", file);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RPMFILE_STATE_NORMAL:
|
1996-01-09 04:21:22 +08:00
|
|
|
if ((action == REMOVE) && (flags & RPMFILE_CONFIG)) {
|
|
|
|
/* if it's a config file, we may not want to remove it */
|
|
|
|
message(MESS_DEBUG, "finding md5sum of %s\n", file);
|
|
|
|
if (mdfile(file, currentMd5))
|
|
|
|
message(MESS_DEBUG, " failed - assuming file removed\n");
|
|
|
|
else {
|
|
|
|
if (strcmp(currentMd5, md5)) {
|
|
|
|
message(MESS_DEBUG, " file changed - will save\n");
|
|
|
|
action = BACKUP;
|
|
|
|
} else {
|
|
|
|
message(MESS_DEBUG, " file unchanged - will remove\n");
|
|
|
|
}
|
|
|
|
}
|
1996-01-09 03:19:53 +08:00
|
|
|
}
|
|
|
|
|
1996-01-09 04:21:22 +08:00
|
|
|
switch (action) {
|
|
|
|
|
|
|
|
case KEEP:
|
|
|
|
message(MESS_DEBUG, "keeping %s\n", file);
|
1996-02-16 05:08:09 +08:00
|
|
|
break;
|
1996-01-09 04:21:22 +08:00
|
|
|
|
|
|
|
case BACKUP:
|
|
|
|
message(MESS_DEBUG, "saving %s as %s.rpmsave\n", file, file);
|
|
|
|
if (!test) {
|
|
|
|
newfile = alloca(strlen(file) + 20);
|
|
|
|
strcpy(newfile, file);
|
|
|
|
strcat(newfile, ".rpmsave");
|
|
|
|
if (rename(file, newfile)) {
|
|
|
|
error(RPMERR_RENAME, "rename of %s to %s failed: %s",
|
|
|
|
file, newfile, strerror(errno));
|
|
|
|
rc = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REMOVE:
|
|
|
|
message(MESS_DEBUG, "%s - %s\n", file, rmmess);
|
|
|
|
if (S_ISDIR(mode)) {
|
|
|
|
if (!test) {
|
|
|
|
if (rmdir(file)) {
|
|
|
|
if (errno == ENOTEMPTY)
|
|
|
|
error(RPMERR_RMDIR, "cannot remove %s - directory "
|
|
|
|
"not empty", file);
|
|
|
|
else
|
|
|
|
error(RPMERR_RMDIR, "rmdir of %s failed: %s",
|
|
|
|
file, strerror(errno));
|
|
|
|
rc = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!test) {
|
|
|
|
if (unlink(file)) {
|
|
|
|
error(RPMERR_UNLINK, "removal of %s failed: %s",
|
|
|
|
file, strerror(errno));
|
|
|
|
rc = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
1996-01-09 03:19:53 +08:00
|
|
|
}
|