image.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  */
00018 
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020 
00021 #include <stddef.h>
00022 #include <string.h>
00023 #include <stdlib.h>
00024 #include <stdio.h>
00025 #include <errno.h>
00026 #include <assert.h>
00027 #include <libgen.h>
00028 #include <gpxe/list.h>
00029 #include <gpxe/umalloc.h>
00030 #include <gpxe/uri.h>
00031 #include <gpxe/image.h>
00032 
00033 /** @file
00034  *
00035  * Executable/loadable images
00036  *
00037  */
00038 
00039 /** List of registered images */
00040 struct list_head images = LIST_HEAD_INIT ( images );
00041 
00042 /**
00043  * Free executable/loadable image
00044  *
00045  * @v refcnt            Reference counter
00046  */
00047 static void free_image ( struct refcnt *refcnt ) {
00048         struct image *image = container_of ( refcnt, struct image, refcnt );
00049 
00050         uri_put ( image->uri );
00051         ufree ( image->data );
00052         image_put ( image->replacement );
00053         free ( image );
00054         DBGC ( image, "IMAGE %p freed\n", image );
00055 }
00056 
00057 /**
00058  * Allocate executable/loadable image
00059  *
00060  * @ret image           Executable/loadable image
00061  */
00062 struct image * alloc_image ( void ) {
00063         struct image *image;
00064 
00065         image = zalloc ( sizeof ( *image ) );
00066         if ( image ) {
00067                 image->refcnt.free = free_image;
00068         }
00069         return image;
00070 }
00071 
00072 /**
00073  * Set image URI
00074  *
00075  * @v image             Image
00076  * @v URI               New image URI
00077  * @ret rc              Return status code
00078  *
00079  * If no name is set, the name will be updated to the base name of the
00080  * URI path (if any).
00081  */
00082 int image_set_uri ( struct image *image, struct uri *uri ) {
00083         const char *path = uri->path;
00084 
00085         /* Replace URI reference */
00086         uri_put ( image->uri );
00087         image->uri = uri_get ( uri );
00088 
00089         /* Set name if none already specified */
00090         if ( path && ( ! image->name[0] ) )
00091                 image_set_name ( image, basename ( ( char * ) path ) );
00092 
00093         return 0;
00094 }
00095 
00096 /**
00097  * Set image command line
00098  *
00099  * @v image             Image
00100  * @v cmdline           New image command line
00101  * @ret rc              Return status code
00102  */
00103 int image_set_cmdline ( struct image *image, const char *cmdline ) {
00104         free ( image->cmdline );
00105         image->cmdline = strdup ( cmdline );
00106         if ( ! image->cmdline )
00107                 return -ENOMEM;
00108         return 0;
00109 }
00110 
00111 /**
00112  * Register executable/loadable image
00113  *
00114  * @v image             Executable/loadable image
00115  * @ret rc              Return status code
00116  */
00117 int register_image ( struct image *image ) {
00118         static unsigned int imgindex = 0;
00119 
00120         /* Create image name if it doesn't already have one */
00121         if ( ! image->name[0] ) {
00122                 snprintf ( image->name, sizeof ( image->name ), "img%d",
00123                            imgindex++ );
00124         }
00125 
00126         /* Add to image list */
00127         image_get ( image );
00128         list_add_tail ( &image->list, &images );
00129         DBGC ( image, "IMAGE %p at [%lx,%lx) registered as %s\n",
00130                image, user_to_phys ( image->data, 0 ),
00131                user_to_phys ( image->data, image->len ), image->name );
00132 
00133         return 0;
00134 }
00135 
00136 /**
00137  * Unregister executable/loadable image
00138  *
00139  * @v image             Executable/loadable image
00140  */
00141 void unregister_image ( struct image *image ) {
00142         DBGC ( image, "IMAGE %p unregistered\n", image );
00143         list_del ( &image->list );
00144         image_put ( image );
00145 }
00146 
00147 /**
00148  * Find image by name
00149  *
00150  * @v name              Image name
00151  * @ret image           Executable/loadable image, or NULL
00152  */
00153 struct image * find_image ( const char *name ) {
00154         struct image *image;
00155 
00156         list_for_each_entry ( image, &images, list ) {
00157                 if ( strcmp ( image->name, name ) == 0 )
00158                         return image;
00159         }
00160 
00161         return NULL;
00162 }
00163 
00164 /**
00165  * Load executable/loadable image into memory
00166  *
00167  * @v image             Executable/loadable image
00168  * @v type              Executable/loadable image type
00169  * @ret rc              Return status code
00170  */
00171 static int image_load_type ( struct image *image, struct image_type *type ) {
00172         int rc;
00173 
00174         /* Check image is actually loadable */
00175         if ( ! type->load )
00176                 return -ENOEXEC;
00177 
00178         /* Try the image loader */
00179         if ( ( rc = type->load ( image ) ) != 0 ) {
00180                 DBGC ( image, "IMAGE %p could not load as %s: %s\n",
00181                        image, type->name, strerror ( rc ) );
00182                 return rc;
00183         }
00184 
00185         /* Flag as loaded */
00186         image->flags |= IMAGE_LOADED;
00187         return 0;
00188 }
00189 
00190 /**
00191  * Load executable/loadable image into memory
00192  *
00193  * @v image             Executable/loadable image
00194  * @ret rc              Return status code
00195  */
00196 int image_load ( struct image *image ) {
00197 
00198         assert ( image->type != NULL );
00199 
00200         return image_load_type ( image, image->type );
00201 }
00202 
00203 /**
00204  * Autodetect image type and load executable/loadable image into memory
00205  *
00206  * @v image             Executable/loadable image
00207  * @ret rc              Return status code
00208  */
00209 int image_autoload ( struct image *image ) {
00210         struct image_type *type;
00211         int rc;
00212 
00213         /* If image already has a type, use it */
00214         if ( image->type )
00215                 return image_load ( image );
00216 
00217         /* Otherwise probe for a suitable type */
00218         for_each_table_entry ( type, IMAGE_TYPES ) {
00219                 DBGC ( image, "IMAGE %p trying type %s\n", image, type->name );
00220                 rc = image_load_type ( image, type );
00221                 if ( image->type == NULL )
00222                         continue;
00223                 return rc;
00224         }
00225 
00226         DBGC ( image, "IMAGE %p format not recognised\n", image );
00227         return -ENOEXEC;
00228 }
00229 
00230 /**
00231  * Execute loaded image
00232  *
00233  * @v image             Loaded image
00234  * @ret rc              Return status code
00235  */
00236 int image_exec ( struct image *image ) {
00237         struct image *replacement;
00238         struct uri *old_cwuri;
00239         int rc;
00240 
00241         /* Image must be loaded first */
00242         if ( ! ( image->flags & IMAGE_LOADED ) ) {
00243                 DBGC ( image, "IMAGE %p could not execute: not loaded\n",
00244                        image );
00245                 return -ENOTTY;
00246         }
00247 
00248         assert ( image->type != NULL );
00249 
00250         /* Check that image is actually executable */
00251         if ( ! image->type->exec )
00252                 return -ENOEXEC;
00253 
00254         /* Switch current working directory to be that of the image itself */
00255         old_cwuri = uri_get ( cwuri );
00256         churi ( image->uri );
00257 
00258         /* Take out a temporary reference to the image.  This allows
00259          * the image to unregister itself if necessary, without
00260          * automatically freeing itself.
00261          */
00262         image_get ( image );
00263 
00264         /* Try executing the image */
00265         if ( ( rc = image->type->exec ( image ) ) != 0 ) {
00266                 DBGC ( image, "IMAGE %p could not execute: %s\n",
00267                        image, strerror ( rc ) );
00268                 /* Do not return yet; we still have clean-up to do */
00269         }
00270 
00271         /* Pick up replacement image before we drop the original
00272          * image's temporary reference.
00273          */
00274         replacement = image->replacement;
00275 
00276         /* Drop temporary reference to the original image */
00277         image_put ( image );
00278 
00279         /* Reset current working directory */
00280         churi ( old_cwuri );
00281         uri_put ( old_cwuri );
00282 
00283         /* Tail-recurse into replacement image, if one exists */
00284         if ( replacement ) {
00285                 DBGC ( image, "IMAGE %p replacing self with IMAGE %p\n",
00286                        image, replacement );
00287                 if ( ( rc = image_exec ( replacement ) ) != 0 )
00288                         return rc;
00289         }
00290 
00291         return rc;
00292 }
00293 
00294 /**
00295  * Register and autoload an image
00296  *
00297  * @v image             Image
00298  * @ret rc              Return status code
00299  */
00300 int register_and_autoload_image ( struct image *image ) {
00301         int rc;
00302 
00303         if ( ( rc = register_image ( image ) ) != 0 )
00304                 return rc;
00305 
00306         if ( ( rc = image_autoload ( image ) ) != 0 )
00307                 return rc;
00308 
00309         return 0;
00310 }
00311 
00312 /**
00313  * Register and autoexec an image
00314  *
00315  * @v image             Image
00316  * @ret rc              Return status code
00317  */
00318 int register_and_autoexec_image ( struct image *image ) {
00319         int rc;
00320 
00321         if ( ( rc = register_and_autoload_image ( image ) ) != 0 )
00322                 return rc;
00323 
00324         if ( ( rc = image_exec ( image ) ) != 0 )
00325                 return rc;
00326 
00327         return 0;
00328 }

Generated on Tue Apr 6 20:00:51 2010 for gPXE by  doxygen 1.5.7.1