Пример #1
0
EXTERN_C int climain( int argc, char **argv )
{
    /* Set up the diagnostic message handler, using the console's
     * `stderr' stream for notifications...
     */
    dmh_init( DMH_SUBSYSTEM_TTY, *argv++ );

    /* TODO: insert code here, to interpret any OPTIONS specified
     * on the command line.
     */

    /* Interpret the `action keyword', specifying the action to be
     * performed on this invocation...
     */
    int action = action_code( *argv );
    if( action < 0 )
        /*
         * The specified action keyword was invalid;
         * force an abort through a DMH_FATAL notification...
         */
        dmh_notify( DMH_FATAL, "%s: unknown action keyword\n", *argv );

    /* If we get to here, then the specified action identifies a
     * valid operation; load the package database, according to the
     * local `profile' configuration, and invoke the operation.
     */
    const char *dfile;
    pkgXmlDocument dbase( dfile = xmlfile( "profile" ) );
    if( dbase.IsOk() )
    {
        /* We successfully loaded the basic settings...
         * The configuration file name was pushed on to the heap,
         * by xmlfile(); we don't need that any more, (because it
         * is reproduced within the database image itself), so
         * free the heap copy, to avoid memory leaks.
         */
        free( (void *)(dfile) );

        /* Merge all package lists, as specified in the "repository"
         * section of the "profile", into the XML database tree...
         */
        if( dbase.BindRepositories( action == ACTION_UPDATE ) == NULL )
            /*
             * ...bailing out, on an invalid profile specification...
             */
            dmh_notify( DMH_FATAL, "%s: invalid application profile\n", dbase.Value() );

#if 0
        /* If the requested action was "update", then we've already done it,
         * as a side effect of binding the cached repository catalogues...
         */
        if( action != ACTION_UPDATE )
        {
            /* ...otherwise, we still need to schedule and execute the action request...
             *
             * so, schedule the specified action for each additionally specified command
             * line argument, (each of which is assumed to represent a package name)...
             */
            while( --argc )
                dbase.Schedule( (unsigned long)(action), *++argv );

            /* ...and finally, execute all scheduled actions...
             */
            dbase.ExecuteActions();
        }
#endif

        /* If we get this far, then all actions completed successfully;
         * we are done...
         */
        return EXIT_SUCCESS;
    }

    /* If we get to here, then the package database load failed;
     * once more, we force an abort through a DMH_FATAL notification...
     *
     * Note: although dmh_notify does not return, in the DMH_FATAL case,
     * GCC cannot know this, so we pretend that it gives us a return value,
     * to avoid a possible warning about reaching the end of a non-void
     * function without a return value assignment...
     */
    return dmh_notify( DMH_FATAL, "%s: cannot load configuration\n", dfile );
}
Пример #2
0
static inline
const char *pkgResolvedName( pkgXmlNode *rel, const char *tag, const char *ext )
{
  /* Local helper function to resolve the mapping from a released
   * package name, as identified from the XML release element "rel",
   * to its corresponding source or licence package name, according
   * to the selection of "source" or "licence" specified by "tag",
   * with "ext" passed a "src" or "lic" respectively.
   */
  const char *refname;
  const char *retname = NULL;

  /* First, we retrieve the released package name...
   */
  if( (refname = pkgArchiveName( rel, release_key, 1 )) != NULL )
  {
    /* ...and if successful, look for an explicit reference to
     * the source or licence package, embedded within the release
     * specification itself.
     */
    if( (retname = pkgArchiveName( rel, tag, 0 )) == NULL )
    {
      /* When this fails to identify the required mapping,
       * then we look for a generic reference, defined for
       * the containing package.
       */
      pkgXmlNode *enc = rel->GetParent();

      /* A generic reference may be placed at any nesting
       * level, between the enclosing package element and
       * the release to which it relates; thus, starting
       * at the first enclosing level...
       */
      rel = NULL;
      while( enc != NULL )
      {
	/* ...enumerate reference specifications of the
	 * appropriate type, examining all children of
	 * the enclosing element.
	 */
	unsigned matched = 0;
	pkgXmlNode *child = enc->GetChildren();
	while( child != NULL )
	{
	  /* We have a child, which we have not examined...
	   */
	  if( child->IsElementOfType( tag ) )
	  {
	    /* ...and it is of the required "tag" type.
	     */
	    if( matched++ )
	      /*
	       * We already had a candidate match, so we
	       * diagnose but otherwise this duplicate...
	       */
	      dmh_notify( DMH_WARNING,
		  "redundant %s specification ignored\n", tag
		);

	    else
	      /* This is the first candidate match found,
	       * so we accept it.
	       */
	      rel = child;
	  }
	  /* Continue examining child elements, until no more
	   * are present at the current nesting level.
	   */
	  child = child->GetNext();
	}

	/* When we've completed the examination of all children
	 * at a given nesting level, without finding a matching
	 * specification, and that level is still within the
	 * enclosing package element...
	 */
	if( (rel == NULL) && ! enc->IsElementOfType( package_key ) )
	  /*
	   * ...then we extend the search to the next enclosing
	   * level of nesting...
	   */
	  enc = enc->GetParent();

	else
	  /* ...otherwise, we abandon the search.
	   */
	  enc = NULL;
      }

      /* If we've searched all available nesting levels,
       * and failed to locate the requisite specification...
       */
      if( rel == NULL )
      {
	/* ...then we assume that the requisite tarname
	 * is identical to the release tarname, with the
	 * appropriate "ext" substitution for the package
	 * class identification...
	 */
	pkgSpecs resolved( refname );
	resolved.SetComponentClass( ext );
	/*
	 * ...so, having made the substitution,
	 * we return the resultant tarname, noting
	 * that this automatically allocates space
	 * on the heap, for the returned string.
	 */
	return resolved.GetTarName();
      }
      else
	/* We did find a mappingspecification, so we
	 * extract a tarname template from it.
	 */
	retname = rel->GetPropVal( tarname_key, NULL );
    }
    else if( strcmp( retname, value_none ) == 0 )
      /*
       * The package is virtual, or an explicit mapping
       * specification indicates that there is no related
       * source or licence package; return NULL to advise
       * the caller of this.
       */
      return NULL;

    /* If we get to here, we found a mapping specification;
     * it may be a template, so resolve any substitutions which
     * it must inherit from the released package tarname, again
     * noting that this allocates heap memory for the result.
     */
    retname = pkgAssociateName( retname, refname );
  }

  /* Finally, how ever we resolved the mapping, we return
   * the result.
   */
  return retname;
}
Пример #3
0
static
const char *pkgArchiveName( pkgXmlNode *rel, const char *tag, unsigned opt )
{
  /* Local helper to establish actual release file names...
   * applicable only to XML "release" elements.
   */
  if( ! rel->IsElementOfType( release_key ) )
  {
    /* The XML element type name is not "release"; identify it...
     */
    const char *reftype;
    if( (reftype = rel->GetName()) == NULL )
      /*
       * ...or classify as "unknown", when given a NULL element.
       */
      reftype = value_unknown;

    /* Complain that this XML element type is invalid, in this context...
     */
    dmh_control( DMH_BEGIN_DIGEST );
    dmh_notify( DMH_ERROR, "internal package specification error\n" );
    dmh_notify( DMH_ERROR, "can't get 'tarname' for non-release element %s\n", reftype );
    dmh_notify( DMH_ERROR, "please report this to the package maintainer\n" );
    dmh_control( DMH_END_DIGEST );

    /* ...and bail out, telling the caller that no archive name is available...
     */
    return NULL;
  }

  /* Given a package release specification...
   * First check that it relates to a real package, rather than to
   * a virtual "meta-package"; such meta-packages exist solely as
   * containers for requirements specifications, and have no
   * associated archive.
   */
  pkgXmlNode *pkg = rel->GetParent();
  while( (pkg != NULL) && ! pkg->IsElementOfType( package_key ) )
    pkg = pkg->GetParent();

  /* FIXME: we should probably provide some error handling here,
   * to diagnose release elements without any package association;
   * (these would be identified by pkg == NULL).
   */
  if( pkg != NULL )
  {
    /* We found the package association...
     * Check its 'class' attribute, if any, and if classified as
     * 'virtual', return the archive association as "none".
     */
    const char *package_class = pkg->GetPropVal( class_key, NULL );
    if( (package_class != NULL) && (strcmp( package_class, value_virtual ) == 0) )
      return value_none;
  }

  /* The given release specification relates to a real package...
   * Determine the archive name for the tarball to be processed; this
   * is retrieved from a child XML element with name specified by "tag";
   * by default, if "opt" is non-zero, it is the canonical "tarname"
   * assigned to the release element itself, unless an alternative
   * specification is provided; if "opt" is zero, no default is
   * assumed, and the return value is NULL if no alternative
   * specification is provided.
   */
  unsigned matched = 0;
  pkgXmlNode *dl = rel->GetChildren();
  while( dl != NULL )
  {
    /* Visit all children of the release specification element,
     * checking for the presence of an expected specification...
     */
    if( dl->IsElementOfType( tag ) )
    {
      /* Found one; ensure it is the only one...
       */
      if( matched++ )
	/*
	 * ...else emit a warning, and ignore this one...
	 */
	dmh_notify( DMH_WARNING, "%s: archive name reassignment ignored\n",
	    rel->GetPropVal( tarname_key, value_unknown )
	);
      else
	/* ...ok; this is the first "tag" specification,
	 * accept it as the non-default source of the release's
	 * "tarname" property.
	 */
	rel = dl;
    }
    /* Continue, until all children have been visited.
     */
    dl = dl->GetNext();
  }
  /* "rel" now points to the XML element having the appropriate
   * "tarname" specification; return a pointer to it's value.
   */
  return (opt || matched) ? rel->GetPropVal( tarname_key, NULL ) : NULL;
}
Пример #4
0
void pkgRepository::GetPackageList( const char *dname )
{
  /* Helper to retrieve and recursively process a named package list.
   *
   * FIXME: having made this recursively process multiple catalogues,
   * potentially from multiple independent repositories, we may have
   * introduced potential for catalogue name clashes; we need to add
   * name hashing in the local catalogue cache, to avoid conflicts.
   */
  if( dname != NULL )
  {
    const char *dfile;
    if( (dfile = xmlfile( dname )) != NULL )
    {
      /* Check for a locally cached copy of the "package-list" file...
       */
      if( force_update || (access( dfile, F_OK ) != 0) )
      {
	/* When performing an "update", or if no local copy is available...
	 * Force a "sync", to fetch a copy from the public host.
	 */
	dmh_printf( "Update catalogue: %s.xml\n", dname );
	owner->SyncRepository( dname, repository );
      }

      /* We SHOULD now have a locally cached copy of the package-list;
       * attempt to merge it into the active profile database...
       */
      pkgXmlDocument merge( dfile );
      if( merge.IsOk() )
      {
	/* We successfully loaded the XML catalogue; refer to its
	 * root element...
	 */
	if( pkgOptions()->Test( OPTION_VERBOSE ) > 1 )
	  dmh_printf( "Load catalogue: %s.xml\n", dname );
	pkgXmlNode *catalogue, *pkglist;
	if( (catalogue = merge.GetRoot()) != NULL )
	{
	  /* ...read it, selecting each of the "package-collection"
	   * records contained within it...
	   */
	  pkglist = catalogue->FindFirstAssociate( package_collection_key );
	  while( pkglist != NULL )
	  {
	    /* ...and append a copy of each to the active profile...
	     */
	    dbase->LinkEndChild( pkglist->Clone() );

	    /* Move on to the next "package-collection" (if any)
	     * within the current catalogue...
	     */
	    pkglist = pkglist->FindNextAssociate( package_collection_key );
	  }

	  /* Recursively incorporate any additional package lists,
	   * which may be specified within the current catalogue...
	   */
	  GetPackageList( catalogue->FindFirstAssociate( package_list_key ) );
	}
      }
      else
      { /* The specified catalogue could not be successfully loaded;
	 * emit a warning diagnostic message, and otherwise ignore it.
	 */
	dmh_notify( DMH_WARNING, "Load catalogue: FAILED: %s.xml\n", dname );
      }

      /* However we handled it, the XML file's path name in "dfile" was
       * allocated on the heap; we lose its reference on termination of
       * this loop, so we must free it to avoid a memory leak.
       */
      free( (void *)(dfile) );
    }
  }
}