4b0f144e41eb2d64cce7812e421236e4cb761042
[petitboot] / ui / common / ui-system.c
1 /*
2  *  Copyright (C) 2009 Sony Computer Entertainment Inc.
3  *  Copyright 2009 Sony Corp.
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; version 2 of the License.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #define _GNU_SOURCE
20
21 #include <assert.h>
22 #include <errno.h>
23 #include <signal.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/types.h>
27 #include <sys/wait.h>
28
29 #include "log/log.h"
30 #include <system/system.h>
31 #include "talloc/talloc.h"
32 #include "loader.h"
33 #include "ui-system.h"
34
35 /**
36  * pb_start_daemon - start the pb-discover daemon.
37  */
38
39 int pb_start_daemon(void)
40 {
41         int result;
42         const char *argv[2];
43         char *name = talloc_asprintf(NULL, "%s/sbin/pb-discover",
44                 pb_system_apps.prefix);
45
46         argv[0] = name;
47         argv[1] =  NULL;
48
49         result = pb_run_cmd(argv, 0);
50
51         talloc_free(name);
52
53         if (result)
54                 pb_log("%s: failed: (%d)\n", __func__, result);
55
56         return result;
57 }
58
59 /**
60  * kexec_load - kexec load helper.
61  * @l_image: The local image file for kexec to execute.
62  * @l_initrd: Optional local initrd file for kexec --initrd, can be NULL.
63  * @args: Optional command line args for kexec --append, can be NULL.
64  */
65
66 static int kexec_load(const char *l_image, const char *l_initrd,
67         const char *args, int dry_run)
68 {
69         int result;
70         const char *argv[6];
71         const char **p;
72         char *s_initrd = NULL;
73         char *s_args = NULL;
74
75         p = argv;
76         *p++ = pb_system_apps.kexec;    /* 1 */
77         *p++ = "-l";                    /* 2 */
78
79         if (l_initrd) {
80                 s_initrd = talloc_asprintf(NULL, "--initrd=%s", l_initrd);
81                 assert(s_initrd);
82                 *p++ = s_initrd;         /* 3 */
83         }
84
85         if (args) {
86                 s_args = talloc_asprintf(NULL, "--append=%s", args);
87                 assert(s_args);
88                 *p++ = s_args;          /* 4 */
89         }
90
91         *p++ = l_image;                 /* 5 */
92         *p++ = NULL;                    /* 6 */
93
94         result = dry_run ? 0 : pb_run_cmd(argv, 1);
95
96         if (result)
97                 pb_log("%s: failed: (%d)\n", __func__, result);
98
99         talloc_free(s_initrd);
100         talloc_free(s_args);
101
102         return result;
103 }
104
105 /**
106  * kexec_reboot - Helper to boot the new kernel.
107  *
108  * Must only be called after a successful call to kexec_load().
109  */
110
111 static int kexec_reboot(int dry_run)
112 {
113         int result = 0;
114         const char *argv[4];
115         const char **p;
116
117         /* First try running shutdown.  Init scripts should run 'exec -e' */
118
119         p = argv;
120         *p++ = pb_system_apps.shutdown; /* 1 */
121         *p++ =  "-r";                   /* 2 */
122         *p++ =  "now";                  /* 3 */
123         *p++ =  NULL;                   /* 4 */
124
125         result = dry_run ? 0 : pb_run_cmd(argv, 1);
126
127         /* On error, force a kexec with the -e option */
128
129         if (result) {
130                 p = argv;
131                 *p++ = pb_system_apps.kexec;    /* 1 */
132                 *p++ = "-e";                    /* 2 */
133                 *p++ = NULL;                    /* 3 */
134
135                 result = pb_run_cmd(argv, 1);
136         }
137
138         if (result)
139                 pb_log("%s: failed: (%d)\n", __func__, result);
140
141         return result;
142 }
143
144 /**
145  * pb_run_kexec - Run kexec with the supplied boot options.
146  */
147
148 int pb_run_kexec(const struct pb_kexec_data *kd, int dry_run)
149 {
150         int result;
151         char *l_image = NULL;
152         char *l_initrd = NULL;
153         unsigned int clean_image = 0;
154         unsigned int clean_initrd = 0;
155
156         pb_log("%s: image:   '%s'\n", __func__, kd->image);
157         pb_log("%s: initrd:  '%s'\n", __func__, kd->initrd);
158         pb_log("%s: args:    '%s'\n", __func__, kd->args);
159         pb_log("%s: dry_run: '%d'\n", __func__, dry_run);
160
161         result = -1;
162
163         if (kd->image) {
164                 l_image = pb_load_file(NULL, kd->image, &clean_image);
165                 if (!l_image)
166                         goto no_load;
167         }
168
169         if (kd->initrd) {
170                 l_initrd = pb_load_file(NULL, kd->initrd, &clean_initrd);
171                 if (!l_initrd)
172                         goto no_load;
173         }
174
175         if (!l_image && !l_initrd)
176                 goto no_load;
177
178         result = kexec_load(l_image, l_initrd, kd->args, dry_run);
179
180 no_load:
181         if (clean_image)
182                 unlink(l_image);
183         if (clean_initrd)
184                 unlink(l_initrd);
185
186         talloc_free(l_image);
187         talloc_free(l_initrd);
188
189         if (!result)
190                 result = kexec_reboot(dry_run);
191
192         return result;
193 }
194
195 /**
196  * pb_elf_hash - Standard elf hash routine.
197  */
198
199 unsigned int pb_elf_hash(const char *str)
200 {
201         unsigned int h = 0, g;
202
203         while (*str) {
204                 h = (h << 4) + *str++;
205                 g = h & 0xf0000000;
206                 if (g)
207                         h ^= g >> 24;
208                 h &= ~g;
209         }
210         pb_log("%s: %x\n", __func__, h);
211         return h;
212 }
213
214 /**
215  * pb_cat_hash - Hashes concatenation of two strings.
216  */
217
218 unsigned int pb_cat_hash(const char *a, const char *b)
219 {
220         unsigned int h;
221         char *s;
222
223         s = talloc_asprintf(NULL, "%s%s", a, b);
224         h = pb_elf_hash(s);
225         talloc_free(s);
226
227         return h;
228 }