/************************************************************************* * FUNCTION : RPMTransaction_Set::Create * * ARGUMENTS : interp, name * * RETURNS : object created or 0 if error * * EXCEPTIONS : none * * PURPOSE : Set up an empty transaction list * *************************************************************************/ RPMTransaction_Set *RPMTransaction_Set::Create(Tcl_Interp *interp,const char *name) { if (RPMTransaction_Set::Cmd_exists(interp,name)) { RPM_for_TCL::Error(interp, "\"%s\" command already exists",name); return 0; } rpmts ts = rpmtsCreate(); if (!ts) { RPM_for_TCL::Error(interp, "cannot create RPM transaction: %s",rpmErrorString()); return 0; } return new RPMTransaction_Set(interp,name,ts); }
/************************************************************************* * FUNCTION : RPMTransaction_Set::Test * * ARGUMENTS : none * * RETURNS : TCL_OK or TCL_ERROR * * EXCEPTIONS : none * * PURPOSE : Check the transaction set for problems * *************************************************************************/ int RPMTransaction_Set::Test(Tcl_Interp *interp,int objc, Tcl_Obj *const objv[]) { if (objc != 2) { Tcl_WrongNumArgs(interp,2,objv,0); return TCL_ERROR; } rpmtsSetFlags(transaction,(rpmtransFlags)(RPMTRANS_FLAG_TEST )); int status = rpmtsRun(transaction,0,(rpmprobFilterFlags)prob_flags); // Assume we've dirtied the database RPM_for_TCL::DBs_are_dirty(); if (status == 0) return TCL_OK; else if (status < 0) return Error("Error on test: %d %s",status,rpmErrorString()); return Problems(interp); }
/* Get the size of the file */ static size_t RPMSize(install_info *info, const char *path) { FD_t fdi; Header hd; size_t size = 0; int_32 type, c; void *p; int rc; fdi = fdOpen(path, O_RDONLY, 0644); rc = rpmReadPackageHeader(fdi, &hd, NULL, NULL, NULL); if ( rc ) { log_warning(_("RPM error: %s"), rpmErrorString()); fdClose(fdi); return 0; } headerGetEntry(hd, RPMTAG_SIZE, &type, &p, &c); if(type==RPM_INT32_TYPE){ size = *(int_32*) p; } fdClose(fdi); return size; }
/* Extract the file */ static size_t RPMCopy(install_info *info, const char *path, const char *dest, const char *current_option_name, xmlNodePtr node, int (*update)(install_info *info, const char *path, size_t progress, size_t size, const char *current)) { FD_t fdi; Header hd; size_t size; int_32 type, c; int rc, isSource; void *p; const char *reloc = xmlGetProp(node, "relocate"); const char *autorm = xmlGetProp(node, "autoremove"); const char *depsoff = xmlGetProp(node, "nodeps"); int relocate = (reloc && !strcasecmp(reloc, "true")); int autoremove = (autorm && !strcasecmp(autorm, "true")); int nodeps = (depsoff && !strcasecmp(depsoff, "true")); fdi = fdOpen(path, O_RDONLY, 0644); rc = rpmReadPackageHeader(fdi, &hd, &isSource, NULL, NULL); if ( rc ) { log_warning(_("RPM error: %s"), rpmErrorString()); return 0; } size = 0; if ( rpm_access && ! force_manual ) { /* We can call RPM directly */ char cmd[300]; FILE *fp; float percent = 0.0; double bytes_copied = 0.0; double previous_bytes = 0.0; char *name = "", *version = "", *release = ""; char *options = (char *) malloc(PATH_MAX); options[0] = '\0'; headerGetEntry(hd, RPMTAG_SIZE, &type, &p, &c); if(type==RPM_INT32_TYPE){ size = *(int_32*) p; } headerGetEntry(hd, RPMTAG_RELEASE, &type, &p, &c); if(type==RPM_STRING_TYPE){ release = (char *) p; } headerGetEntry(hd, RPMTAG_NAME, &type, &p, &c); if(type==RPM_STRING_TYPE){ name = (char*)p; } headerGetEntry(hd, RPMTAG_VERSION, &type, &p, &c); if(type==RPM_STRING_TYPE){ version = (char*)p; } fdClose(fdi); if (relocate) { /* force relocating RPM to install directory */ sprintf(options, " --relocate /=%s --badreloc ", dest); } if (nodeps) { strcat(options, " --nodeps "); } snprintf(cmd,sizeof(cmd),"rpm -U --percent --root %s %s %s", rpm_root, options, path); fp = popen(cmd, "r"); while ( percent < 100.0 ) { if(!fp || feof(fp)){ pclose(fp); free(options); log_warning(_("Unable to install RPM file: '%s'"), path); return 0; } fscanf(fp,"%s", cmd); if(strcmp(cmd,"%%")){ pclose(fp); free(options); log_warning(_("Unable to install RPM file: '%s'"), path); return 0; } fscanf(fp,"%f", &percent); /* calculate the bytes installed in this pass of the loop */ bytes_copied = (percent/100.0)*size - previous_bytes; previous_bytes += bytes_copied; info->installed_bytes += bytes_copied; if ( ! update(info, path, (percent/100.0)*size, size, current_option_name) ) break; } pclose(fp); free (options); /* Log the RPM installation */ add_rpm_entry(info, current_option, name, version, atoi(release), autoremove); } else { /* Manually install the RPM file */ gzFile gzdi = NULL; BZFILE *bzdi = NULL; FILE *fd = NULL; unsigned char magic[2]; stream *cpio; if(headerIsEntry(hd, RPMTAG_PREIN)){ headerGetEntry(hd, RPMTAG_PREIN, &type, &p, &c); if(type==RPM_STRING_TYPE) run_script(info, (char*)p, 1, 1); } /* Identify the type of compression for the archive */ if ( fdRead(fdi, magic, 2) < 2 ) { return 0; } lseek(fdFileno(fdi), -2L, SEEK_CUR); if ( magic[0]==037 && magic[1]==0213 ) { gzdi = gzdopen(fdFileno(fdi), "r"); /* XXX gzdi == fdi */ } else if ( magic[0]=='B' && magic[1]=='Z' ) { bzdi = BZDOPEN(fdFileno(fdi), "r"); } else { /* Assume not compressed */ fd = fdopen(fdFileno(fdi), "r"); } cpio = file_fdopen(info, path, fd, gzdi, bzdi, "r"); /* if relocate="true", copy the files into dest instead of rpm_root */ if (relocate) { size = copy_cpio_stream(info, cpio, dest, current_option_name, node, update); } else { size = copy_cpio_stream(info, cpio, rpm_root, current_option_name, node, update); } if(headerIsEntry(hd, RPMTAG_POSTIN)){ headerGetEntry(hd, RPMTAG_POSTIN, &type, &p, &c); if(type==RPM_STRING_TYPE) run_script(info, (char*)p, 1, 1); } /* Append the uninstall scripts to the uninstall */ if(headerIsEntry(hd, RPMTAG_PREUN)){ headerGetEntry(hd, RPMTAG_PREUN, &type, &p, &c); if(type==RPM_STRING_TYPE) add_script_entry(info, current_option, (char*)p, 0); } if(headerIsEntry(hd, RPMTAG_POSTUN)){ headerGetEntry(hd, RPMTAG_POSTUN, &type, &p, &c); if(type==RPM_STRING_TYPE) add_script_entry(info, current_option, (char*)p, 1); } fdClose(fdi); } return size; }
/************************************************************************* * FUNCTION : RPMTransaction_Set::Install_or_remove * * ARGUMENTS : RPM headers to add * * RETURNS : TCL_OK or TCL_ERROR * * EXCEPTIONS : none * * PURPOSE : Add an RPM to an install set * *************************************************************************/ int RPMTransaction_Set::Install_or_remove(Tcl_Obj *name,Install_mode mode) { // Is this a list? if so, recurse through it Tcl_ObjType *listtype = Tcl_GetObjType("list"); if (name->typePtr == listtype) { // OK, go recursive on this int count = 0; if (Tcl_ListObjLength(_interp,name,&count) != TCL_OK) return TCL_ERROR; for (int i = 0; i < count; ++i) { Tcl_Obj *element = 0; if (Tcl_ListObjIndex(_interp,name,i,&element) != TCL_OK) { return TCL_ERROR; } if (Install_or_remove(element,mode) != TCL_OK) return TCL_ERROR; } return TCL_OK; } // OK, so not a list. Try to make it into an RPM header if (Tcl_ConvertToType(_interp,name,&RPMHeader_Obj::mytype) != TCL_OK) return TCL_ERROR; RPMHeader_Obj *header = ( RPMHeader_Obj *)(name->internalRep.otherValuePtr); \ // Unfortunately, the transaction set API does not give us a way to know when // it has freed a fnpyKey key object. In order to clean these up, we will create // a TCL list object of all headers we use for this purpose, and clean it as needed. Tcl_Obj *hdr_copy = header->Get_obj(); Tcl_IncrRefCount(hdr_copy); int error = 0; switch (mode) { case INSTALL: error = rpmtsAddInstallElement(transaction,*header,header,0,0); break; case UPGRADE: error = rpmtsAddInstallElement(transaction,*header,header,1,0); break; case REMOVE: error = rpmtsAddEraseElement(transaction,*header,header->DB_entry()); break; } switch (error) { case 0: // Record that we have created an entry on the list header_list = Grow_list(header_list,hdr_copy); return TCL_OK; case 1: header->Dec_refcount(); return Error("Error adding %s: %s\n",Tcl_GetStringFromObj(name,0),rpmErrorString()); case 2: header->Dec_refcount(); return Error("Error adding %s: needs capabilities %s\n",Tcl_GetStringFromObj(name,0),rpmErrorString()); default: header->Dec_refcount(); return Error("Unknown RPMlib error %d adding %s: needs capabilities %s\n",error,Tcl_GetStringFromObj(name,0),rpmErrorString()); } return TCL_OK; }