/* * Copyright (C) 2008 Kristian Høgsberg * Copyright (C) 2008 Red Hat, Inc * Copyright (C) 2009, 2011 J. Ali Harlow * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include #include #include #include "config.h" #include "plover/plover.h" static char *rpm_filename(const char *name,const char *version,const char *arch) { const char *v; v=strchr(version,':'); /* Skip epoch */ if (v) v++; else v=version; return plover_strconcat(name,"-",v,".",arch,".rpm",NULL); } struct razor_set *plover_relocate_packages(struct razor_set *set, struct razor_atomic *atomic,const char *base, struct razor_relocations *relocations) { struct razor_importer *importer; struct razor_property_iterator *prop_iter; struct razor_package_iterator *pkg_iter; struct razor_file_iterator *file_iter; struct razor_package *package; struct razor_property *property; struct razor_rpm *rpm; struct razor_set *new; const char *name,*version,*arch,*summary,*desc,*url,*license; char *s,*file; uint32_t flags; importer=razor_importer_create(); pkg_iter=razor_package_iterator_create(set); while (razor_package_iterator_next(pkg_iter,&package,RAZOR_DETAIL_NAME, &name,RAZOR_DETAIL_VERSION,&version,RAZOR_DETAIL_ARCH,&arch, RAZOR_DETAIL_SUMMARY,&summary,RAZOR_DETAIL_DESCRIPTION,&desc, RAZOR_DETAIL_URL,&url,RAZOR_DETAIL_LICENSE,&license,RAZOR_DETAIL_LAST)) { s=rpm_filename(name,version,arch); file=plover_strconcat(base,"/rpms/",s,NULL); free(s); rpm=razor_rpm_open(file,atomic); free(file); if (!rpm) { razor_package_iterator_destroy(pkg_iter); razor_importer_destroy(importer); return NULL; } razor_relocations_set_rpm(relocations,rpm); razor_rpm_close(rpm); razor_importer_begin_package(importer,name,version,arch); razor_importer_add_details(importer,summary,desc,url,license); prop_iter=razor_property_iterator_create(set,package); while (razor_property_iterator_next(prop_iter,&property,&name,&flags, &version)) razor_importer_add_property(importer,name,flags,version); razor_property_iterator_destroy(prop_iter); file_iter=razor_file_iterator_create(set,package,0); while (razor_file_iterator_next(file_iter,&name)) { name=razor_relocations_apply(relocations,name); razor_importer_add_file(importer,name); } razor_file_iterator_destroy(file_iter); razor_importer_finish_package(importer); } razor_package_iterator_destroy(pkg_iter); new=razor_importer_finish(importer); if (new) razor_set_set_header_version(new,razor_set_get_header_version(set)); return new; } int plover_run_transaction(struct razor_transaction *trans, struct razor_install_iterator *ii,const char *base,const char *install_root, struct razor_set *system,struct razor_set *next,struct razor_atomic *atomic, struct razor_relocations *relocations,enum razor_stage_type stage) { struct razor_package *package; enum razor_install_action action; struct razor_rpm *rpm; const char *name,*version,*arch; char *s,*file; int count; razor_install_iterator_rewind(ii); switch(stage) { case RAZOR_STAGE_SCRIPTS_PRE: printf("Running pre-transaction scripts\n"); break; case RAZOR_STAGE_FILES: printf("Running Transaction\n"); break; case RAZOR_STAGE_SCRIPTS_POST: printf("Running post-transaction scripts\n"); break; default: /* Keep the compiler happy */ break; } while (razor_install_iterator_next(ii,&package,&action,&count)) { if (action==RAZOR_INSTALL_ACTION_REMOVE) { razor_package_get_details(system,package,RAZOR_DETAIL_NAME,&name, RAZOR_DETAIL_LAST); if (stage==RAZOR_STAGE_FILES) printf(" Removing : %s ",name); razor_package_remove(system,next,atomic,package,install_root, count,stage); if (stage==RAZOR_STAGE_FILES) printf("\n"); } else { razor_package_get_details(next,package,RAZOR_DETAIL_NAME,&name, RAZOR_DETAIL_VERSION,&version,RAZOR_DETAIL_ARCH,&arch, RAZOR_DETAIL_LAST); s=rpm_filename(name,version,arch); file=plover_strconcat(base,"/rpms/",s,NULL); free(s); rpm=razor_rpm_open(file,atomic); free(file); if (!rpm) return -1; if (stage==RAZOR_STAGE_FILES) printf(" Installing : %s ",name); if (relocations) razor_rpm_set_relocations(rpm,relocations); razor_transaction_fixup_package(trans,package,rpm); razor_rpm_install(rpm,atomic,install_root,1,stage); razor_rpm_close(rpm); if (stage==RAZOR_STAGE_FILES) printf("\n"); } if (razor_atomic_in_error_state(atomic)) return -1; } return 0; } /* * Note: plover_commit_transaction() takes ownership of root which should * not be used after it returns. */ int plover_commit_transaction(struct razor_transaction *trans,const char *base, const char *install_root,struct razor_root *root,struct razor_atomic *atomic, struct razor_relocations *relocations) { int retval; struct razor_set *next,*system; struct razor_install_iterator *ii; razor_transaction_resolve(trans); if (razor_transaction_describe(trans)>0) { razor_root_close(root); return -1; } next=razor_transaction_commit(trans); system=razor_root_get_system_set(root); ii=razor_set_create_install_iterator(system,next); plover_run_transaction(trans,ii,base,install_root,system,next,atomic, relocations,RAZOR_STAGE_SCRIPTS_PRE); plover_run_transaction(trans,ii,base,install_root,system,next,atomic, relocations,RAZOR_STAGE_FILES); razor_root_update(root,next); razor_root_commit(root); retval=razor_atomic_commit(atomic); if (!retval) plover_run_transaction(trans,ii,base,install_root,system,next,atomic, relocations,RAZOR_STAGE_SCRIPTS_POST); razor_set_unref(next); razor_install_iterator_destroy(ii); return retval; } static int plover_mark_package_for_update(struct razor_transaction *trans, struct razor_set *set,const char *pkg) { struct razor_package_iterator *pi; struct razor_package *package; const char *name; int retval=-1; pi=razor_package_iterator_create(set); while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_NAME,&name, RAZOR_DETAIL_LAST)) { if (!strcmp(name,pkg)) { razor_transaction_update_package(trans,package); retval=0; break; } } razor_package_iterator_destroy(pi); return retval; } int plover_install(const char *base,const char *prefix,char **pkgs) { int i,retval; char *s; char *install_root; struct razor_root *root; struct razor_set *system,*set,*upstream; struct razor_transaction *trans; struct razor_relocations *relocations; struct razor_atomic *atomic; install_root=getenv("RAZOR_ROOT"); if (!install_root) install_root=""; if (prefix) { relocations=razor_relocations_create(); razor_relocations_add(relocations,"/usr",prefix); } else relocations=NULL; atomic=razor_atomic_open("Install packages"); /* * Calling razor_root_open() on a system that hasn't yet had * razor_root_create() run generates a confusing error message * on stderr. Avoid this by trying to open it R/O first which * fails without generating any error. */ set=razor_root_open_read_only(install_root,atomic); if (set) razor_set_unref(set); else razor_root_create(install_root); root=razor_root_open(install_root,atomic); if (!root) { fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic)); razor_atomic_destroy(atomic); if (relocations) razor_relocations_destroy(relocations); return -1; } system=razor_root_get_system_set(root); if (!system) { fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic)); razor_root_close(root); razor_atomic_destroy(atomic); if (relocations) razor_relocations_destroy(relocations); return -1; } s=plover_strconcat(base,"/repodata",NULL); if (s) { retval=chdir(s); if (retval<0) perror(s); } else retval=-1; free(s); if (retval<0) { fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic)); razor_root_close(root); razor_atomic_destroy(atomic); if (relocations) razor_relocations_destroy(relocations); return -1; } set=plover_razor_set_create_from_yum(base); if (set) { upstream=plover_relocate_packages(set,atomic,base,relocations); razor_set_unref(set); } else upstream=NULL; if (!upstream) { fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic)); razor_root_close(root); razor_atomic_destroy(atomic); if (relocations) razor_relocations_destroy(relocations); return -1; } trans=razor_transaction_create(system,upstream); razor_set_unref(upstream); for(i=0;pkgs[i];i++) if (plover_mark_package_for_update(trans,system,pkgs[i]) && plover_mark_package_for_update(trans,upstream,pkgs[i])) { fprintf(stderr,"%s: Package not found\n",pkgs[i]); retval=-1; break; } if (!retval) { retval=plover_commit_transaction(trans,base,install_root,root,atomic, relocations); if (retval) fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic)); } else razor_root_close(root); razor_transaction_destroy(trans); razor_atomic_destroy(atomic); if (relocations) razor_relocations_destroy(relocations); return retval; } int plover_update(const char *base,const char *prefix,char **pkgs) { int i,retval; char *install_root,*s; struct razor_root *root; struct razor_set *system,*set,*upstream; struct razor_transaction *trans; struct razor_relocations *relocations; struct razor_atomic *atomic; install_root=getenv("RAZOR_ROOT"); if (!install_root) install_root=""; if (prefix) { relocations=razor_relocations_create(); razor_relocations_add(relocations,"/usr",prefix); } else relocations=NULL; atomic=razor_atomic_open("Update packages"); set=razor_root_open_read_only(install_root,atomic); if (!set) { fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic)); razor_atomic_destroy(atomic); if (relocations) razor_relocations_destroy(relocations); return 0; } razor_set_unref(set); root=razor_root_open(install_root,atomic); if (!root) { fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic)); razor_atomic_destroy(atomic); if (relocations) razor_relocations_destroy(relocations); return -1; } system=razor_root_get_system_set(root); if (!system) { fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic)); razor_root_close(root); razor_atomic_destroy(atomic); if (relocations) razor_relocations_destroy(relocations); return -1; } s=plover_strconcat(base,"/repodata",NULL); if (s) { retval=chdir(s); if (retval) perror(s); } else retval=-1; free(s); if (retval) { fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic)); razor_root_close(root); razor_atomic_destroy(atomic); if (relocations) razor_relocations_destroy(relocations); return -1; } set=plover_razor_set_create_from_yum(base); if (set) { upstream=plover_relocate_packages(set,atomic,base,relocations); razor_set_unref(set); } else upstream=NULL; if (!upstream) { fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic)); razor_root_close(root); razor_atomic_destroy(atomic); if (relocations) razor_relocations_destroy(relocations); return -1; } trans=razor_transaction_create(system,upstream); razor_set_unref(upstream); if (pkgs) for(i=0;pkgs[i];i++) { if (plover_mark_package_for_update(trans,system,pkgs[i])) { fprintf(stderr,"%s: Package not found\n",pkgs[i]); retval=-1; break; } } else razor_transaction_update_all(trans); if (!retval) { retval=plover_commit_transaction(trans,base,install_root,root,atomic, relocations); if (retval) fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic)); } else razor_root_close(root); razor_transaction_destroy(trans); if (relocations) razor_relocations_destroy(relocations); razor_atomic_destroy(atomic); return retval; } static int plover_mark_packages_for_removal(struct razor_transaction *trans, struct razor_set *set,const char *pkg) { struct razor_package_iterator *pi; struct razor_package *package; const char *name; int retval=pkg?-1:0; pi=razor_package_iterator_create(set); while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_NAME,&name, RAZOR_DETAIL_LAST)) { if (!pkg || !strcmp(name,pkg)) { razor_transaction_remove_package(trans,package); retval=0; } } razor_package_iterator_destroy(pi); return retval; } int plover_remove(char **pkgs) { int i,retval=0; char *install_root; struct razor_root *root; struct razor_set *system,*set,*upstream; struct razor_transaction *trans; struct razor_atomic *atomic; install_root=getenv("RAZOR_ROOT"); if (!install_root) install_root=""; atomic=razor_atomic_open("Remove packages"); set=razor_root_open_read_only(install_root,atomic); if (!set) { fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic)); razor_atomic_destroy(atomic); return 0; } razor_set_unref(set); root=razor_root_open(install_root,atomic); if (!root) { fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic)); razor_atomic_destroy(atomic); return -1; } system=razor_root_get_system_set(root); if (!system) { fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic)); razor_root_close(root); razor_atomic_destroy(atomic); return -1; } upstream=razor_set_create_without_root(); trans=razor_transaction_create(system,upstream); razor_set_unref(upstream); if (pkgs) for(i=0;pkgs[i];i++) { if (plover_mark_packages_for_removal(trans,system,pkgs[i])) { fprintf(stderr,"%s: Package not found\n",pkgs[i]); retval=-1; break; } } else plover_mark_packages_for_removal(trans,system,NULL); if (!retval) { retval= plover_commit_transaction(trans,NULL,install_root,root,atomic,NULL); if (retval) fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic)); } else razor_root_close(root); razor_transaction_destroy(trans); razor_atomic_destroy(atomic); return retval; } /* * Note: If there are no installed files, then any prefix will match. */ int plover_installed_files_match_prefix(const char *prefix) { int len,matches=1; const char *name; char *install_root; struct razor_set *set; struct razor_atomic *atomic; struct razor_package *package; struct razor_package_iterator *pi; struct razor_file_iterator *fi; len=strlen(prefix); while(len && prefix[len-1]=='/') len--; install_root=getenv("RAZOR_ROOT"); if (!install_root) install_root=""; atomic=razor_atomic_open("Query packages"); set=razor_root_open_read_only(install_root,atomic); if (set) { pi=razor_package_iterator_create(set); while (matches && razor_package_iterator_next(pi,&package,RAZOR_DETAIL_LAST)) { fi=razor_file_iterator_create(set,package,0); while (matches && razor_file_iterator_next(fi,&name)) { if (strncmp(name,prefix,len) || name[len]!='\0' && name[len]!='/') matches=0; } razor_file_iterator_destroy(fi); } razor_package_iterator_destroy(pi); razor_set_unref(set); } razor_atomic_destroy(atomic); return matches; }