[image] Fix a memleak in free_image()
[people/pcmattman/gpxe.git] / src / core / image.c
1 /*
2  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 FILE_LICENCE ( GPL2_OR_LATER );
20
21 #include <stddef.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include <libgen.h>
28 #include <gpxe/list.h>
29 #include <gpxe/umalloc.h>
30 #include <gpxe/uri.h>
31 #include <gpxe/image.h>
32
33 /** @file
34  *
35  * Executable/loadable images
36  *
37  */
38
39 /** List of registered images */
40 struct list_head images = LIST_HEAD_INIT ( images );
41
42 /**
43  * Free executable/loadable image
44  *
45  * @v refcnt            Reference counter
46  */
47 static void free_image ( struct refcnt *refcnt ) {
48         struct image *image = container_of ( refcnt, struct image, refcnt );
49
50         free ( image->cmdline );
51         uri_put ( image->uri );
52         ufree ( image->data );
53         image_put ( image->replacement );
54         free ( image );
55         DBGC ( image, "IMAGE %p freed\n", image );
56 }
57
58 /**
59  * Allocate executable/loadable image
60  *
61  * @ret image           Executable/loadable image
62  */
63 struct image * alloc_image ( void ) {
64         struct image *image;
65
66         image = zalloc ( sizeof ( *image ) );
67         if ( image ) {
68                 ref_init ( &image->refcnt, free_image );
69         }
70         return image;
71 }
72
73 /**
74  * Set image URI
75  *
76  * @v image             Image
77  * @v URI               New image URI
78  * @ret rc              Return status code
79  *
80  * If no name is set, the name will be updated to the base name of the
81  * URI path (if any).
82  */
83 int image_set_uri ( struct image *image, struct uri *uri ) {
84         const char *path = uri->path;
85
86         /* Replace URI reference */
87         uri_put ( image->uri );
88         image->uri = uri_get ( uri );
89
90         /* Set name if none already specified */
91         if ( path && ( ! image->name[0] ) )
92                 image_set_name ( image, basename ( ( char * ) path ) );
93
94         return 0;
95 }
96
97 /**
98  * Set image command line
99  *
100  * @v image             Image
101  * @v cmdline           New image command line
102  * @ret rc              Return status code
103  */
104 int image_set_cmdline ( struct image *image, const char *cmdline ) {
105         free ( image->cmdline );
106         image->cmdline = strdup ( cmdline );
107         if ( ! image->cmdline )
108                 return -ENOMEM;
109         return 0;
110 }
111
112 /**
113  * Register executable/loadable image
114  *
115  * @v image             Executable/loadable image
116  * @ret rc              Return status code
117  */
118 int register_image ( struct image *image ) {
119         static unsigned int imgindex = 0;
120
121         /* Create image name if it doesn't already have one */
122         if ( ! image->name[0] ) {
123                 snprintf ( image->name, sizeof ( image->name ), "img%d",
124                            imgindex++ );
125         }
126
127         /* Add to image list */
128         image_get ( image );
129         list_add_tail ( &image->list, &images );
130         DBGC ( image, "IMAGE %p at [%lx,%lx) registered as %s\n",
131                image, user_to_phys ( image->data, 0 ),
132                user_to_phys ( image->data, image->len ), image->name );
133
134         return 0;
135 }
136
137 /**
138  * Unregister executable/loadable image
139  *
140  * @v image             Executable/loadable image
141  */
142 void unregister_image ( struct image *image ) {
143         DBGC ( image, "IMAGE %p unregistered\n", image );
144         list_del ( &image->list );
145         image_put ( image );
146 }
147
148 /**
149  * Find image by name
150  *
151  * @v name              Image name
152  * @ret image           Executable/loadable image, or NULL
153  */
154 struct image * find_image ( const char *name ) {
155         struct image *image;
156
157         list_for_each_entry ( image, &images, list ) {
158                 if ( strcmp ( image->name, name ) == 0 )
159                         return image;
160         }
161
162         return NULL;
163 }
164
165 /**
166  * Load executable/loadable image into memory
167  *
168  * @v image             Executable/loadable image
169  * @v type              Executable/loadable image type
170  * @ret rc              Return status code
171  */
172 static int image_load_type ( struct image *image, struct image_type *type ) {
173         int rc;
174
175         /* Check image is actually loadable */
176         if ( ! type->load )
177                 return -ENOEXEC;
178
179         /* Try the image loader */
180         if ( ( rc = type->load ( image ) ) != 0 ) {
181                 DBGC ( image, "IMAGE %p could not load as %s: %s\n",
182                        image, type->name, strerror ( rc ) );
183                 return rc;
184         }
185
186         /* Flag as loaded */
187         image->flags |= IMAGE_LOADED;
188         return 0;
189 }
190
191 /**
192  * Load executable/loadable image into memory
193  *
194  * @v image             Executable/loadable image
195  * @ret rc              Return status code
196  */
197 int image_load ( struct image *image ) {
198
199         assert ( image->type != NULL );
200
201         return image_load_type ( image, image->type );
202 }
203
204 /**
205  * Autodetect image type and load executable/loadable image into memory
206  *
207  * @v image             Executable/loadable image
208  * @ret rc              Return status code
209  */
210 int image_autoload ( struct image *image ) {
211         struct image_type *type;
212         int rc;
213
214         /* If image already has a type, use it */
215         if ( image->type )
216                 return image_load ( image );
217
218         /* Otherwise probe for a suitable type */
219         for_each_table_entry ( type, IMAGE_TYPES ) {
220                 DBGC ( image, "IMAGE %p trying type %s\n", image, type->name );
221                 rc = image_load_type ( image, type );
222                 if ( image->type == NULL )
223                         continue;
224                 return rc;
225         }
226
227         DBGC ( image, "IMAGE %p format not recognised\n", image );
228         return -ENOEXEC;
229 }
230
231 /**
232  * Execute loaded image
233  *
234  * @v image             Loaded image
235  * @ret rc              Return status code
236  */
237 int image_exec ( struct image *image ) {
238         struct image *replacement;
239         struct uri *old_cwuri;
240         int rc;
241
242         /* Image must be loaded first */
243         if ( ! ( image->flags & IMAGE_LOADED ) ) {
244                 DBGC ( image, "IMAGE %p could not execute: not loaded\n",
245                        image );
246                 return -ENOTTY;
247         }
248
249         assert ( image->type != NULL );
250
251         /* Check that image is actually executable */
252         if ( ! image->type->exec )
253                 return -ENOEXEC;
254
255         /* Switch current working directory to be that of the image itself */
256         old_cwuri = uri_get ( cwuri );
257         churi ( image->uri );
258
259         /* Take out a temporary reference to the image.  This allows
260          * the image to unregister itself if necessary, without
261          * automatically freeing itself.
262          */
263         image_get ( image );
264
265         /* Try executing the image */
266         if ( ( rc = image->type->exec ( image ) ) != 0 ) {
267                 DBGC ( image, "IMAGE %p could not execute: %s\n",
268                        image, strerror ( rc ) );
269                 /* Do not return yet; we still have clean-up to do */
270         }
271
272         /* Pick up replacement image before we drop the original
273          * image's temporary reference.
274          */
275         replacement = image->replacement;
276
277         /* Drop temporary reference to the original image */
278         image_put ( image );
279
280         /* Reset current working directory */
281         churi ( old_cwuri );
282         uri_put ( old_cwuri );
283
284         /* Tail-recurse into replacement image, if one exists */
285         if ( replacement ) {
286                 DBGC ( image, "IMAGE %p replacing self with IMAGE %p\n",
287                        image, replacement );
288                 if ( ( rc = image_exec ( replacement ) ) != 0 )
289                         return rc;
290         }
291
292         return rc;
293 }
294
295 /**
296  * Register and autoload an image
297  *
298  * @v image             Image
299  * @ret rc              Return status code
300  */
301 int register_and_autoload_image ( struct image *image ) {
302         int rc;
303
304         if ( ( rc = register_image ( image ) ) != 0 )
305                 return rc;
306
307         if ( ( rc = image_autoload ( image ) ) != 0 )
308                 return rc;
309
310         return 0;
311 }
312
313 /**
314  * Register and autoexec an image
315  *
316  * @v image             Image
317  * @ret rc              Return status code
318  */
319 int register_and_autoexec_image ( struct image *image ) {
320         int rc;
321
322         if ( ( rc = register_and_autoload_image ( image ) ) != 0 )
323                 return rc;
324
325         if ( ( rc = image_exec ( image ) ) != 0 )
326                 return rc;
327
328         return 0;
329 }