Warnings purge: src/arch/i386, src/core/disk.c, ramdisk, autoboot
[people/xl0/gpxe.git] / src / usr / autoboot.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 #include <string.h>
20 #include <stdio.h>
21 #include <errno.h>
22 #include <gpxe/netdevice.h>
23 #include <gpxe/dhcp.h>
24 #include <gpxe/image.h>
25 #include <usr/ifmgmt.h>
26 #include <usr/route.h>
27 #include <usr/dhcpmgmt.h>
28 #include <usr/imgmgmt.h>
29 #include <usr/autoboot.h>
30
31 /** @file
32  *
33  * Automatic booting
34  *
35  */
36
37 /**
38  * Identify the boot network device
39  *
40  * @ret netdev          Boot network device
41  */
42 static struct net_device * find_boot_netdev ( void ) {
43         return NULL;
44 }
45
46 /**
47  * Boot from a network device
48  *
49  * @v netdev            Network device
50  */
51 void netboot ( struct net_device *netdev ) {
52         char filename[256];
53         struct image *image;
54         int rc;
55
56         /* Open device and display device status */
57         if ( ( rc = ifopen ( netdev ) ) != 0 )
58                 return;
59         ifstat ( netdev );
60
61         /* Configure device via DHCP */
62         if ( ( rc = dhcp ( netdev ) ) != 0 )
63                 return;
64         route();
65
66         /* Try to download and boot whatever we are given as a filename */
67         dhcp_snprintf ( filename, sizeof ( filename ),
68                         find_global_dhcp_option ( DHCP_BOOTFILE_NAME ) );
69         if ( ! filename[0] ) {
70                 printf ( "No boot filename\n" );
71                 return;
72         }
73         printf ( "Booting \"%s\"\n", filename );
74         image = alloc_image();
75         if ( ! image ) {
76                 printf ( "Out of memory\n" );
77                 return;
78         }
79         if ( ( rc = imgfetch ( image, filename, 0 ) ) != 0 ) {
80                 printf ( "Could not retrieve %s: %s\n",
81                          filename, strerror ( rc ) );
82                 image_put ( image );
83                 return;
84         }
85         if ( ( rc = imgload ( image ) ) != 0 ) {
86                 printf ( "Could not load %s: %s\n", image->name,
87                          strerror ( rc ) );
88                 image_put ( image );
89                 return;
90         }
91         if ( ( rc = imgexec ( image ) ) != 0 ) {
92                 printf ( "Could not execute %s: %s\n", image->name,
93                          strerror ( rc ) );
94                 image_put ( image );
95                 return;
96         }
97 }
98
99 /**
100  * Close all open net devices
101  *
102  * Called before a fresh boot attempt in order to free up memory.  We
103  * don't just close the device immediately after the boot fails,
104  * because there may still be TCP connections in the process of
105  * closing.
106  */
107 static void close_all_netdevs ( void ) {
108         struct net_device *netdev;
109
110         for_each_netdev ( netdev ) {
111                 ifclose ( netdev );
112         }
113 }
114
115 /**
116  * Boot the system
117  */
118 void autoboot ( void ) {
119         struct net_device *boot_netdev;
120         struct net_device *netdev;
121
122         /* If we have an identifable boot device, try that first */
123         close_all_netdevs();
124         if ( ( boot_netdev = find_boot_netdev() ) )
125                 netboot ( boot_netdev );
126
127         /* If that fails, try booting from any of the other devices */
128         for_each_netdev ( netdev ) {
129                 if ( netdev == boot_netdev )
130                         continue;
131                 close_all_netdevs();
132                 netboot ( netdev );
133         }
134
135         printf ( "No more network devices\n" );
136 }