• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

tools/rpmrepo.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #if defined(WITH_SQLITE)
00008 #include <sqlite3.h>
00009 #ifdef  __LCLINT__
00010 /*@-incondefs -redecl @*/
00011 extern const char *sqlite3_errmsg(sqlite3 *db)
00012         /*@*/;
00013 extern int sqlite3_open(
00014   const char *filename,            /* Database filename (UTF-8) */
00015   /*@out@*/ sqlite3 **ppDb         /* OUT: SQLite db handle */
00016 )
00017         /*@modifies *ppDb @*/;
00018 extern int sqlite3_exec(
00019   sqlite3 *db,                     /* An open database */
00020   const char *sql,                 /* SQL to be evaluted */
00021   int (*callback)(void*,int,char**,char**),  /* Callback function */
00022   void *,                          /* 1st argument to callback */
00023   /*@out@*/ char **errmsg          /* Error msg written here */
00024 )
00025         /*@modifies db, *errmsg @*/;
00026 extern int sqlite3_prepare(
00027   sqlite3 *db,                     /* Database handle */
00028   const char *zSql,                /* SQL statement, UTF-8 encoded */
00029   int nByte,                       /* Maximum length of zSql in bytes. */
00030   /*@out@*/ sqlite3_stmt **ppStmt, /* OUT: Statement handle */
00031   /*@out@*/ const char **pzTail    /* OUT: Pointer to unused portion of zSql */
00032 )
00033         /*@modifies *ppStmt, *pzTail @*/;
00034 extern int sqlite3_reset(sqlite3_stmt *pStmt)
00035         /*@modifies pStmt @*/;
00036 extern int sqlite3_step(sqlite3_stmt *pStmt)
00037         /*@modifies pStmt @*/;
00038 extern int sqlite3_finalize(/*@only@*/ sqlite3_stmt *pStmt)
00039         /*@modifies pStmt @*/;
00040 extern int sqlite3_close(sqlite3 * db)
00041         /*@modifies db @*/;
00042 /*@=incondefs =redecl @*/
00043 #endif
00044 #endif
00045 
00046 #include <rpmio_internal.h>     /* XXX fdInitDigest() et al */
00047 #include <fts.h>
00048 #include <argv.h>
00049 #include <mire.h>
00050 #include <poptIO.h>
00051 
00052 #include <rpmtypes.h>
00053 #include <rpmtag.h>
00054 #include <pkgio.h>
00055 #include <rpmts.h>
00056 
00057 #include "debug.h"
00058 
00059 /*@access FD_t @*/
00060 /*@access miRE @*/
00061 
00062 /*==============================================================*/
00063 
00064 /*@unchecked@*/
00065 static int _repo_debug;
00066 
00067 typedef struct rpmrepo_s * rpmrepo;
00068 typedef struct rpmrfile_s * rpmrfile;
00069 
00073 struct rpmrfile_s {
00074 /*@observer@*/
00075     const char * type;
00076 /*@observer@*/
00077     const char * xml_init;
00078 /*@observer@*/ /*@relnull@*/
00079     const char * xml_qfmt;
00080 /*@observer@*/
00081     const char * xml_fini;
00082 /*@observer@*/
00083     const char ** sql_init;
00084 /*@observer@*/
00085     const char * sql_qfmt;
00086 #ifdef  NOTYET  /* XXX char **?!? */
00087 /*@observer@*/
00088     const char ** sql_fini;
00089 #endif
00090 /*@observer@*/
00091     const char * yaml_init;
00092 /*@observer@*/
00093     const char * yaml_qfmt;
00094 /*@observer@*/
00095     const char * yaml_fini;
00096 /*@observer@*/
00097     const char * Packages_init;
00098 /*@observer@*/
00099     const char * Packages_qfmt;
00100 /*@observer@*/
00101     const char * Packages_fini;
00102 /*@observer@*/
00103     const char * Sources_init;
00104 /*@observer@*/
00105     const char * Sources_qfmt;
00106 /*@observer@*/
00107     const char * Sources_fini;
00108 /*@relnull@*/
00109     FD_t fd;
00110 #if defined(WITH_SQLITE)
00111     sqlite3 * sqldb;
00112 #endif
00113 /*@null@*/
00114     const char * digest;
00115 /*@null@*/
00116     const char * Zdigest;
00117     time_t ctime;
00118 };
00119 
00123 struct rpmrepo_s {
00124     int quiet;
00125     int verbose;
00126     int dryrun;
00127 /*@null@*/
00128     ARGV_t exclude_patterns;
00129 /*@relnull@*/
00130     miRE excludeMire;
00131     int nexcludes;
00132 /*@null@*/
00133     ARGV_t include_patterns;
00134 /*@relnull@*/
00135     miRE includeMire;
00136     int nincludes;
00137 /*@null@*/
00138     const char * basedir;
00139 /*@null@*/
00140     const char * baseurl;
00141 #ifdef  NOTYET
00142 /*@null@*/
00143     const char * groupfile;
00144 #endif
00145     int split;
00146 #if defined(WITH_SQLITE)
00147     int database;
00148 #endif
00149     int pretty;
00150     int checkts;
00151 /*@relnull@*/
00152     const char * outputdir;
00153 
00154     int nofollow;
00155 /*@null@*/
00156     ARGV_t manifests;
00157 
00158 /*@observer@*/ /*@relnull@*/
00159     const char * tempdir;
00160 /*@observer@*/ /*@relnull@*/
00161     const char * finaldir;
00162 /*@observer@*/ /*@relnull@*/
00163     const char * olddir;
00164 
00165     time_t mdtimestamp;
00166 
00167     int uniquemdfilenames;
00168 
00169 /*@null@*/
00170     rpmts ts;
00171 /*@null@*/
00172     ARGV_t pkglist;
00173     unsigned current;
00174     unsigned pkgcount;
00175 
00176 /*@null@*/
00177     ARGV_t directories;
00178     int ftsoptions;
00179     uint32_t pkgalgo;
00180     uint32_t algo;
00181     int compression;
00182 /*@observer@*/
00183     const char * markup;
00184 /*@observer@*/ /*@null@*/
00185     const char * suffix;
00186 /*@observer@*/
00187     const char * wmode;
00188 
00189     struct rpmrfile_s primary;
00190     struct rpmrfile_s filelists;
00191     struct rpmrfile_s other;
00192     struct rpmrfile_s repomd;
00193 
00194 };
00195 
00196 /*@unchecked@*/ /*@observer@*/
00197 static const char primary_xml_init[] =
00198 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
00199 "<metadata xmlns=\"http://linux.duke.edu/metadata/common\" xmlns:rpm=\"http://linux.duke.edu/metadata/rpm\" packages=\"0\">\n";
00200 /*@unchecked@*/ /*@observer@*/
00201 static const char primary_xml_fini[] = "</metadata>\n";
00202 
00203 /*@unchecked@*/ /*@observer@*/
00204 static const char filelists_xml_init[] =
00205 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
00206 "<filelists xmlns=\"http://linux.duke.edu/metadata/filelists\" packages=\"0\">\n";
00207 /*@unchecked@*/ /*@observer@*/
00208 static const char filelists_xml_fini[] = "</filelists>\n";
00209 
00210 /*@unchecked@*/ /*@observer@*/
00211 static const char other_xml_init[] =
00212 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
00213 "<otherdata xmlns=\"http://linux.duke.edu/metadata/other\" packages=\"0\">\n";
00214 /*@unchecked@*/ /*@observer@*/
00215 static const char other_xml_fini[] = "</otherdata>\n";
00216 
00217 /*@unchecked@*/ /*@observer@*/
00218 static const char repomd_xml_init[] = "\
00219 <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
00220 <repomd xmlns=\"http://linux.duke.edu/metadata/repo\">\n";
00221 /*@unchecked@*/ /*@observer@*/
00222 static const char repomd_xml_fini[] = "</repomd>\n";
00223 
00224 /* XXX todo: wire up popt aliases and bury the --queryformat glop externally. */
00225 /*@unchecked@*/ /*@observer@*/
00226 static const char primary_xml_qfmt[] =
00227 #include "yum_primary_xml"
00228 ;
00229 
00230 /*@unchecked@*/ /*@observer@*/
00231 static const char filelists_xml_qfmt[] =
00232 #include "yum_filelists_xml"
00233 ;
00234 
00235 /*@unchecked@*/ /*@observer@*/
00236 static const char other_xml_qfmt[] =
00237 #include "yum_other_xml"
00238 ;
00239 
00240 /*@unchecked@*/ /*@observer@*/
00241 static const char primary_yaml_qfmt[] =
00242 #include "wnh_primary_yaml"
00243 ;
00244 
00245 /*@unchecked@*/ /*@observer@*/
00246 static const char filelists_yaml_qfmt[] =
00247 #include "wnh_filelists_yaml"
00248 ;
00249 
00250 /*@unchecked@*/ /*@observer@*/
00251 static const char other_yaml_qfmt[] =
00252 #include "wnh_other_yaml"
00253 ;
00254 
00255 /*@unchecked@*/ /*@observer@*/
00256 static const char Packages_qfmt[] =
00257 #include "deb_Packages"
00258 ;
00259 
00260 /*@unchecked@*/ /*@observer@*/
00261 static const char Sources_qfmt[] =
00262 #include "deb_Sources"
00263 ;
00264 
00265 /*@-nullassign@*/
00266 /*@unchecked@*/ /*@observer@*/
00267 static const char *primary_sql_init[] = {
00268 "PRAGMA synchronous = \"OFF\";",
00269 "pragma locking_mode = \"EXCLUSIVE\";",
00270 "CREATE TABLE conflicts (  pkgKey INTEGER,  name TEXT,  flags TEXT,  epoch TEXT,  version TEXT,  release TEXT );",
00271 "CREATE TABLE db_info (dbversion INTEGER,  checksum TEXT);",
00272 "CREATE TABLE files (  pkgKey INTEGER,  name TEXT,  type TEXT );",
00273 "CREATE TABLE obsoletes (  pkgKey INTEGER,  name TEXT,  flags TEXT,  epoch TEXT,  version TEXT,  release TEXT );",
00274 "CREATE TABLE packages (  pkgKey INTEGER PRIMARY KEY,  pkgId TEXT,  name TEXT,  arch TEXT,  version TEXT,  epoch TEXT,  release TEXT,  summary TEXT,  description TEXT,  url TEXT,  time_file INTEGER,  time_build INTEGER,  rpm_license TEXT,  rpm_vendor TEXT,  rpm_group TEXT,  rpm_buildhost TEXT,  rpm_sourcerpm TEXT,  rpm_header_start INTEGER,  rpm_header_end INTEGER,  rpm_packager TEXT,  size_package INTEGER,  size_installed INTEGER,  size_archive INTEGER,  location_href TEXT,  location_base TEXT,  checksum_type TEXT);",
00275 "CREATE TABLE provides (  pkgKey INTEGER,  name TEXT,  flags TEXT,  epoch TEXT,  version TEXT,  release TEXT );",
00276 "CREATE TABLE requires (  pkgKey INTEGER,  name TEXT,  flags TEXT,  epoch TEXT,  version TEXT,  release TEXT  );",
00277 "CREATE INDEX filenames ON files (name);",
00278 "CREATE INDEX packageId ON packages (pkgId);",
00279 "CREATE INDEX packagename ON packages (name);",
00280 "CREATE INDEX pkgconflicts on conflicts (pkgKey);",
00281 "CREATE INDEX pkgobsoletes on obsoletes (pkgKey);",
00282 "CREATE INDEX pkgprovides on provides (pkgKey);",
00283 "CREATE INDEX pkgrequires on requires (pkgKey);",
00284 "CREATE INDEX providesname ON provides (name);",
00285 "CREATE INDEX requiresname ON requires (name);",
00286 "CREATE TRIGGER removals AFTER DELETE ON packages\
00287 \n    BEGIN\n\
00288 \n    DELETE FROM files WHERE pkgKey = old.pkgKey;\
00289 \n    DELETE FROM requires WHERE pkgKey = old.pkgKey;\
00290 \n    DELETE FROM provides WHERE pkgKey = old.pkgKey;\
00291 \n    DELETE FROM conflicts WHERE pkgKey = old.pkgKey;\
00292 \n    DELETE FROM obsoletes WHERE pkgKey = old.pkgKey;\
00293 \n    END;",
00294 "INSERT into db_info values (9, 'direct_create');",
00295     NULL
00296 };
00297 /*XXX todo: DBVERSION needs to be set */
00298 
00299 /*@unchecked@*/ /*@observer@*/
00300 static const char *filelists_sql_init[] = {
00301 "PRAGMA synchronous = \"OFF\";",
00302 "pragma locking_mode = \"EXCLUSIVE\";",
00303 "CREATE TABLE db_info (dbversion INTEGER, checksum TEXT);",
00304 "CREATE TABLE filelist (  pkgKey INTEGER,  name TEXT,  type TEXT );",
00305 "CREATE TABLE packages (  pkgKey INTEGER PRIMARY KEY,  pkgId TEXT);",
00306 "CREATE INDEX filelistnames ON filelist (name);",
00307 "CREATE INDEX keyfile ON filelist (pkgKey);",
00308 "CREATE INDEX pkgId ON packages (pkgId);",
00309 "CREATE TRIGGER remove_filelist AFTER DELETE ON packages\
00310 \n    BEGIN\
00311 \n    DELETE FROM filelist WHERE pkgKey = old.pkgKey;\
00312 \n    END;",
00313 "INSERT into db_info values (9, 'direct_create');",
00314     NULL
00315 };
00316 /*XXX todo: DBVERSION needs to be set */
00317 
00318 /*@unchecked@*/ /*@observer@*/
00319 static const char *other_sql_init[] = {
00320 "PRAGMA synchronous = \"OFF\";",
00321 "pragma locking_mode = \"EXCLUSIVE\";",
00322 "CREATE TABLE changelog (  pkgKey INTEGER,  author TEXT,  date INTEGER,  changelog TEXT);",
00323 "CREATE TABLE db_info (dbversion INTEGER, checksum TEXT);",
00324 "CREATE TABLE packages (  pkgKey INTEGER PRIMARY KEY,  pkgId TEXT);",
00325 "CREATE INDEX keychange ON changelog (pkgKey);",
00326 "CREATE INDEX pkgId ON packages (pkgId);",
00327 "CREATE TRIGGER remove_changelogs AFTER DELETE ON packages\
00328 \n    BEGIN\
00329 \n    DELETE FROM changelog WHERE pkgKey = old.pkgKey;\
00330 \n    END;",
00331 "INSERT into db_info values (9, 'direct_create');",
00332     NULL
00333 };
00334 /*XXX todo: DBVERSION needs to be set */
00335 /*@=nullassign@*/
00336 
00337 /* packages   1 pkgKey INTEGER PRIMARY KEY */
00338 /* packages   2 pkgId TEXT */
00339 /* packages   3 name TEXT */
00340 /* packages   4 arch TEXT */
00341 /* packages   5 version TEXT */
00342 /* packages   6 epoch TEXT */
00343 /* packages   7 release TEXT */
00344 /* packages   8 summary TEXT */
00345 /* packages   9 description TEXT */
00346 /* packages  10 url TEXT */
00347 /* packages  11 time_file INTEGER */
00348 /* packages  12 time_build INTEGER */
00349 /* packages  13 rpm_license TEXT */
00350 /* packages  14 rpm_vendor TEXT */
00351 /* packages  15 rpm_group TEXT */
00352 /* packages  16 rpm_buildhost TEXT */
00353 /* packages  17 rpm_sourcerpm TEXT */
00354 /* packages  18 rpm_header_start INTEGER */
00355 /* packages  19 rpm_header_end INTEGER */
00356 /* packages  20 rpm_packager TEXT */
00357 /* packages  21 size_package INTEGER */
00358 /* packages  22 size_installed INTEGER */
00359 /* packages  23 size_archive INTEGER */
00360 /* packages  24 location_href TEXT */
00361 /* packages  25 location_base TEXT */
00362 /* packages  26 checksum_type TEXT */
00363 /* obsoletes  1 pkgKey INTEGER */
00364 /* obsoletes  2 name TEXT */
00365 /* obsoletes  3 flags TEXT */
00366 /* obsoletes  4 epoch TEXT */
00367 /* obsoletes  5 version TEXT */
00368 /* obsoletes  6 release TEXT */
00369 /* provides   1 pkgKey INTEGER */
00370 /* provides   2 name TEXT */
00371 /* provides   3 flags TEXT */
00372 /* provides   4 epoch TEXT */
00373 /* provides   5 version TEXT */
00374 /* provides   6 release TEXT */
00375 /* conflicts  1 pkgKey INTEGER */
00376 /* conflicts  2 name TEXT */
00377 /* conflicts  3 flags TEXT */
00378 /* conflicts  4 epoch TEXT */
00379 /* conflicts  5 version TEXT */
00380 /* conflicts  6 release TEXT */
00381 /* requires   1 pkgKey INTEGER */
00382 /* requires   2 name TEXT */
00383 /* requires   3 flags TEXT */
00384 /* requires   4 epoch TEXT */
00385 /* requires   5 version TEXT */
00386 /* requires   6 release TEXT */
00387 /* files      1 pkgKey INTEGER */
00388 /* files      2 name TEXT */
00389 /* files      3 type TEXT */
00390 
00391 /*@unchecked@*/ /*@observer@*/
00392 static const char primary_sql_qfmt[] =
00393 #include "yum_primary_sqlite"
00394 ;
00395 
00396 /* packages  1 pkgKey INTEGER PRIMARY KEY */
00397 /* packages  2 pkgId TEXT */
00398 /* filelist  1 pkgKey INTEGER */
00399 /* filelist  2 name TEXT */
00400 /* filelist  3 type TEXT */
00401 
00402 /*@unchecked@*/ /*@observer@*/
00403 static const char filelists_sql_qfmt[] =
00404 #include "yum_filelists_sqlite"
00405 ;
00406 
00407 /* packages  1 pkgKey INTEGER PRIMARY KEY */
00408 /* packages  2 pkgId TEXT */
00409 /* changelog 1 pkgKey INTEGER */
00410 /* changelog 2 author TEXT */
00411 /* changelog 3 date INTEGER */
00412 /* changelog 4 changelog TEXT */
00413 
00414 /*@unchecked@*/ /*@observer@*/
00415 static const char other_sql_qfmt[] =
00416 #include "yum_other_sqlite"
00417 ;
00418 
00419 /*@-fullinitblock@*/
00420 /*@unchecked@*/
00421 static struct rpmrepo_s __rpmrepo = {
00422     .pretty     = 1,
00423 #if defined(WITH_SQLITE)
00424     .database   = 0,
00425 #endif
00426     .tempdir    = ".repodata",
00427     .finaldir   = "repodata",
00428     .olddir     = ".olddata",
00429     .markup     = ".xml",
00430     .pkgalgo    = PGPHASHALGO_SHA1,
00431     .algo       = PGPHASHALGO_SHA1,
00432     .primary    = {
00433         .type   = "primary",
00434         .xml_init= primary_xml_init,
00435         .xml_qfmt= primary_xml_qfmt,
00436         .xml_fini= primary_xml_fini,
00437         .sql_init= primary_sql_init,
00438         .sql_qfmt= primary_sql_qfmt,
00439 #ifdef  NOTYET  /* XXX char **?!? */
00440         .sql_fini= NULL,
00441 #endif
00442         .yaml_init= NULL,
00443         .yaml_qfmt= primary_yaml_qfmt,
00444         .yaml_fini= NULL,
00445         .Packages_init= NULL,
00446         .Packages_qfmt= NULL,
00447         .Packages_fini= NULL,
00448         .Sources_init= NULL,
00449         .Sources_qfmt= NULL,
00450         .Sources_fini= NULL
00451     },
00452     .filelists  = {
00453         .type   = "filelists",
00454         .xml_init= filelists_xml_init,
00455         .xml_qfmt= filelists_xml_qfmt,
00456         .xml_fini= filelists_xml_fini,
00457         .sql_init= filelists_sql_init,
00458         .sql_qfmt= filelists_sql_qfmt,
00459 #ifdef  NOTYET  /* XXX char **?!? */
00460         .sql_fini= NULL,
00461 #endif
00462         .yaml_init= NULL,
00463         .yaml_qfmt= filelists_yaml_qfmt,
00464         .yaml_fini= NULL,
00465         .Packages_init= NULL,
00466         .Packages_qfmt= NULL,
00467         .Packages_fini= NULL,
00468         .Sources_init= NULL,
00469         .Sources_qfmt= NULL,
00470         .Sources_fini= NULL
00471     },
00472     .other      = {
00473         .type   = "other",
00474         .xml_init= other_xml_init,
00475         .xml_qfmt= other_xml_qfmt,
00476         .xml_fini= other_xml_fini,
00477         .sql_init= other_sql_init,
00478         .sql_qfmt= other_sql_qfmt,
00479 #ifdef  NOTYET  /* XXX char **?!? */
00480         .sql_fini= NULL,
00481 #endif
00482         .yaml_init= NULL,
00483         .yaml_qfmt= other_yaml_qfmt,
00484         .yaml_fini= NULL,
00485         .Packages_init= NULL,
00486         .Packages_qfmt= NULL,
00487         .Packages_fini= NULL,
00488         .Sources_init= NULL,
00489         .Sources_qfmt= NULL,
00490         .Sources_fini= NULL
00491     },
00492     .repomd     = {
00493         .type   = "repomd",
00494         .xml_init= repomd_xml_init,
00495         .xml_qfmt= NULL,
00496         .xml_fini= repomd_xml_fini,
00497         .sql_init= NULL,
00498         .sql_qfmt= NULL,
00499 #ifdef  NOTYET  /* XXX char **?!? */
00500         .sql_fini= NULL,
00501 #endif
00502         .yaml_init= NULL,
00503         .yaml_qfmt= NULL,
00504         .yaml_fini= NULL,
00505         .Packages_init= NULL,
00506         .Packages_qfmt= Packages_qfmt,
00507         .Packages_fini= NULL,
00508         .Sources_init= NULL,
00509         .Sources_qfmt= Sources_qfmt,
00510         .Sources_fini= NULL
00511     }
00512 };
00513 /*@=fullinitblock@*/
00514 
00515 /*@unchecked@*/
00516 static rpmrepo _rpmrepo = &__rpmrepo;
00517 
00518 /*==============================================================*/
00524 /*@mayexit@*/
00525 static void
00526 repo_error(int lvl, const char *fmt, ...)
00527         /*@globals fileSystem @*/
00528         /*@modifies fileSystem @*/
00529 {
00530     va_list ap;
00531 
00532     va_start(ap, fmt);
00533     (void) fflush(NULL);
00534     (void) fprintf(stderr, "%s: ", __progname);
00535     (void) vfprintf(stderr, fmt, ap);
00536     va_end (ap);
00537     (void) fprintf(stderr, "\n");
00538     if (lvl)
00539         exit(EXIT_FAILURE);
00540 }
00541 
00549 static void repoProgress(/*@unused@*/ rpmrepo repo,
00550                 /*@null@*/ const char * item, int current, int total)
00551         /*@globals fileSystem, internalState @*/
00552         /*@modifies fileSystem, internalState @*/
00553 {
00554     static size_t ncols = 80 - 1;       /* XXX TIOCGWINSIZ */
00555     const char * bn = (item != NULL ? strrchr(item, '/') : NULL);
00556     size_t nb;
00557 
00558     if (bn != NULL)
00559         bn++;
00560     else
00561         bn = item;
00562     nb = fprintf(stdout, "\r%s: %d/%d", __progname, current, total);
00563     if (bn != NULL)
00564         nb += fprintf(stdout, " - %s", bn);
00565     nb--;
00566     if (nb < ncols)
00567         fprintf(stdout, "%*s", (int)(ncols - nb), "");
00568     ncols = nb;
00569     (void) fflush(stdout);
00570 }
00571 
00577 static int rpmioExists(const char * fn, /*@out@*/ struct stat * st)
00578         /*@globals h_errno, fileSystem, internalState @*/
00579         /*@modifies st, fileSystem, internalState @*/
00580 {
00581     return (Stat(fn, st) == 0);
00582 }
00583 
00589 static time_t rpmioCtime(const char * fn)
00590         /*@globals h_errno, fileSystem, internalState @*/
00591         /*@modifies fileSystem, internalState @*/
00592 {
00593     struct stat sb;
00594     time_t stctime = 0;
00595 
00596     if (rpmioExists(fn, &sb))
00597         stctime = sb.st_ctime;
00598     return stctime;
00599 }
00600 
00606 /*@null@*/
00607 static const char * repoRealpath(const char * lpath)
00608         /*@globals fileSystem, internalState @*/
00609         /*@modifies fileSystem, internalState @*/
00610 {
00611     /* XXX GLIBC: realpath(path, NULL) return malloc'd */
00612     const char *rpath = Realpath(lpath, NULL);
00613     if (rpath == NULL) {
00614         char fullpath[MAXPATHLEN];
00615         rpath = Realpath(lpath, fullpath);
00616         if (rpath != NULL)
00617             rpath = xstrdup(rpath);
00618     }
00619     return rpath;
00620 }
00621 
00622 /*==============================================================*/
00629 static int repoMkdir(rpmrepo repo, const char * dn)
00630         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00631         /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
00632 {
00633     const char * dnurl = rpmGetPath(repo->outputdir, "/", dn, NULL);
00634 /*@-mods@*/
00635     int ut = urlPath(dnurl, &dn);
00636 /*@=mods@*/
00637     int rc = 0;;
00638 
00639     /* XXX todo: rpmioMkpath doesn't grok URI's */
00640     if (ut == URL_IS_UNKNOWN)
00641         rc = rpmioMkpath(dn, 0755, (uid_t)-1, (gid_t)-1);
00642     else
00643         rc = (Mkdir(dnurl, 0755) == 0 || errno == EEXIST ? 0 : -1);
00644     if (rc)
00645         repo_error(0, _("Cannot create/verify %s: %s"), dnurl, strerror(errno));
00646     dnurl = _free(dnurl);
00647     return rc;
00648 }
00649 
00657 static const char * repoGetPath(rpmrepo repo, const char * dir,
00658                 const char * type, int compress)
00659         /*@globals h_errno, rpmGlobalMacroContext, internalState @*/
00660         /*@modifies rpmGlobalMacroContext, internalState @*/
00661 {
00662     return rpmGetPath(repo->outputdir, "/", dir, "/", type,
00663                 (repo->markup != NULL ? repo->markup : ""),
00664                 (repo->suffix != NULL && compress ? repo->suffix : ""), NULL);
00665 }
00666 
00672 static int repoTestSetupDirs(rpmrepo repo)
00673         /*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/
00674         /*@modifies repo, rpmGlobalMacroContext, fileSystem, internalState @*/
00675 {
00676     const char ** directories = repo->directories;
00677     struct stat sb, *st = &sb;
00678     const char * dn;
00679     const char * fn;
00680     int rc = 0;
00681 
00682     /* XXX todo: check repo->pkglist existence? */
00683 
00684     if (directories != NULL)
00685     while ((dn = *directories++) != NULL) {
00686         if (!rpmioExists(dn, st) || !S_ISDIR(st->st_mode)) {
00687             repo_error(0, _("Directory %s must exist"), dn);
00688             rc = 1;
00689         }
00690     }
00691 
00692     /* XXX todo create outputdir if it doesn't exist? */
00693     if (!rpmioExists(repo->outputdir, st)) {
00694         repo_error(0, _("Directory %s does not exist."), repo->outputdir);
00695         rc = 1;
00696     }
00697     if (Access(repo->outputdir, W_OK)) {
00698         repo_error(0, _("Directory %s must be writable."), repo->outputdir);
00699         rc = 1;
00700     }
00701 
00702     if (repoMkdir(repo, repo->tempdir)
00703      || repoMkdir(repo, repo->finaldir))
00704         rc = 1;
00705 
00706     dn = rpmGetPath(repo->outputdir, "/", repo->olddir, NULL);
00707     if (rpmioExists(dn, st)) {
00708         repo_error(0, _("Old data directory exists, please remove: %s"), dn);
00709         rc = 1;
00710     }
00711     dn = _free(dn);
00712 
00713   { /*@observer@*/
00714     static const char * dirs[] = { ".repodata", "repodata", NULL };
00715     /*@observer@*/
00716     static const char * types[] =
00717         { "primary", "filelists", "other", "repomd", NULL };
00718     const char ** dirp, ** typep;
00719     for (dirp = dirs; *dirp != NULL; dirp++) {
00720         for (typep = types; *typep != NULL; typep++) {
00721             fn = repoGetPath(repo, *dirp, *typep, strcmp(*typep, "repomd"));
00722             if (rpmioExists(fn, st)) {
00723                 if (Access(fn, W_OK)) {
00724                     repo_error(0, _("Path must be writable: %s"), fn);
00725                     rc = 1;
00726                 } else
00727                 if (repo->checkts && st->st_ctime > repo->mdtimestamp)
00728                     repo->mdtimestamp = st->st_ctime;
00729             }
00730             fn = _free(fn);
00731         }
00732     }
00733   }
00734 
00735 #ifdef  NOTYET          /* XXX repo->package_dir needs to go away. */
00736     if (repo->groupfile != NULL) {
00737         if (repo->split || repo->groupfile[0] != '/') {
00738             fn = rpmGetPath(repo->package_dir, "/", repo->groupfile, NULL);
00739             repo->groupfile = _free(repo->groupfile);
00740             repo->groupfile = fn;
00741             fn = NULL;
00742         }
00743         if (!rpmioExists(repo->groupfile, st)) {
00744             repo_error(0, _("groupfile %s cannot be found."), repo->groupfile);
00745             rc = 1;
00746         }
00747     }
00748 #endif
00749     return rc;
00750 }
00751 
00758 static int chkSuffix(const char * fn, const char * suffix)
00759         /*@*/
00760 {
00761     size_t flen = strlen(fn);
00762     size_t slen = strlen(suffix);
00763     return (flen > slen && !strcmp(fn + flen - slen, suffix));
00764 }
00765 
00773 /*@null@*/
00774 static const char ** repoGetFileList(rpmrepo repo, const char *roots[],
00775                 const char * ext)
00776         /*@globals fileSystem, internalState @*/
00777         /*@modifies repo, fileSystem, internalState @*/
00778 {
00779     const char ** pkglist = NULL;
00780     FTS * t;
00781     FTSENT * p;
00782     int xx;
00783 
00784     if ((t = Fts_open((char *const *)roots, repo->ftsoptions, NULL)) == NULL)
00785         repo_error(1, _("Fts_open: %s"), strerror(errno));
00786 
00787     while ((p = Fts_read(t)) != NULL) {
00788 #ifdef  NOTYET
00789         const char * fts_name = p->fts_name;
00790         size_t fts_namelen = p->fts_namelen;
00791 
00792         /* XXX fts(3) (and Fts(3)) have fts_name = "" with pesky trailing '/' */
00793         if (p->fts_level == 0 && fts_namelen == 0) {
00794             fts_name = ".";
00795             fts_namelen = sizeof(".") - 1;
00796         }
00797 #endif
00798 
00799         /* Should this element be excluded/included? */
00800         /* XXX todo: apply globs to fts_path rather than fts_name? */
00801 /*@-onlytrans@*/
00802         if (mireApply(repo->excludeMire, repo->nexcludes, p->fts_name, 0, -1) >= 0)
00803             continue;
00804         if (mireApply(repo->includeMire, repo->nincludes, p->fts_name, 0, +1) < 0)
00805             continue;
00806 /*@=onlytrans@*/
00807 
00808         switch (p->fts_info) {
00809         case FTS_D:
00810         case FTS_DP:
00811         default:
00812             continue;
00813             /*@notreached@*/ /*@switchbreak@*/ break;
00814         case FTS_SL:
00815             if (repo->nofollow)
00816                 continue;
00817             /* XXX todo: fuss with symlinks */
00818             /*@notreached@*/ /*@switchbreak@*/ break;
00819         case FTS_F:
00820             /* Is this a *.rpm file? */
00821             if (chkSuffix(p->fts_name, ext))
00822                 xx = argvAdd(&pkglist, p->fts_path);
00823             /*@switchbreak@*/ break;
00824         }
00825     }
00826 
00827     (void) Fts_close(t);
00828 
00829 if (_repo_debug)
00830 argvPrint("pkglist", pkglist, NULL);
00831 
00832     return pkglist;
00833 }
00834 
00840 static int repoCheckTimeStamps(rpmrepo repo)
00841         /*@globals h_errno, fileSystem, internalState @*/
00842         /*@modifies fileSystem, internalState @*/
00843 {
00844     int rc = 0;
00845 
00846     if (repo->checkts) {
00847         const char ** pkg;
00848 
00849         if (repo->pkglist != NULL)
00850         for (pkg = repo->pkglist; *pkg != NULL ; pkg++) {
00851             struct stat sb, *st = &sb;
00852             if (!rpmioExists(*pkg, st)) {
00853                 repo_error(0, _("cannot get to file: %s"), *pkg);
00854                 rc = 1;
00855             } else if (st->st_ctime > repo->mdtimestamp)
00856                 rc = 1;
00857         }
00858     } else
00859         rc = 1;
00860 
00861     return rc;
00862 }
00863 
00870 static int rfileXMLWrite(rpmrfile rfile, /*@only@*/ /*@null@*/ const char * spew)
00871         /*@globals fileSystem @*/
00872         /*@modifies rfile, fileSystem @*/
00873 {
00874     size_t nspew = (spew != NULL ? strlen(spew) : 0);
00875 /*@-nullpass@*/ /* XXX spew != NULL @*/
00876     size_t nb = (nspew > 0 ? Fwrite(spew, 1, nspew, rfile->fd) : 0);
00877 /*@=nullpass@*/
00878     int rc = 0;
00879     if (nspew != nb) {
00880         repo_error(0, _("Fwrite failed: expected write %u != %u bytes: %s\n"),
00881                 (unsigned)nspew, (unsigned)nb, Fstrerror(rfile->fd));
00882         rc = 1;
00883     }
00884     spew = _free(spew);
00885     return rc;
00886 }
00887 
00894 static int repoFclose(rpmrepo repo, FD_t fd)
00895         /*@modifies repo, fd @*/
00896 {
00897     int rc = 0;
00898 
00899     if (fd != NULL) {
00900         if (repo->ts != NULL) {
00901             (void) rpmswAdd(rpmtsOp(repo->ts, RPMTS_OP_UNCOMPRESS),
00902                         fdstat_op(fd, FDSTAT_READ));
00903             (void) rpmswAdd(rpmtsOp(repo->ts, RPMTS_OP_DIGEST),
00904                         fdstat_op(fd, FDSTAT_DIGEST));
00905         }
00906         rc = Fclose(fd);
00907     }
00908     return rc;
00909 }
00910 
00917 static int repoOpenMDFile(const rpmrepo repo, rpmrfile rfile)
00918         /*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/
00919         /*@modifies rfile, rpmGlobalMacroContext, fileSystem, internalState @*/
00920 {
00921     const char * spew = rfile->xml_init;
00922     size_t nspew = strlen(spew);
00923     const char * fn = repoGetPath(repo, repo->tempdir, rfile->type, 1);
00924     const char * tail;
00925     size_t nb;
00926     int rc = 0;
00927 
00928     rfile->fd = Fopen(fn, repo->wmode);
00929 assert(rfile->fd != NULL);
00930 
00931     if (repo->algo != PGPHASHALGO_NONE)
00932         fdInitDigest(rfile->fd, repo->algo, 0);
00933 
00934     if ((tail = strstr(spew, " packages=\"0\">\n")) != NULL)
00935         nspew -= strlen(tail);
00936 
00937     nb = Fwrite(spew, 1, nspew, rfile->fd);
00938 
00939     if (tail != NULL) {
00940         char buf[64];
00941         size_t tnb = snprintf(buf, sizeof(buf), " packages=\"%d\">\n",
00942                                 repo->pkgcount);
00943         nspew += tnb;
00944         nb += Fwrite(buf, 1, tnb, rfile->fd);
00945     }
00946     if (nspew != nb) {
00947         repo_error(0, _("Fwrite failed: expected write %u != %u bytes: %s\n"),
00948                 (unsigned)nspew, (unsigned)nb, Fstrerror(rfile->fd));
00949         rc = 1;
00950     }
00951 
00952     fn = _free(fn);
00953 
00954 #if defined(WITH_SQLITE)
00955     if (repo->database) {
00956         const char ** stmt;
00957         int xx;
00958         fn = rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
00959                 rfile->type, ".sqlite", NULL);
00960         if ((xx = sqlite3_open(fn, &rfile->sqldb)) != SQLITE_OK)
00961             repo_error(1, "sqlite3_open(%s): %s", fn, sqlite3_errmsg(rfile->sqldb));
00962         for (stmt = rfile->sql_init; *stmt != NULL; stmt++) {
00963             char * msg;
00964             xx = sqlite3_exec(rfile->sqldb, *stmt, NULL, NULL, &msg);
00965             if (xx != SQLITE_OK)
00966                 repo_error(1, "sqlite3_exec(%s, \"%s\"): %s\n", fn, *stmt,
00967                         (msg != NULL ? msg : "failed"));
00968         }
00969         fn = _free(fn);
00970     }
00971 #endif
00972 
00973     return rc;
00974 }
00975 
00982 static Header repoReadHeader(rpmrepo repo, const char * path)
00983         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00984         /*@modifies repo, rpmGlobalMacroContext, fileSystem, internalState @*/
00985 {
00986     /* XXX todo: read the payload and collect the blessed file digest. */
00987     FD_t fd = Fopen(path, "r.ufdio");
00988     Header h = NULL;
00989 
00990     if (fd != NULL) {
00991         uint32_t algo = repo->pkgalgo;
00992         rpmRC rpmrc;
00993 
00994         if (algo != PGPHASHALGO_NONE)
00995             fdInitDigest(fd, algo, 0);
00996 
00997         /* XXX what if path needs expansion? */
00998         rpmrc = rpmReadPackageFile(repo->ts, fd, path, &h);
00999         if (algo != PGPHASHALGO_NONE) {
01000             char buffer[32 * BUFSIZ];
01001             size_t nb = sizeof(buffer);
01002             size_t nr;
01003             while ((nr = Fread(buffer, sizeof(buffer[0]), nb, fd)) == nb)
01004                 {};
01005             if (Ferror(fd)) {
01006                 fprintf(stderr, _("%s: Fread(%s) failed: %s\n"),
01007                         __progname, path, Fstrerror(fd));
01008                 rpmrc = RPMRC_FAIL;
01009             } else {
01010                 static int asAscii = 1;
01011                 const char *digest = NULL;
01012                 fdFiniDigest(fd, algo, &digest, NULL, asAscii);
01013                 (void) headerSetDigest(h, digest);
01014                 digest = _free(digest);
01015             }
01016         }
01017 
01018         (void) Fclose(fd);
01019 
01020         switch (rpmrc) {
01021         case RPMRC_NOTFOUND:
01022         case RPMRC_FAIL:
01023         default:
01024             (void)headerFree(h);
01025             h = NULL;
01026             break;
01027         case RPMRC_NOTTRUSTED:
01028         case RPMRC_NOKEY:
01029         case RPMRC_OK:
01030             if (repo->baseurl)
01031                 (void) headerSetBaseURL(h, repo->baseurl);
01032             break;
01033         }
01034     }
01035     return h;
01036 }
01037 
01044 static const char * rfileHeaderSprintf(Header h, const char * qfmt)
01045         /*@globals fileSystem @*/
01046         /*@modifies h, fileSystem @*/
01047 {
01048     const char * msg = NULL;
01049     const char * s = headerSprintf(h, qfmt, NULL, NULL, &msg);
01050     if (s == NULL)
01051         repo_error(1, _("headerSprintf(%s): %s"), qfmt, msg);
01052 assert(s != NULL);
01053     return s;
01054 }
01055 
01056 #if defined(WITH_SQLITE)
01057 
01062 static int rfileSQL(rpmrfile rfile, const char * msg, int rc)
01063         /*@globals fileSystem @*/
01064         /*@modifies fileSystem @*/
01065 {
01066     if (rc != SQLITE_OK || _repo_debug)
01067         repo_error(0, "sqlite3_%s(%s): %s", msg, rfile->type,
01068                 sqlite3_errmsg(rfile->sqldb));
01069     return rc;
01070 }
01071 
01077 static int rfileSQLStep(rpmrfile rfile, sqlite3_stmt * stmt)
01078         /*@globals fileSystem @*/
01079         /*@modifies fileSystem @*/
01080 {
01081     int loop = 1;
01082     int rc = 0;
01083     int xx;
01084 
01085 /*@-infloops@*/
01086     while (loop) {
01087         rc = sqlite3_step(stmt);
01088         switch (rc) {
01089         default:
01090             rc = rfileSQL(rfile, "step", rc);
01091             /*@fallthrough@*/
01092         case SQLITE_DONE:
01093             loop = 0;
01094             /*@switchbreak@*/ break;
01095         }
01096     }
01097 /*@=infloops@*/
01098 
01099     xx = rfileSQL(rfile, "reset",
01100         sqlite3_reset(stmt));
01101 
01102     return rc;
01103 }
01104 
01111 static const char * rfileHeaderSprintfHack(Header h, const char * qfmt)
01112         /*@globals fileSystem @*/
01113         /*@modifies h, fileSystem @*/
01114 {
01115     static const char mark[] = "'XXX'";
01116     static size_t nmark = sizeof("'XXX'") - 1;
01117     const char * msg = NULL;
01118     char * s = (char *) headerSprintf(h, qfmt, NULL, NULL, &msg);
01119     char * f, * fe;
01120     int nsubs = 0;
01121 
01122     if (s == NULL)
01123         repo_error(1, _("headerSprintf(%s): %s"), qfmt, msg);
01124 assert(s != NULL);
01125 
01126     /* XXX Find & replace 'XXX' with '%{DBINSTANCE}' the hard way. */
01127 /*@-nullptrarith@*/
01128     for (f = s; *f != '\0' && (fe = strstr(f, "'XXX'")) != NULL; fe += nmark, f = fe)
01129         nsubs++;
01130 /*@=nullptrarith@*/
01131 
01132     if (nsubs > 0) {
01133         char instance[64];
01134         int xx = snprintf(instance, sizeof(instance), "'%u'",
01135                 (unsigned) headerGetInstance(h));
01136         size_t tlen = strlen(s) + nsubs * ((int)strlen(instance) - (int)nmark);
01137         char * t = xmalloc(tlen + 1);
01138         char * te = t;
01139 
01140         xx = xx;
01141 /*@-nullptrarith@*/
01142         for (f = s; *f != '\0' && (fe = strstr(f, mark)) != NULL; fe += nmark, f = fe) {
01143             *fe = '\0';
01144             te = stpcpy( stpcpy(te, f), instance);
01145         }
01146 /*@=nullptrarith@*/
01147         if (*f != '\0')
01148             te = stpcpy(te, f);
01149         s = _free(s);
01150         s = t;
01151     }
01152  
01153     return s;
01154 }
01155 
01162 static int rfileSQLWrite(rpmrfile rfile, /*@only@*/ const char * cmd)
01163         /*@globals fileSystem @*/
01164         /*@modifies fileSystem @*/
01165 {
01166     sqlite3_stmt * stmt;
01167     const char * tail;
01168     int xx;
01169 
01170     xx = rfileSQL(rfile, "prepare",
01171         sqlite3_prepare(rfile->sqldb, cmd, (int)strlen(cmd), &stmt, &tail));
01172 
01173     xx = rfileSQL(rfile, "reset",
01174         sqlite3_reset(stmt));
01175 
01176     xx = rfileSQLStep(rfile, stmt);
01177 
01178     xx = rfileSQL(rfile, "finalize",
01179         sqlite3_finalize(stmt));
01180 
01181     cmd = _free(cmd);
01182 
01183     return 0;
01184 }
01185 #endif
01186 
01194 static int repoWriteMDFile(rpmrepo repo, rpmrfile rfile, Header h)
01195         /*@globals fileSystem @*/
01196         /*@modifies rfile, h, fileSystem @*/
01197 {
01198     int rc = 0;
01199 
01200     if (rfile->xml_qfmt != NULL) {
01201         if (rfileXMLWrite(rfile, rfileHeaderSprintf(h, rfile->xml_qfmt)))
01202             rc = 1;
01203     }
01204 
01205 #if defined(WITH_SQLITE)
01206     if (repo->database) {
01207         if (rfileSQLWrite(rfile, rfileHeaderSprintfHack(h, rfile->sql_qfmt)))
01208             rc = 1;
01209     }
01210 #endif
01211 
01212     return rc;
01213 }
01214 
01221 static int repoWriteMetadataDocs(rpmrepo repo, /*@null@*/ const char ** pkglist)
01222         /*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/
01223         /*@modifies repo, rpmGlobalMacroContext, fileSystem, internalState @*/
01224 {
01225     const char * pkg;
01226     int rc = 0;
01227 
01228     while ((pkg = *pkglist++) != NULL) {
01229         Header h = repoReadHeader(repo, pkg);
01230 
01231         repo->current++;
01232         if (h == NULL) {
01233 #ifdef  DYING   /* XXX repoReadHeader() displays error. Continuing is foolish */
01234             repo_error(0, _("\nError %s: %s\n"), pkg, strerror(errno));
01235             continue;
01236 #else
01237             rc = 1;
01238             break;
01239 #endif
01240         }
01241         (void) headerSetInstance(h, (uint32_t)repo->current);
01242 
01243 #ifdef  NOTYET
01244         /* XXX todo: rpmGetPath(mydir, "/", filematrix[mydir], NULL); */
01245         reldir = (pkgpath != NULL ? pkgpath : rpmGetPath(repo->basedir, "/", repo->directories[0], NULL));
01246         self.primaryfile.write(po.do_primary_xml_dump(reldir, baseurl=repo->baseurl))
01247         self.flfile.write(po.do_filelists_xml_dump())
01248         self.otherfile.write(po.do_other_xml_dump())
01249 #endif
01250         if (repoWriteMDFile(repo, &repo->primary, h)
01251          || repoWriteMDFile(repo, &repo->filelists, h)
01252          || repoWriteMDFile(repo, &repo->other, h))
01253             rc = 1;
01254 
01255         (void)headerFree(h);
01256         h = NULL;
01257         if (rc) break;
01258 
01259         if (!repo->quiet) {
01260             if (repo->verbose)
01261                 repo_error(0, "%d/%d - %s", repo->current, repo->pkgcount, pkg);
01262             else
01263                 repoProgress(repo, pkg, repo->current, repo->pkgcount);
01264         }
01265     }
01266     return rc;
01267 }
01268 
01273 static int repoRfileDigest(const rpmrepo repo, rpmrfile rfile,
01274                 const char ** digestp)
01275         /*@modifies *digestp @*/
01276 {
01277     static int asAscii = 1;
01278     struct stat sb, *st = &sb;
01279     const char * fn = repoGetPath(repo, repo->tempdir, rfile->type, 1);
01280     const char * path = NULL;
01281     int ut = urlPath(fn, &path);
01282     FD_t fd = NULL;
01283     int rc = 1;
01284     int xx;
01285 
01286     memset(st, 0, sizeof(*st));
01287     if (!rpmioExists(fn, st))
01288         goto exit;
01289     fd = Fopen(fn, "r.ufdio");
01290     if (fd == NULL || Ferror(fd))
01291         goto exit;
01292 
01293     switch (ut) {
01294     case URL_IS_PATH:
01295     case URL_IS_UNKNOWN:
01296 #if defined(HAVE_MMAP)
01297     {   void * mapped = (void *)-1;
01298 
01299         if (st->st_size > 0)
01300             mapped = mmap(NULL, st->st_size, PROT_READ, MAP_SHARED, Fileno(fd), 0);
01301         if (mapped != (void *)-1) {
01302             rpmop op = rpmtsOp(repo->ts, RPMTS_OP_DIGEST);
01303             rpmtime_t tstamp = rpmswEnter(op, 0);
01304             DIGEST_CTX ctx = rpmDigestInit(repo->algo, RPMDIGEST_NONE);
01305             xx = rpmDigestUpdate(ctx, mapped, st->st_size);
01306             xx = rpmDigestFinal(ctx, digestp, NULL, asAscii);
01307             tstamp = rpmswExit(op, st->st_size);
01308             xx = munmap(mapped, st->st_size);
01309             break;
01310         }
01311     }   /*@fallthrough@*/
01312 #endif
01313     default:
01314     {   char buf[64 * BUFSIZ];
01315         size_t nb;
01316         size_t fsize = 0;
01317 
01318         fdInitDigest(fd, repo->algo, 0);
01319         while ((nb = Fread(buf, sizeof(buf[0]), sizeof(buf), fd)) > 0)
01320             fsize += nb;
01321         if (Ferror(fd))
01322             goto exit;
01323         fdFiniDigest(fd, repo->algo, digestp, NULL, asAscii);
01324     }   break;
01325     }
01326 
01327     rc = 0;
01328 
01329 exit:
01330     if (fd)
01331         xx = repoFclose(repo, fd);
01332     fn = _free(fn);
01333     return rc;
01334 }
01335 
01342 static int repoCloseMDFile(const rpmrepo repo, rpmrfile rfile)
01343         /*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/
01344         /*@modifies rfile, rpmGlobalMacroContext, fileSystem, internalState @*/
01345 {
01346     static int asAscii = 1;
01347     char * xmlfn = xstrdup(fdGetOPath(rfile->fd));
01348     int rc = 0;
01349 
01350     if (!repo->quiet)
01351         repo_error(0, _("Saving %s metadata"), basename(xmlfn));
01352 
01353     if (rfileXMLWrite(rfile, xstrdup(rfile->xml_fini)))
01354         rc = 1;
01355 
01356     if (repo->algo > 0)
01357         fdFiniDigest(rfile->fd, repo->algo, &rfile->digest, NULL, asAscii);
01358     else
01359         rfile->digest = xstrdup("");
01360 
01361     (void) repoFclose(repo, rfile->fd);
01362     rfile->fd = NULL;
01363 
01364     /* Compute the (usually compressed) ouput file digest too. */
01365     rfile->Zdigest = NULL;
01366     (void) repoRfileDigest(repo, rfile, &rfile->Zdigest);
01367 
01368 #if defined(WITH_SQLITE)
01369     if (repo->database && rfile->sqldb != NULL) {
01370         const char *dbfn = rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
01371                 rfile->type, ".sqlite", NULL);
01372         int xx;
01373         if ((xx = sqlite3_close(rfile->sqldb)) != SQLITE_OK)
01374             repo_error(1, "sqlite3_close(%s): %s", dbfn, sqlite3_errmsg(rfile->sqldb));
01375         rfile->sqldb = NULL;
01376         dbfn = _free(dbfn);
01377     }
01378 #endif
01379 
01380     rfile->ctime = rpmioCtime(xmlfn);
01381     xmlfn = _free(xmlfn);
01382 
01383     return rc;
01384 }
01385 
01391 static int repoDoPkgMetadata(rpmrepo repo)
01392         /*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/
01393         /*@modifies repo, rpmGlobalMacroContext, fileSystem, internalState @*/
01394 {
01395     int rc = 0;
01396 
01397     repo->current = 0;
01398 
01399 #ifdef  NOTYET
01400     def _getFragmentUrl(self, url, fragment):
01401         import urlparse
01402         urlparse.uses_fragment.append('media')
01403         if not url:
01404             return url
01405         (scheme, netloc, path, query, fragid) = urlparse.urlsplit(url)
01406         return urlparse.urlunsplit((scheme, netloc, path, query, str(fragment)))
01407 
01408     def doPkgMetadata(self):
01409         """all the heavy lifting for the package metadata"""
01410         if (argvCount(repo->directories) == 1) {
01411             MetaDataGenerator.doPkgMetadata(self)
01412             return
01413         }
01414 
01415     ARGV_t roots = NULL;
01416     filematrix = {}
01417     for mydir in repo->directories {
01418         if (mydir[0] == '/')
01419             thisdir = xstrdup(mydir);
01420         else if (mydir[0] == '.' && mydir[1] == '.' && mydir[2] == '/')
01421             thisdir = Realpath(mydir, NULL);
01422         else
01423             thisdir = rpmGetPath(repo->basedir, "/", mydir, NULL);
01424 
01425         xx = argvAdd(&roots, thisdir);
01426         thisdir = _free(thisdir);
01427 
01428         filematrix[mydir] = repoGetFileList(repo, roots, '.rpm')
01429         self.trimRpms(filematrix[mydir])
01430         repo->pkgcount = argvCount(filematrix[mydir]);
01431         roots = argvFree(roots);
01432     }
01433 
01434     mediano = 1;
01435     repo->baseurl = self._getFragmentUrl(repo->baseurl, mediano)
01436 #endif
01437 
01438     if (repoOpenMDFile(repo, &repo->primary)
01439      || repoOpenMDFile(repo, &repo->filelists)
01440      || repoOpenMDFile(repo, &repo->other))
01441         rc = 1;
01442     if (rc) return rc;
01443 
01444 #ifdef  NOTYET
01445     for mydir in repo->directories {
01446         repo->baseurl = self._getFragmentUrl(repo->baseurl, mediano)
01447         /* XXX todo: rpmGetPath(mydir, "/", filematrix[mydir], NULL); */
01448         if (repoWriteMetadataDocs(repo, filematrix[mydir]))
01449             rc = 1;
01450         mediano++;
01451     }
01452     repo->baseurl = self._getFragmentUrl(repo->baseurl, 1)
01453 #else
01454     if (repoWriteMetadataDocs(repo, repo->pkglist))
01455         rc = 1;
01456 #endif
01457 
01458     if (!repo->quiet)
01459         fprintf(stderr, "\n");
01460     if (repoCloseMDFile(repo, &repo->primary)
01461      || repoCloseMDFile(repo, &repo->filelists)
01462      || repoCloseMDFile(repo, &repo->other))
01463         rc = 1;
01464 
01465     return rc;
01466 }
01467 
01470 static /*@observer@*/ /*@null@*/ const char *
01471 algo2tagname(uint32_t algo)
01472         /*@*/
01473 {
01474     const char * tagname = NULL;
01475 
01476     switch (algo) {
01477     case PGPHASHALGO_NONE:      tagname = "none";       break;
01478     case PGPHASHALGO_MD5:       tagname = "md5";        break;
01479     /* XXX todo: should be "sha1" */
01480     case PGPHASHALGO_SHA1:      tagname = "sha";        break;
01481     case PGPHASHALGO_RIPEMD160: tagname = "rmd160";     break;
01482     case PGPHASHALGO_MD2:       tagname = "md2";        break;
01483     case PGPHASHALGO_TIGER192:  tagname = "tiger192";   break;
01484     case PGPHASHALGO_HAVAL_5_160: tagname = "haval160"; break;
01485     case PGPHASHALGO_SHA256:    tagname = "sha256";     break;
01486     case PGPHASHALGO_SHA384:    tagname = "sha384";     break;
01487     case PGPHASHALGO_SHA512:    tagname = "sha512";     break;
01488     case PGPHASHALGO_MD4:       tagname = "md4";        break;
01489     case PGPHASHALGO_RIPEMD128: tagname = "rmd128";     break;
01490     case PGPHASHALGO_CRC32:     tagname = "crc32";      break;
01491     case PGPHASHALGO_ADLER32:   tagname = "adler32";    break;
01492     case PGPHASHALGO_CRC64:     tagname = "crc64";      break;
01493     case PGPHASHALGO_JLU32:     tagname = "jlu32";      break;
01494     case PGPHASHALGO_SHA224:    tagname = "sha224";     break;
01495     case PGPHASHALGO_RIPEMD256: tagname = "rmd256";     break;
01496     case PGPHASHALGO_RIPEMD320: tagname = "rmd320";     break;
01497     case PGPHASHALGO_SALSA10:   tagname = "salsa10";    break;
01498     case PGPHASHALGO_SALSA20:   tagname = "salsa20";    break;
01499     default:                    tagname = NULL;         break;
01500     }
01501     return tagname;
01502 }
01503 
01509 static const char * repoMDExpand(rpmrepo repo, rpmrfile rfile)
01510         /*@globals h_errno, rpmGlobalMacroContext, internalState @*/
01511         /*@modifies rpmGlobalMacroContext, internalState @*/
01512 {
01513     const char * spewalgo = algo2tagname(repo->algo);
01514     char spewtime[64];
01515 
01516     (void) snprintf(spewtime, sizeof(spewtime), "%u", (unsigned)rfile->ctime);
01517     return rpmExpand("\
01518   <data type=\"", rfile->type, "\">\n\
01519     <checksum type=\"", spewalgo, "\">", rfile->Zdigest, "</checksum>\n\
01520     <timestamp>", spewtime, "</timestamp>\n\
01521     <open-checksum type=\"",spewalgo,"\">", rfile->digest, "</open-checksum>\n\
01522     <location href=\"", repo->finaldir, "/", rfile->type, (repo->markup != NULL ? repo->markup : ""), (repo->suffix != NULL ? repo->suffix : ""), "\"/>\n\
01523   </data>\n", NULL);
01524 }
01525 
01531 static int repoDoRepoMetadata(rpmrepo repo)
01532         /*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/
01533         /*@modifies repo, rpmGlobalMacroContext, fileSystem, internalState @*/
01534 {
01535     rpmrfile rfile = &repo->repomd;
01536     const char * fn = repoGetPath(repo, repo->tempdir, rfile->type, 0);
01537     int rc = 0;
01538 
01539     if ((rfile->fd = Fopen(fn, "w.ufdio")) != NULL) {   /* no compression */
01540         if (rfileXMLWrite(rfile, xstrdup(rfile->xml_init))
01541          || rfileXMLWrite(rfile, repoMDExpand(repo, &repo->other))
01542          || rfileXMLWrite(rfile, repoMDExpand(repo, &repo->filelists))
01543          || rfileXMLWrite(rfile, repoMDExpand(repo, &repo->primary))
01544          || rfileXMLWrite(rfile, xstrdup(rfile->xml_fini)))
01545             rc = 1;
01546         (void) repoFclose(repo, rfile->fd);
01547         rfile->fd = NULL;
01548     }
01549 
01550     fn = _free(fn);
01551     if (rc) return rc;
01552 
01553 #ifdef  NOTYET
01554     def doRepoMetadata(self):
01555         """wrapper to generate the repomd.xml file that stores the info on the other files"""
01556     const char * repopath =
01557                 rpmGetPath(repo->outputdir, "/", repo->tempdir, NULL);
01558         repodoc = libxml2.newDoc("1.0")
01559         reporoot = repodoc.newChild(None, "repomd", None)
01560         repons = reporoot.newNs("http://linux.duke.edu/metadata/repo", None)
01561         reporoot.setNs(repons)
01562         repopath = rpmGetPath(repo->outputdir, "/", repo->tempdir, NULL);
01563         fn = repoGetPath(repo, repo->tempdir, repo->repomd.type, 1);
01564 
01565         repoid = "garbageid";
01566 
01567         if (repo->database) {
01568             if (!repo->quiet) repo_error(0, _("Generating sqlite DBs"));
01569             try:
01570                 dbversion = str(sqlitecachec.DBVERSION)
01571             except AttributeError:
01572                 dbversion = "9"
01573             rp = sqlitecachec.RepodataParserSqlite(repopath, repoid, None)
01574         }
01575 
01576   { static const char * types[] =
01577         { "primary", "filelists", "other", NULL };
01578     const char ** typep;
01579         for (typep = types; *typep != NULL; typep++) {
01580             complete_path = repoGetPath(repo, repo->tempdir, *typep, 1);
01581 
01582             zfo = _gzipOpen(complete_path)
01583             uncsum = misc.checksum(algo2tagname(repo->algo), zfo)
01584             zfo.close()
01585             csum = misc.checksum(algo2tagname(repo->algo), complete_path)
01586             (void) rpmioExists(complete_path, st)
01587             timestamp = os.stat(complete_path)[8]
01588 
01589             db_csums = {}
01590             db_compressed_sums = {}
01591 
01592             if (repo->database) {
01593                 if (repo->verbose) {
01594                     time_t now = time(NULL);
01595                     repo_error(0, _("Starting %s db creation: %s"),
01596                         *typep, ctime(&now));
01597                 }
01598 
01599                 if (!strcmp(*typep, "primary"))
01600                     rp.getPrimary(complete_path, csum)
01601                 else if (!strcmp(*typep, "filelists"));
01602                     rp.getFilelists(complete_path, csum)
01603                 else if (!strcmp(*typep, "other"))
01604                     rp.getOtherdata(complete_path, csum)
01605 
01606                 {   const char *  tmp_result_path =
01607                         rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
01608                                 *typep, ".xml.gz.sqlite", NULL);
01609                     const char * resultpath =
01610                         rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
01611                                 *typep, ".sqlite", NULL);
01612 
01613                     /* rename from silly name to not silly name */
01614                     xx = Rename(tmp_result_path, resultpath);
01615                     tmp_result_path = _free(tmp_result_path);
01616                     result_compressed =
01617                         rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
01618                                 *typep, ".sqlite.bz2", NULL);
01619                     db_csums[*typep] = misc.checksum(algo2tagname(repo->algo), resultpath)
01620 
01621                     /* compress the files */
01622                     bzipFile(resultpath, result_compressed)
01623                     /* csum the compressed file */
01624                     db_compressed_sums[*typep] = misc.checksum(algo2tagname(repo->algo), result_compressed)
01625                     /* remove the uncompressed file */
01626                     xx = Unlink(resultpath);
01627                     resultpath = _free(resultpath);
01628                 }
01629 
01630                 if (repo->uniquemdfilenames) {
01631                     const char * csum_result_compressed =
01632                         rpmGetPath(repo->outputdir, "/", repo->tempdir, "/",
01633                                 db_compressed_sums[*typep], "-", *typep, ".sqlite.bz2", NULL);
01634                     xx = Rename(result_compressed, csum_result_compressed);
01635                     result_compressed = _free(result_compressed);
01636                     result_compressed = csum_result_compressed;
01637                 }
01638 
01639                 /* timestamp the compressed file */
01640                 (void) rpmioExists(result_compressed, st)
01641                 db_timestamp = os.stat(result_compressed)[8]
01642 
01643                 /* add this data as a section to the repomdxml */
01644                 db_data_type = rpmExpand(*typep, "_db", NULL);
01645                 data = reporoot.newChild(None, 'data', None)
01646                 data.newProp('type', db_data_type)
01647                 location = data.newChild(None, 'location', None)
01648                 if (repo->baseurl != NULL) {
01649                     location.newProp('xml:base', repo->baseurl)
01650                 }
01651 
01652                 location.newProp('href', rpmGetPath(repo->finaldir, "/", *typep, ".sqlite.bz2", NULL));
01653                 checksum = data.newChild(None, 'checksum', db_compressed_sums[*typep])
01654                 checksum.newProp('type', algo2tagname(repo->algo))
01655                 db_tstamp = data.newChild(None, 'timestamp', str(db_timestamp))
01656                 unchecksum = data.newChild(None, 'open-checksum', db_csums[*typep])
01657                 unchecksum.newProp('type', algo2tagname(repo->algo))
01658                 database_version = data.newChild(None, 'database_version', dbversion)
01659                 if (repo->verbose) {
01660                    time_t now = time(NULL);
01661                    repo_error(0, _("Ending %s db creation: %s"),
01662                         *typep, ctime(&now));
01663                 }
01664             }
01665 
01666             data = reporoot.newChild(None, 'data', None)
01667             data.newProp('type', *typep)
01668 
01669             checksum = data.newChild(None, 'checksum', csum)
01670             checksum.newProp('type', algo2tagname(repo->algo))
01671             timestamp = data.newChild(None, 'timestamp', str(timestamp))
01672             unchecksum = data.newChild(None, 'open-checksum', uncsum)
01673             unchecksum.newProp('type', algo2tagname(repo->algo))
01674             location = data.newChild(None, 'location', None)
01675             if (repo->baseurl != NULL)
01676                 location.newProp('xml:base', repo->baseurl)
01677             if (repo->uniquemdfilenames) {
01678                 orig_file = repoGetPath(repo, repo->tempdir, *typep, strcmp(*typep, "repomd"));
01679                 res_file = rpmExpand(csum, "-", *typep,
01680                         (repo->markup ? repo->markup : ""),
01681                         (repo->suffix && strcmp(*typep, "repomd") ? repo->suffix : ""), NULL);
01682                 dest_file = rpmGetPath(repo->outputdir, "/", repo->tempdir, "/", res_file, NULL);
01683                 xx = Rename(orig_file, dest_file);
01684 
01685             } else
01686                 res_file = rpmExpand(*typep,
01687                         (repo->markup ? repo->markup : ""),
01688                         (repo->suffix && strcmp(*typep, "repomd") ? repo->suffix : ""), NULL);
01689 
01690             location.newProp('href', rpmGetPath(repo->finaldir, "/", res_file, NULL));
01691         }
01692   }
01693 
01694         if (!repo->quiet && repo->database)
01695             repo_error(0, _("Sqlite DBs complete"));
01696 
01697         if (repo->groupfile != NULL) {
01698             self.addArbitraryMetadata(repo->groupfile, 'group_gz', reporoot)
01699             self.addArbitraryMetadata(repo->groupfile, 'group', reporoot, compress=False)
01700         }
01701 
01702         /* save it down */
01703         try:
01704             repodoc.saveFormatFileEnc(fn, 'UTF-8', 1)
01705         except:
01706             repo_error(0, _("Error saving temp file for %s%s%s: %s"),
01707                 rfile->type,
01708                 (repo->markup ? repo->markup : ""),
01709                 (repo->suffix && strcmp(*typep, "repomd") ? repo->suffix : ""),
01710                 fn);
01711             repo_error(1, _("Could not save temp file: %s"), fn);
01712 
01713         del repodoc
01714 #endif
01715 
01716     return rc;
01717 }
01718 
01724 static int repoDoFinalMove(rpmrepo repo)
01725         /*@globals h_errno, rpmGlobalMacroContext, fileSystem, internalState @*/
01726         /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
01727 {
01728     const char * output_final_dir =
01729                 rpmGetPath(repo->outputdir, "/", repo->finaldir, NULL);
01730     const char * output_old_dir =
01731                 rpmGetPath(repo->outputdir, "/", repo->olddir, NULL);
01732     const char * oldfile;
01733     struct stat sb, *st = &sb;
01734     int xx;
01735 
01736     if (rpmioExists(output_final_dir, st)) {
01737         if ((xx = Rename(output_final_dir, output_old_dir)) != 0)
01738             repo_error(1, _("Error moving final %s to old dir %s"),
01739                         output_final_dir, output_old_dir);
01740     }
01741 
01742     {   const char * output_temp_dir =
01743                 rpmGetPath(repo->outputdir, "/", repo->tempdir, NULL);
01744         if ((xx = Rename(output_temp_dir, output_final_dir)) != 0) {
01745             xx = Rename(output_old_dir, output_final_dir);
01746             repo_error(1, _("Error moving final metadata into place"));
01747         }
01748         output_temp_dir = _free(output_temp_dir);
01749     }
01750 
01751   { /*@observer@*/
01752     static const char * types[] =
01753         { "primary", "filelists", "other", "repomd", "group", NULL };
01754     const char ** typep;
01755 
01756     for (typep = types; *typep != NULL; typep++) {
01757         oldfile = rpmGetPath(output_old_dir, "/", *typep,
01758                 (repo->markup != NULL ? repo->markup : ""),
01759                 (repo->suffix != NULL && strcmp(*typep, "repomd")
01760                         ? repo->suffix : ""), NULL);
01761         if (rpmioExists(oldfile, st)) {
01762             if (Unlink(oldfile))
01763                 repo_error(1, _("Could not remove old metadata file: %s: %s"),
01764                         oldfile, strerror(errno));
01765         }
01766         oldfile = _free(oldfile);
01767     }
01768   }
01769 
01770   { DIR * dir = Opendir(output_old_dir);
01771     struct dirent * dp;
01772 
01773    if (dir != NULL) {
01774     while ((dp = Readdir(dir)) != NULL) {
01775         const char * finalfile;
01776 
01777         if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
01778             continue;
01779 
01780         finalfile = rpmGetPath(output_final_dir, "/", dp->d_name, NULL);
01781         oldfile = rpmGetPath(output_old_dir, "/", dp->d_name, NULL);
01782 
01783         if (!strcmp(dp->d_name, "filelists.sqlite.bz2")
01784          || !strcmp(dp->d_name, "other.sqlite.bz2")
01785          || !strcmp(dp->d_name, "primary.sqlite.bz2"))
01786         {
01787             xx = Unlink(oldfile);
01788             oldfile = _free(oldfile);
01789             continue;
01790         }
01791 
01792         if (rpmioExists(finalfile, st)) {
01793             if (!S_ISDIR(st->st_mode)) {
01794                 if ((xx = Unlink(oldfile)) != 0)
01795                     repo_error(1, _("Could not remove old metadata file: %s: %s"),
01796                                 oldfile, strerror(errno));
01797             }
01798 #ifdef  NOTYET
01799             else {
01800                 shutil.rmtree(oldfile)
01801             }
01802 #endif
01803         } else {
01804             if ((xx = Rename(oldfile, finalfile)) != 0) {
01805                 repo_error(1, _("Could not restore old non-metadata file: %s -> %s: %s"),
01806                         oldfile, finalfile, strerror(errno));
01807             }
01808         }
01809         oldfile = _free(oldfile);
01810         finalfile = _free(finalfile);
01811     }
01812     xx = Closedir(dir);
01813    }
01814   }
01815 
01816     if ((xx = Rmdir(output_old_dir)) != 0) {
01817         repo_error(1, _("Could not remove old metadata dir: %s: %s"),
01818                 repo->olddir, strerror(errno));
01819     }
01820     output_old_dir = _free(output_old_dir);
01821     output_final_dir = _free(output_final_dir);
01822 
01823     return 0;
01824 }
01825 
01826 /*==============================================================*/
01827 
01830 static void repoArgCallback(poptContext con,
01831                 /*@unused@*/ enum poptCallbackReason reason,
01832                 const struct poptOption * opt, /*@unused@*/ const char * arg,
01833                 /*@unused@*/ void * data)
01834         /*@globals _rpmrepo, fileSystem, internalState @*/
01835         /*@modifies _rpmrepo, fileSystem, internalState @*/
01836 {
01837     rpmrepo repo = _rpmrepo;
01838 
01839     /* XXX avoid accidental collisions with POPT_BIT_SET for flags */
01840     if (opt->arg == NULL)
01841     switch (opt->val) {
01842 
01843     case 'v':                   /* --verbose */
01844         repo->verbose++;
01845         break;
01846     case '?':
01847     default:
01848         fprintf(stderr, _("%s: Unknown option -%c\n"), __progname, opt->val);
01849         poptPrintUsage(con, stderr, 0);
01850         exit(EXIT_FAILURE);
01851         /*@notreached@*/ break;
01852     }
01853 }
01854 
01855 /*@unchecked@*/
01856 static int compression = -1;
01857 
01858 /*@unchecked@*/ /*@observer@*/
01859 static struct poptOption repoCompressionPoptTable[] = {
01860  { "uncompressed", '\0', POPT_ARG_VAL,          &compression, 0,
01861         N_("don't compress"), NULL },
01862  { "gzip", 'Z', POPT_ARG_VAL,                   &compression, 1,
01863         N_("use gzip compression"), NULL },
01864  { "bzip2", '\0', POPT_ARG_VAL,                 &compression, 2,
01865         N_("use bzip2 compression"), NULL },
01866  { "lzma", '\0', POPT_ARG_VAL,                  &compression, 3,
01867         N_("use lzma compression"), NULL },
01868  { "xz", '\0', POPT_ARG_VAL,                    &compression, 4,
01869         N_("use xz compression"), NULL },
01870     POPT_TABLEEND
01871 };
01872 
01873 /*@unchecked@*/ /*@observer@*/
01874 static struct poptOption optionsTable[] = {
01875 /*@-type@*/ /* FIX: cast? */
01876  { NULL, '\0', POPT_ARG_CALLBACK | POPT_CBFLAG_INC_DATA | POPT_CBFLAG_CONTINUE,
01877         repoArgCallback, 0, NULL, NULL },
01878 /*@=type@*/
01879 
01880  { "repodebug", '\0', POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &_repo_debug, -1,
01881         N_("debug repo handling"), NULL },
01882 
01883  { "quiet", 'q', POPT_ARG_VAL,                  &__rpmrepo.quiet, 0,
01884         N_("output nothing except for serious errors"), NULL },
01885  { "verbose", 'v', 0,                           NULL, (int)'v',
01886         N_("output more debugging info."), NULL },
01887  { "dryrun", '\0', POPT_ARG_VAL,                &__rpmrepo.dryrun, 1,
01888         N_("sanity check arguments, don't create metadata"), NULL },
01889  { "excludes", 'x', POPT_ARG_ARGV,              &__rpmrepo.exclude_patterns, 0,
01890         N_("glob PATTERN(s) to exclude"), N_("PATTERN") },
01891  { "includes", 'i', POPT_ARG_ARGV,              &__rpmrepo.include_patterns, 0,
01892         N_("glob PATTERN(s) to include"), N_("PATTERN") },
01893  { "basedir", '\0', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN,    &__rpmrepo.basedir, 0,
01894         N_("top level directory"), N_("DIR") },
01895  { "baseurl", 'u', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN,     &__rpmrepo.baseurl, 0,
01896         N_("baseurl to append on all files"), N_("BASEURL") },
01897 #ifdef  NOTYET
01898  { "groupfile", 'g', POPT_ARG_STRING|POPT_ARGFLAG_DOC_HIDDEN,   &__rpmrepo.groupfile, 0,
01899         N_("path to groupfile to include in metadata"), N_("FILE") },
01900 #endif
01901  { "pretty", 'p', POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN,         &__rpmrepo.pretty, 1,
01902         N_("make sure all xml generated is formatted"), NULL },
01903  { "checkts", 'C', POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN,        &__rpmrepo.checkts, 1,
01904         N_("check timestamps on files vs the metadata to see if we need to update"), NULL },
01905 #if defined(WITH_SQLITE)
01906  { "database", 'd', POPT_ARG_VAL,               &__rpmrepo.database, 1,
01907         N_("create sqlite3 database files"), NULL },
01908 #endif
01909  { "split", '\0', POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN,         &__rpmrepo.split, 1,
01910         N_("generate split media"), NULL },
01911  { "pkglist", 'l', POPT_ARG_ARGV|POPT_ARGFLAG_DOC_HIDDEN,       &__rpmrepo.manifests, 0,
01912         N_("use only the files listed in this file from the directory specified"), N_("FILE") },
01913  { "outputdir", 'o', POPT_ARG_STRING,           &__rpmrepo.outputdir, 0,
01914         N_("<dir> = optional directory to output to"), N_("DIR") },
01915  { "skip-symlinks", 'S', POPT_ARG_VAL,          &__rpmrepo.nofollow, 1,
01916         N_("ignore symlinks of packages"), NULL },
01917  { "unique-md-filenames", '\0', POPT_ARG_VAL|POPT_ARGFLAG_DOC_HIDDEN, &__rpmrepo.uniquemdfilenames, 1,
01918         N_("include the file's checksum in the filename, helps with proxies"), NULL },
01919 
01920  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioFtsPoptTable, 0,
01921         N_("Fts(3) traversal options:"), NULL },
01922 
01923 #ifdef  NOTYET
01924  { "version", '\0', 0, NULL, POPT_SHOWVERSION,
01925         N_("print the version"), NULL },
01926 #endif
01927 
01928  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, repoCompressionPoptTable, 0,
01929         N_("Available compressions:"), NULL },
01930 
01931  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioDigestPoptTable, 0,
01932         N_("Available digests:"), NULL },
01933 
01934  { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmioAllPoptTable, 0,
01935         N_("Common options for all rpmio executables:"),
01936         NULL },
01937 
01938   POPT_AUTOALIAS
01939   POPT_AUTOHELP
01940   POPT_TABLEEND
01941 
01942 };
01943 
01944 int
01945 main(int argc, char *argv[])
01946         /*@globals _rpmrepo,
01947                 rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01948         /*@modifies _rpmrepo,
01949                 rpmGlobalMacroContext, fileSystem, internalState @*/
01950 {
01951     rpmrepo repo = _rpmrepo;
01952     poptContext optCon;
01953     const char ** av = NULL;
01954     int ndirs = 0;
01955     int nfiles = 0;
01956     int rc = 1;         /* assume failure. */
01957     int xx;
01958     int i;
01959 
01960 #if !defined(__LCLINT__)        /* XXX force "rpmrepo" name. */
01961     __progname = "rpmrepo";
01962 #endif
01963 
01964     /* Process options. */
01965     optCon = rpmioInit(argc, argv, optionsTable);
01966 
01967     repo->ftsoptions = (rpmioFtsOpts ? rpmioFtsOpts : FTS_PHYSICAL);
01968     switch (repo->ftsoptions & (FTS_LOGICAL|FTS_PHYSICAL)) {
01969     case (FTS_LOGICAL|FTS_PHYSICAL):
01970         repo_error(1, "FTS_LOGICAL and FTS_PYSICAL are mutually exclusive");
01971         /*@notreached@*/ break;
01972     case 0:
01973         repo->ftsoptions |= FTS_PHYSICAL;
01974         break;
01975     }
01976 
01977     repo->algo = (rpmioDigestHashAlgo >= 0 ? (rpmioDigestHashAlgo & 0xff)  : PGPHASHALGO_SHA1);
01978 
01979     repo->compression = (compression >= 0 ? compression : 1);
01980     switch (repo->compression) {
01981     case 0:
01982         repo->suffix = NULL;
01983         repo->wmode = "w.ufdio";
01984         break;
01985     default:
01986         /*@fallthrough@*/
01987     case 1:
01988         repo->suffix = ".gz";
01989         repo->wmode = "w9.gzdio";
01990         break;
01991     case 2:
01992         repo->suffix = ".bz2";
01993         repo->wmode = "w9.bzdio";
01994         break;
01995     case 3:
01996         repo->suffix = ".lzma";
01997         repo->wmode = "w.lzdio";
01998         break;
01999     case 4:
02000         repo->suffix = ".xz";
02001         repo->wmode = "w.xzdio";
02002         break;
02003     }
02004 
02005     av = poptGetArgs(optCon);
02006     if (av == NULL || av[0] == NULL) {
02007         repo_error(0, _("Must specify path(s) to index."));
02008         poptPrintUsage(optCon, stderr, 0);
02009         goto exit;
02010     }
02011 
02012     if (av != NULL)
02013     for (i = 0; av[i] != NULL; i++) {
02014         char fullpath[MAXPATHLEN];
02015         struct stat sb;
02016         const char * rpath;
02017         const char * lpath = NULL;
02018         int ut = urlPath(av[i], &lpath);
02019         size_t nb = (size_t)(lpath - av[i]);
02020         int isdir = (lpath[strlen(lpath)-1] == '/');
02021         
02022         /* Convert to absolute/clean/malloc'd path. */
02023         if (lpath[0] != '/') {
02024             if ((rpath = repoRealpath(lpath)) == NULL)
02025                 repo_error(1, _("Realpath(%s): %s"), lpath, strerror(errno));
02026             lpath = rpmGetPath(rpath, NULL);
02027             rpath = _free(rpath);
02028         } else
02029             lpath = rpmGetPath(lpath, NULL);
02030 
02031         /* Reattach the URI to the absolute/clean path. */
02032         /* XXX todo: rpmGenPath was confused by file:///path/file URI's. */
02033         switch (ut) {
02034         case URL_IS_DASH:
02035         case URL_IS_UNKNOWN:
02036             rpath = lpath;
02037             lpath = NULL;
02038             /*@switchbreak@*/ break;
02039         default:
02040 assert(nb < sizeof(fullpath));
02041             strncpy(fullpath, av[i], nb);
02042             fullpath[nb] = '\0';
02043             rpath = rpmGenPath(fullpath, lpath, NULL);
02044             lpath = _free(lpath);
02045             /*@switchbreak@*/ break;
02046         }
02047 
02048         /* Add a trailing '/' on directories. */
02049         lpath = (isdir || (!Stat(rpath, &sb) && S_ISDIR(sb.st_mode))
02050                 ? "/" : NULL);
02051         if (lpath != NULL) {
02052             lpath = rpmExpand(rpath, lpath, NULL);
02053             xx = argvAdd(&repo->directories, lpath);
02054             lpath = _free(lpath);
02055             ndirs++;
02056         } else {
02057             xx = argvAdd(&repo->pkglist, rpath);
02058             nfiles++;
02059         }
02060         rpath = _free(rpath);
02061     }
02062 
02063 if (_repo_debug || repo->dryrun)
02064 argvPrint("repo->directories", repo->directories, NULL);
02065 
02066 #ifdef  NOTYET
02067     if (repo->basedir == NULL)
02068         repo->basedir = xstrdup(repo->directories[0]);
02069 #endif
02070 
02071     if (repo->outputdir == NULL) {
02072         if (repo->directories != NULL && repo->directories[0] != NULL)
02073             repo->outputdir = xstrdup(repo->directories[0]);
02074         else {
02075             repo->outputdir = repoRealpath(".");
02076             if (repo->outputdir == NULL)
02077                 repo_error(1, _("Realpath(%s): %s"), ".", strerror(errno));
02078         }
02079     }
02080 
02081     if (repo->split && repo->checkts)
02082         repo_error(1, _("--split and --checkts options are mutually exclusive"));
02083 
02084 #ifdef  NOTYET
02085     /* Add manifest(s) contents to rpm list. */
02086     if (repo->manifests != NULL) {
02087         const char ** av = repo->manifests;
02088         const char * fn;
02089         /* Load the rpm list from manifest(s). */
02090         while ((fn = *av++) != NULL) {
02091             /* XXX todo: parse paths from files. */
02092             /* XXX todo: convert to absolute paths. */
02093             /* XXX todo: check for existence. */
02094             xx = argvAdd(&repo->pkglist, fn);
02095         }
02096     }
02097 #endif
02098 
02099     /* Set up mire patterns (no error returns with globs, easy pie). */
02100     if (mireLoadPatterns(RPMMIRE_GLOB, 0, repo->exclude_patterns, NULL,
02101                 &repo->excludeMire, &repo->nexcludes))
02102         repo_error(1, _("Error loading exclude glob patterns."));
02103     if (mireLoadPatterns(RPMMIRE_GLOB, 0, repo->include_patterns, NULL,
02104                 &repo->includeMire, &repo->nincludes))
02105         repo_error(1, _("Error loading include glob patterns."));
02106 
02107     /* Load the rpm list from a multi-rooted directory traversal. */
02108     if (repo->directories != NULL) {
02109         ARGV_t pkglist = repoGetFileList(repo, repo->directories, ".rpm");
02110         xx = argvAppend(&repo->pkglist, pkglist);
02111         pkglist = argvFree(pkglist);
02112     }
02113 
02114     /* XXX todo: check for duplicates in repo->pkglist? */
02115     xx = argvSort(repo->pkglist, NULL);
02116 
02117 if (_repo_debug || repo->dryrun)
02118 argvPrint("repo->pkglist", repo->pkglist, NULL);
02119 
02120     repo->pkgcount = argvCount(repo->pkglist);
02121 
02122     /* XXX enable --stats using transaction set. */
02123     _rpmts_stats = _rpmsw_stats;
02124     repo->ts = rpmtsCreate();
02125 
02126     /* XXX todo wire up usual rpm CLI options. hotwire --nosignature for now */
02127     (void) rpmtsSetVSFlags(repo->ts, _RPMVSF_NOSIGNATURES);
02128 
02129     rc = repoTestSetupDirs(repo);
02130         
02131     if (rc || repo->dryrun)
02132         goto exit;
02133 
02134     if (!repo->split) {
02135         rc = repoCheckTimeStamps(repo);
02136         if (rc == 0) {
02137             fprintf(stdout, _("repo is up to date\n"));
02138             goto exit;
02139         }
02140     }
02141 
02142     if ((rc = repoDoPkgMetadata(repo)) != 0)
02143         goto exit;
02144     if ((rc = repoDoRepoMetadata(repo)) != 0)
02145         goto exit;
02146     if ((rc = repoDoFinalMove(repo)) != 0)
02147         goto exit;
02148 
02149 exit:
02150     (void)rpmtsFree(repo->ts); 
02151     repo->ts = NULL;
02152     repo->primary.digest = _free(repo->primary.digest);
02153     repo->primary.Zdigest = _free(repo->primary.Zdigest);
02154     repo->filelists.digest = _free(repo->filelists.digest);
02155     repo->filelists.Zdigest = _free(repo->filelists.Zdigest);
02156     repo->other.digest = _free(repo->other.digest);
02157     repo->other.Zdigest = _free(repo->other.Zdigest);
02158     repo->repomd.digest = _free(repo->repomd.digest);
02159     repo->repomd.Zdigest = _free(repo->repomd.Zdigest);
02160     repo->outputdir = _free(repo->outputdir);
02161     repo->pkglist = argvFree(repo->pkglist);
02162     repo->directories = argvFree(repo->directories);
02163     repo->manifests = argvFree(repo->manifests);
02164 /*@-onlytrans -refcounttrans @*/
02165     repo->excludeMire = mireFreeAll(repo->excludeMire, repo->nexcludes);
02166     repo->includeMire = mireFreeAll(repo->includeMire, repo->nincludes);
02167 /*@=onlytrans =refcounttrans @*/
02168     repo->exclude_patterns = argvFree(repo->exclude_patterns);
02169     repo->include_patterns = argvFree(repo->include_patterns);
02170 
02171     tagClean(NULL);
02172     optCon = rpmioFini(optCon);
02173 
02174     return rc;
02175 }

Generated on Fri Dec 3 2010 20:54:51 for rpm by  doxygen 1.7.2