plover/razor.c
author J. Ali Harlow <ali@juiblex.co.uk>
Thu Nov 10 11:15:09 2011 +0000 (2011-11-10)
changeset 13 b0a35bae4961
parent 6 e8c9cc792c5d
child 19 5cafc65a6183
permissions -rw-r--r--
Support razor 0.5 (atomic transactions).
Don't create repositories with multiple roots.
Filter out "other" arches from yum repositories.
Mark win32 binaries as needing elevated privileges.
     1 /*
     2  * Copyright (C) 2008  Kristian Høgsberg <krh@redhat.com>
     3  * Copyright (C) 2008  Red Hat, Inc
     4  * Copyright (C) 2009, 2011  J. Ali Harlow <ali@juiblex.co.uk>
     5  *
     6  * This program is free software; you can redistribute it and/or modify
     7  * it under the terms of the GNU General Public License as published by
     8  * the Free Software Foundation; either version 2 of the License, or
     9  * (at your option) any later version.
    10  *
    11  * This program is distributed in the hope that it will be useful,
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  * GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along
    17  * with this program; if not, write to the Free Software Foundation, Inc.,
    18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    19  */
    20 
    21 #include <stdlib.h>
    22 #include <stdio.h>
    23 #include <stdarg.h>
    24 #include <string.h>
    25 #include <unistd.h>
    26 #include <razor.h>
    27 #include "config.h"
    28 #include "plover/plover.h"
    29 
    30 static char *rpm_filename(const char *name,const char *version,const char *arch)
    31 {
    32     const char *v;
    33     v=strchr(version,':');	      /* Skip epoch */
    34     if (v)
    35 	v++;
    36     else
    37 	v=version;
    38     return plover_strconcat(name,"-",v,".",arch,".rpm",NULL);
    39 }
    40 
    41 struct razor_set *plover_relocate_packages(struct razor_set *set,
    42   struct razor_atomic *atomic,const char *base,
    43   struct razor_relocations *relocations)
    44 {
    45     struct razor_importer *importer;
    46     struct razor_property_iterator *prop_iter;
    47     struct razor_package_iterator *pkg_iter;
    48     struct razor_file_iterator *file_iter;
    49     struct razor_package *package;
    50     struct razor_property *property;
    51     struct razor_rpm *rpm;
    52     struct razor_set *new;
    53     const char *name,*version,*arch,*summary,*desc,*url,*license;
    54     char *s,*file;
    55     uint32_t flags;
    56     importer=razor_importer_create();
    57     pkg_iter=razor_package_iterator_create(set);
    58     while (razor_package_iterator_next(pkg_iter,&package,RAZOR_DETAIL_NAME,
    59       &name,RAZOR_DETAIL_VERSION,&version,RAZOR_DETAIL_ARCH,&arch,
    60       RAZOR_DETAIL_SUMMARY,&summary,RAZOR_DETAIL_DESCRIPTION,&desc,
    61       RAZOR_DETAIL_URL,&url,RAZOR_DETAIL_LICENSE,&license,RAZOR_DETAIL_LAST))
    62     {
    63 	s=rpm_filename(name,version,arch);
    64 	file=plover_strconcat(base,"/rpms/",s,NULL);
    65 	free(s);
    66 	rpm=razor_rpm_open(file,atomic);
    67 	free(file);
    68 	if (!rpm)
    69 	{
    70 	    razor_package_iterator_destroy(pkg_iter);
    71 	    razor_importer_destroy(importer);
    72 	    return NULL;
    73 	}
    74 	razor_relocations_set_rpm(relocations,rpm);
    75 	razor_rpm_close(rpm);
    76 	razor_importer_begin_package(importer,name,version,arch);
    77 	razor_importer_add_details(importer,summary,desc,url,license);
    78 	prop_iter=razor_property_iterator_create(set,package);
    79 	while (razor_property_iterator_next(prop_iter,&property,&name,&flags,
    80 	  &version))
    81 	    razor_importer_add_property(importer,name,flags,version);
    82 	razor_property_iterator_destroy(prop_iter);
    83 	file_iter=razor_file_iterator_create(set,package,0);
    84 	while (razor_file_iterator_next(file_iter,&name))
    85 	{
    86 	    name=razor_relocations_apply(relocations,name);
    87 	    razor_importer_add_file(importer,name);
    88 	}
    89 	razor_file_iterator_destroy(file_iter);
    90 	razor_importer_finish_package(importer);
    91     }
    92     razor_package_iterator_destroy(pkg_iter);
    93     new=razor_importer_finish(importer);
    94     if (new)
    95 	razor_set_set_header_version(new,razor_set_get_header_version(set));
    96     return new;
    97 }
    98 
    99 int plover_run_transaction(struct razor_transaction *trans,
   100   struct razor_install_iterator *ii,const char *base,const char *install_root,
   101   struct razor_set *system,struct razor_set *next,struct razor_atomic *atomic,
   102   struct razor_relocations *relocations,enum razor_stage_type stage)
   103 {
   104     struct razor_package *package;
   105     enum razor_install_action action;
   106     struct razor_rpm *rpm;
   107     const char *name,*version,*arch;
   108     char *s,*file;
   109     int count;
   110     razor_install_iterator_rewind(ii);
   111     switch(stage)
   112     {
   113 	case RAZOR_STAGE_SCRIPTS_PRE:
   114 	    printf("Running pre-transaction scripts\n");
   115 	    break;
   116 	case RAZOR_STAGE_FILES:
   117 	    printf("Running Transaction\n");
   118 	    break;
   119 	case RAZOR_STAGE_SCRIPTS_POST:
   120 	    printf("Running post-transaction scripts\n");
   121 	    break;
   122 	default:
   123 	    /* Keep the compiler happy */
   124 	    break;
   125     }
   126     while (razor_install_iterator_next(ii,&package,&action,&count))
   127     {
   128 	if (action==RAZOR_INSTALL_ACTION_REMOVE)
   129 	{
   130 	    razor_package_get_details(system,package,RAZOR_DETAIL_NAME,&name,
   131 	      RAZOR_DETAIL_LAST);
   132 	    if (stage==RAZOR_STAGE_FILES)
   133 		printf("  Removing : %s ",name);
   134 	    razor_package_remove(system,next,atomic,package,install_root,
   135 	      count,stage);
   136 	    if (stage==RAZOR_STAGE_FILES)
   137 		printf("\n");
   138 	}
   139 	else
   140 	{
   141 	    razor_package_get_details(next,package,RAZOR_DETAIL_NAME,&name,
   142 	      RAZOR_DETAIL_VERSION,&version,RAZOR_DETAIL_ARCH,&arch,
   143 	      RAZOR_DETAIL_LAST);
   144 	    s=rpm_filename(name,version,arch);
   145 	    file=plover_strconcat(base,"/rpms/",s,NULL);
   146 	    free(s);
   147 	    rpm=razor_rpm_open(file,atomic);
   148 	    free(file);
   149 	    if (!rpm)
   150 		return -1;
   151 	    if (stage==RAZOR_STAGE_FILES)
   152 		printf("  Installing : %s ",name);
   153 	    if (relocations)
   154 		razor_rpm_set_relocations(rpm,relocations);
   155 	    razor_transaction_fixup_package(trans,package,rpm);
   156 	    razor_rpm_install(rpm,atomic,install_root,1,stage);
   157 	    razor_rpm_close(rpm);
   158 	    if (stage==RAZOR_STAGE_FILES)
   159 		printf("\n");
   160 	}
   161 	if (razor_atomic_in_error_state(atomic))
   162 	    return -1;
   163     }
   164     return 0;
   165 }
   166 
   167 /*
   168  * Note: plover_commit_transaction() takes ownership of root which should
   169  * not be used after it returns.
   170  */
   171 int plover_commit_transaction(struct razor_transaction *trans,const char *base,
   172   const char *install_root,struct razor_root *root,struct razor_atomic *atomic,
   173   struct razor_relocations *relocations)
   174 {
   175     int retval;
   176     struct razor_set *next,*system;
   177     struct razor_install_iterator *ii;
   178     razor_transaction_resolve(trans);
   179     if (razor_transaction_describe(trans)>0)
   180     {
   181 	razor_root_close(root);
   182 	return -1;
   183     }
   184     next=razor_transaction_commit(trans);
   185     system=razor_root_get_system_set(root);
   186     ii=razor_set_create_install_iterator(system,next);
   187     plover_run_transaction(trans,ii,base,install_root,system,next,atomic,
   188       relocations,RAZOR_STAGE_SCRIPTS_PRE);
   189     plover_run_transaction(trans,ii,base,install_root,system,next,atomic,
   190       relocations,RAZOR_STAGE_FILES);
   191     razor_root_update(root,next);
   192     razor_root_commit(root);
   193     retval=razor_atomic_commit(atomic);
   194     if (!retval)
   195 	plover_run_transaction(trans,ii,base,install_root,system,next,atomic,
   196 	  relocations,RAZOR_STAGE_SCRIPTS_POST);
   197     razor_set_unref(next);
   198     razor_install_iterator_destroy(ii);
   199     return retval;
   200 }
   201 
   202 static int plover_mark_package_for_update(struct razor_transaction *trans,
   203   struct razor_set *set,const char *pkg)
   204 {
   205     struct razor_package_iterator *pi;
   206     struct razor_package *package;
   207     const char *name;
   208     int retval=-1;
   209     pi=razor_package_iterator_create(set);
   210     while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_NAME,&name,
   211       RAZOR_DETAIL_LAST))
   212     {
   213 	if (!strcmp(name,pkg))
   214 	{
   215 	    razor_transaction_update_package(trans,package);
   216 	    retval=0;
   217 	    break;
   218 	}
   219     }
   220     razor_package_iterator_destroy(pi);
   221     return retval;
   222 }
   223 
   224 int plover_install(const char *base,const char *prefix,char **pkgs)
   225 {
   226     int i,retval;
   227     char *s;
   228     char *install_root;
   229     struct razor_root *root;
   230     struct razor_set *system,*set,*upstream;
   231     struct razor_transaction *trans;
   232     struct razor_relocations *relocations;
   233     struct razor_atomic *atomic;
   234     install_root=getenv("RAZOR_ROOT");
   235     if (!install_root)
   236 	install_root="";
   237     if (prefix)
   238     {
   239 	relocations=razor_relocations_create();
   240 	razor_relocations_add(relocations,"/usr",prefix);
   241     }
   242     else
   243 	relocations=NULL;
   244     atomic=razor_atomic_open("Install packages");
   245     /*
   246      * Calling razor_root_open() on a system that hasn't yet had
   247      * razor_root_create() run generates a confusing error message
   248      * on stderr. Avoid this by trying to open it R/O first which
   249      * fails without generating any error.
   250      */
   251     set=razor_root_open_read_only(install_root,atomic);
   252     if (set)
   253 	razor_set_unref(set);
   254     else
   255 	razor_root_create(install_root);
   256     root=razor_root_open(install_root,atomic);
   257     if (!root)
   258     {
   259 	fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic));
   260 	razor_atomic_destroy(atomic);
   261 	if (relocations)
   262 	    razor_relocations_destroy(relocations);
   263 	return -1;
   264     }
   265     system=razor_root_get_system_set(root);
   266     if (!system)
   267     {
   268 	fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic));
   269 	razor_root_close(root);
   270 	razor_atomic_destroy(atomic);
   271 	if (relocations)
   272 	    razor_relocations_destroy(relocations);
   273 	return -1;
   274     }
   275     s=plover_strconcat(base,"/repodata",NULL);
   276     if (s)
   277     {
   278 	retval=chdir(s);
   279 	if (retval<0)
   280 	    perror(s);
   281     }
   282     else
   283 	retval=-1;
   284     free(s);
   285     if (retval<0)
   286     {
   287 	fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic));
   288 	razor_root_close(root);
   289 	razor_atomic_destroy(atomic);
   290 	if (relocations)
   291 	    razor_relocations_destroy(relocations);
   292 	return -1;
   293     }
   294     set=plover_razor_set_create_from_yum(base);
   295     if (set)
   296     {
   297 	upstream=plover_relocate_packages(set,atomic,base,relocations);
   298 	razor_set_unref(set);
   299     }
   300     else
   301 	upstream=NULL;
   302     if (!upstream)
   303     {
   304 	fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic));
   305 	razor_root_close(root);
   306 	razor_atomic_destroy(atomic);
   307 	if (relocations)
   308 	    razor_relocations_destroy(relocations);
   309 	return -1;
   310     }
   311     trans=razor_transaction_create(system,upstream);
   312     razor_set_unref(upstream);
   313     for(i=0;pkgs[i];i++)
   314 	if (plover_mark_package_for_update(trans,system,pkgs[i]) &&
   315 	  plover_mark_package_for_update(trans,upstream,pkgs[i]))
   316 	{
   317 	    fprintf(stderr,"%s: Package not found\n",pkgs[i]);
   318 	    retval=-1;
   319 	    break;
   320 	}
   321     if (!retval)
   322     {
   323 	retval=plover_commit_transaction(trans,base,install_root,root,atomic,
   324 	  relocations);
   325 	if (retval)
   326 	    fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic));
   327     }
   328     else
   329 	razor_root_close(root);
   330     razor_transaction_destroy(trans);
   331     razor_atomic_destroy(atomic);
   332     if (relocations)
   333 	razor_relocations_destroy(relocations);
   334     return retval;
   335 }
   336 
   337 int plover_update(const char *base,const char *prefix,char **pkgs)
   338 {
   339     int i,retval;
   340     char *install_root,*s;
   341     struct razor_root *root;
   342     struct razor_set *system,*set,*upstream;
   343     struct razor_transaction *trans;
   344     struct razor_relocations *relocations;
   345     struct razor_atomic *atomic;
   346     install_root=getenv("RAZOR_ROOT");
   347     if (!install_root)
   348 	install_root="";
   349     if (prefix)
   350     {
   351 	relocations=razor_relocations_create();
   352 	razor_relocations_add(relocations,"/usr",prefix);
   353     }
   354     else
   355 	relocations=NULL;
   356     atomic=razor_atomic_open("Update packages");
   357     set=razor_root_open_read_only(install_root,atomic);
   358     if (!set)
   359     {
   360 	fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic));
   361 	razor_atomic_destroy(atomic);
   362 	if (relocations)
   363 	    razor_relocations_destroy(relocations);
   364 	return 0;
   365     }
   366     razor_set_unref(set);
   367     root=razor_root_open(install_root,atomic);
   368     if (!root)
   369     {
   370 	fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic));
   371 	razor_atomic_destroy(atomic);
   372 	if (relocations)
   373 	    razor_relocations_destroy(relocations);
   374 	return -1;
   375     }
   376     system=razor_root_get_system_set(root);
   377     if (!system)
   378     {
   379 	fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic));
   380 	razor_root_close(root);
   381 	razor_atomic_destroy(atomic);
   382 	if (relocations)
   383 	    razor_relocations_destroy(relocations);
   384 	return -1;
   385     }
   386     s=plover_strconcat(base,"/repodata",NULL);
   387     if (s)
   388     {
   389 	retval=chdir(s);
   390 	if (retval)
   391 	    perror(s);
   392     }
   393     else
   394 	retval=-1;
   395     free(s);
   396     if (retval)
   397     {
   398 	fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic));
   399 	razor_root_close(root);
   400 	razor_atomic_destroy(atomic);
   401 	if (relocations)
   402 	    razor_relocations_destroy(relocations);
   403 	return -1;
   404     }
   405     set=plover_razor_set_create_from_yum(base);
   406     if (set)
   407     {
   408 	upstream=plover_relocate_packages(set,atomic,base,relocations);
   409 	razor_set_unref(set);
   410     }
   411     else
   412 	upstream=NULL;
   413     if (!upstream)
   414     {
   415 	fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic));
   416 	razor_root_close(root);
   417 	razor_atomic_destroy(atomic);
   418 	if (relocations)
   419 	    razor_relocations_destroy(relocations);
   420 	return -1;
   421     }
   422     trans=razor_transaction_create(system,upstream);
   423     razor_set_unref(upstream);
   424     if (pkgs)
   425 	for(i=0;pkgs[i];i++)
   426 	{
   427 	    if (plover_mark_package_for_update(trans,system,pkgs[i]))
   428 	    {
   429 		fprintf(stderr,"%s: Package not found\n",pkgs[i]);
   430 		retval=-1;
   431 		break;
   432 	    }
   433 	}
   434     else
   435 	razor_transaction_update_all(trans);
   436     if (!retval) {
   437 	retval=plover_commit_transaction(trans,base,install_root,root,atomic,
   438 	  relocations);
   439 	if (retval)
   440 	    fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic));
   441     }
   442     else
   443 	razor_root_close(root);
   444     razor_transaction_destroy(trans);
   445     if (relocations)
   446 	razor_relocations_destroy(relocations);
   447     razor_atomic_destroy(atomic);
   448     return retval;
   449 }
   450 
   451 static int plover_mark_packages_for_removal(struct razor_transaction *trans,
   452   struct razor_set *set,const char *pkg)
   453 {
   454     struct razor_package_iterator *pi;
   455     struct razor_package *package;
   456     const char *name;
   457     int retval=pkg?-1:0;
   458     pi=razor_package_iterator_create(set);
   459     while (razor_package_iterator_next(pi,&package,RAZOR_DETAIL_NAME,&name,
   460       RAZOR_DETAIL_LAST))
   461     {
   462 	if (!pkg || !strcmp(name,pkg))
   463 	{
   464 	    razor_transaction_remove_package(trans,package);
   465 	    retval=0;
   466 	}
   467     }
   468     razor_package_iterator_destroy(pi);
   469     return retval;
   470 }
   471 
   472 int plover_remove(char **pkgs)
   473 {
   474     int i,retval=0;
   475     char *install_root;
   476     struct razor_root *root;
   477     struct razor_set *system,*set,*upstream;
   478     struct razor_transaction *trans;
   479     struct razor_atomic *atomic;
   480     install_root=getenv("RAZOR_ROOT");
   481     if (!install_root)
   482 	install_root="";
   483     atomic=razor_atomic_open("Remove packages");
   484     set=razor_root_open_read_only(install_root,atomic);
   485     if (!set)
   486     {
   487 	fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic));
   488 	razor_atomic_destroy(atomic);
   489 	return 0;
   490     }
   491     razor_set_unref(set);
   492     root=razor_root_open(install_root,atomic);
   493     if (!root)
   494     {
   495 	fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic));
   496 	razor_atomic_destroy(atomic);
   497 	return -1;
   498     }
   499     system=razor_root_get_system_set(root);
   500     if (!system)
   501     {
   502 	fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic));
   503 	razor_root_close(root);
   504 	razor_atomic_destroy(atomic);
   505 	return -1;
   506     }
   507     upstream=razor_set_create_without_root();
   508     trans=razor_transaction_create(system,upstream);
   509     razor_set_unref(upstream);
   510     if (pkgs)
   511 	for(i=0;pkgs[i];i++)
   512 	{
   513 	    if (plover_mark_packages_for_removal(trans,system,pkgs[i]))
   514 	    {
   515 		fprintf(stderr,"%s: Package not found\n",pkgs[i]);
   516 		retval=-1;
   517 		break;
   518 	    }
   519 	}
   520     else
   521 	plover_mark_packages_for_removal(trans,system,NULL);
   522     if (!retval)
   523     {
   524 	retval=
   525 	  plover_commit_transaction(trans,NULL,install_root,root,atomic,NULL);
   526 	if (retval)
   527 	    fprintf(stderr,"%s\n",razor_atomic_get_error_msg(atomic));
   528     }
   529     else
   530 	razor_root_close(root);
   531     razor_transaction_destroy(trans);
   532     razor_atomic_destroy(atomic);
   533     return retval;
   534 }
   535 
   536 /*
   537  * Note: If there are no installed files, then any prefix will match.
   538  */
   539 
   540 int plover_installed_files_match_prefix(const char *prefix)
   541 {
   542     int len,matches=1;
   543     const char *name;
   544     char *install_root;
   545     struct razor_set *set;
   546     struct razor_atomic *atomic;
   547     struct razor_package *package;
   548     struct razor_package_iterator *pi;
   549     struct razor_file_iterator *fi;
   550     len=strlen(prefix);
   551     while(len && prefix[len-1]=='/')
   552 	len--;
   553     install_root=getenv("RAZOR_ROOT");
   554     if (!install_root)
   555 	install_root="";
   556     atomic=razor_atomic_open("Query packages");
   557     set=razor_root_open_read_only(install_root,atomic);
   558     if (set)
   559     {
   560 	pi=razor_package_iterator_create(set);
   561 	while (matches &&
   562 	  razor_package_iterator_next(pi,&package,RAZOR_DETAIL_LAST))
   563 	{
   564 	    fi=razor_file_iterator_create(set,package,0);
   565 	    while (matches && razor_file_iterator_next(fi,&name))
   566 	    {
   567 		if (strncmp(name,prefix,len) ||
   568 		  name[len]!='\0' && name[len]!='/')
   569 		    matches=0;
   570 	    }
   571 	    razor_file_iterator_destroy(fi);
   572 	}
   573 	razor_package_iterator_destroy(pi);
   574 	razor_set_unref(set);
   575     }
   576     razor_atomic_destroy(atomic);
   577     return matches;
   578 }