ieee1275: split up grub_machine_get_bootlocation
[grub.git] / util / grub-mkstandalone.c
1
2 /*
3   * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013  Free Software Foundation, Inc.
4   *
5   * GRUB 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, either version 3 of the License, or
8   * (at your option) any later version.
9   *
10   * GRUB is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <config.h>
20
21 #include <grub/util/install.h>
22 #include <grub/util/misc.h>
23 #include <grub/emu/config.h>
24
25 #include <string.h>
26
27 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
28 #pragma GCC diagnostic ignored "-Wmissing-declarations"
29 #include <argp.h>
30 #pragma GCC diagnostic error "-Wmissing-prototypes"
31 #pragma GCC diagnostic error "-Wmissing-declarations"
32
33 static char *output_image;
34 static char **files;
35 static int nfiles;
36 const struct grub_install_image_target_desc *format;
37 static FILE *memdisk;
38
39 enum
40   {
41     OPTION_OUTPUT = 'o',
42     OPTION_FORMAT = 'O'
43   };
44
45 static struct argp_option options[] = {
46   GRUB_INSTALL_OPTIONS,
47   {"output", 'o', N_("FILE"),
48    0, N_("save output in FILE [required]"), 2},
49   {"format", 'O', N_("FILE"), 0, 0, 2},
50   {"compression", 'C', "xz|none|auto", OPTION_HIDDEN, 0, 2},
51   {0, 0, 0, 0, 0, 0}
52 };
53
54 static char *
55 help_filter (int key, const char *text, void *input __attribute__ ((unused)))
56 {
57   switch (key)
58     {
59     case 'O':
60       {
61         char *formats = grub_install_get_image_targets_string (), *ret;
62         ret = xasprintf ("%s\n%s %s", _("generate an image in FORMAT"),
63                          _("available formats:"), formats);
64         free (formats);
65         return ret;
66       }
67     default:
68       return grub_install_help_filter (key, text, input);
69     }
70 }
71
72 static error_t
73 argp_parser (int key, char *arg, struct argp_state *state)
74 {
75   if (key == 'C')
76     key = GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS;
77
78   if (grub_install_parse (key, arg))
79     return 0;
80
81   switch (key)
82     {
83
84     case 'o':
85       if (output_image)
86         free (output_image);
87
88       output_image = xstrdup (arg);
89       break;
90
91     case 'O':
92       {
93         format = grub_install_get_image_target (arg);
94         if (!format)
95           {
96             printf (_("unknown target format %s\n"), arg);
97             argp_usage (state);
98             exit (1);
99           }
100         break;
101       }
102
103     case ARGP_KEY_ARG:
104       files[nfiles++] = xstrdup (arg);
105       break;
106
107     default:
108       return ARGP_ERR_UNKNOWN;
109     }
110   return 0;
111 }
112
113 struct argp argp = {
114   options, argp_parser, N_("[OPTION] SOURCE..."),
115   N_("Generate a standalone image (containing all modules) in the selected format")"\v"N_("Graft point syntax (E.g. /boot/grub/grub.cfg=./grub.cfg) is accepted"), 
116   NULL, help_filter, NULL
117 };
118
119 /* tar support */
120 #define MAGIC   "ustar"
121 struct head
122 {
123   char name[100];
124   char mode[8];
125   char uid[8];
126   char gid[8];
127   char size[12];
128   char mtime[12];
129   char chksum[8];
130   char typeflag;
131   char linkname[100];
132   char magic[6];
133   char version[2];
134   char uname[32];
135   char gname[32];
136   char devmajor[8];
137   char devminor[8];
138   char prefix[155];
139   char pad[12];
140 } GRUB_PACKED;
141
142 static void
143 write_zeros (unsigned rsz)
144 {
145   char buf[512];
146
147   memset (buf, 0, 512);
148   fwrite (buf, 1, rsz, memdisk);
149 }
150
151 static void
152 write_pad (unsigned sz)
153 {
154   write_zeros ((~sz + 1) & 511);
155 }
156
157 static void
158 set_tar_value (char *field, grub_uint32_t val,
159                unsigned len)
160 {
161   unsigned i;
162   for (i = 0; i < len - 1; i++)
163     field[len - 2 - i] = '0' + ((val >> (3 * i)) & 7);
164 }
165
166 static void
167 compute_checksum (struct head *hd)
168 {
169   unsigned int chk = 0;
170   unsigned char *ptr;
171   memset (hd->chksum, ' ', 8);
172   for (ptr = (unsigned char *) hd; ptr < (unsigned char *) (hd + 1); ptr++)
173     chk += *ptr;
174   set_tar_value (hd->chksum, chk, 8);
175 }
176
177 static void
178 add_tar_file (const char *from,
179               const char *to)
180 {
181   char *tcn;
182   const char *iptr;
183   char *optr;
184   struct head hd;
185   grub_util_fd_t in;
186   ssize_t r;
187   grub_uint32_t mtime = 0;
188   grub_uint32_t size;
189
190   COMPILE_TIME_ASSERT (sizeof (hd) == 512);
191
192   if (grub_util_is_special_file (from))
193     return;
194
195   mtime = grub_util_get_mtime (from);
196
197   optr = tcn = xmalloc (strlen (to) + 1);
198   for (iptr = to; *iptr == '/'; iptr++);
199   for (; *iptr; iptr++)
200     if (!(iptr[0] == '/' && iptr[1] == '/'))
201       *optr++ = *iptr;
202   *optr = '\0';
203
204   if (grub_util_is_directory (from))
205     {
206       grub_util_fd_dir_t d;
207       grub_util_fd_dirent_t de;
208
209       d = grub_util_fd_opendir (from);
210
211       while ((de = grub_util_fd_readdir (d)))
212         {
213           char *fp, *tfp;
214           if (strcmp (de->d_name, ".") == 0)
215             continue;
216           if (strcmp (de->d_name, "..") == 0)
217             continue;
218           fp = grub_util_path_concat (2, from, de->d_name);
219           tfp = xasprintf ("%s/%s", to, de->d_name);
220           add_tar_file (fp, tfp);
221           free (fp);
222         }
223       grub_util_fd_closedir (d);
224       free (tcn);
225       return;
226     }
227
228   if (optr - tcn > 99)
229     {
230       memset (&hd, 0, sizeof (hd));
231       memcpy (hd.name, tcn, 99);
232       memcpy (hd.mode, "0000600", 7);
233       memcpy (hd.uid, "0001750", 7);
234       memcpy (hd.gid, "0001750", 7);
235
236       set_tar_value (hd.size, optr - tcn, 12);
237       set_tar_value (hd.mtime, mtime, 12);
238       hd.typeflag = 'L';
239       memcpy (hd.magic, MAGIC, sizeof (hd.magic));
240       memcpy (hd.uname, "grub", 4);
241       memcpy (hd.gname, "grub", 4);
242
243       compute_checksum (&hd);
244
245       fwrite (&hd, 1, sizeof (hd), memdisk);
246       fwrite (tcn, 1, optr - tcn, memdisk);
247
248       write_pad (optr - tcn);
249     }
250
251   in = grub_util_fd_open (from, GRUB_UTIL_FD_O_RDONLY);
252   if (!GRUB_UTIL_FD_IS_VALID (in))
253     grub_util_error (_("cannot open `%s': %s"), from, grub_util_fd_strerror ());
254
255   if (!grub_install_copy_buffer)
256     grub_install_copy_buffer = xmalloc (GRUB_INSTALL_COPY_BUFFER_SIZE);
257
258   size = grub_util_get_fd_size (in, from, NULL);
259
260   memset (&hd, 0, sizeof (hd));
261   memcpy (hd.name, tcn, optr - tcn < 99 ? optr - tcn : 99);
262   memcpy (hd.mode, "0000600", 7);
263   memcpy (hd.uid, "0001750", 7);
264   memcpy (hd.gid, "0001750", 7);
265
266   set_tar_value (hd.size, size, 12);
267   set_tar_value (hd.mtime, mtime, 12);
268   hd.typeflag = '0';
269   memcpy (hd.magic, MAGIC, sizeof (hd.magic));
270   memcpy (hd.uname, "grub", 4);
271   memcpy (hd.gname, "grub", 4);
272
273   compute_checksum (&hd);
274
275   fwrite (&hd, 1, sizeof (hd), memdisk);
276  
277   while (1)
278     {
279       r = grub_util_fd_read (in, grub_install_copy_buffer, GRUB_INSTALL_COPY_BUFFER_SIZE);
280       if (r <= 0)
281         break;
282       fwrite (grub_install_copy_buffer, 1, r, memdisk);
283     }
284   grub_util_fd_close (in);
285
286   write_pad (size);
287   free (tcn);
288 }
289
290 int
291 main (int argc, char *argv[])
292 {
293   const char *pkglibdir;
294   int i;
295
296   grub_util_host_init (&argc, &argv);
297   grub_util_disable_fd_syncs ();
298
299   files = xmalloc ((argc + 1) * sizeof (files[0]));
300
301   argp_parse (&argp, argc, argv, 0, 0, 0);
302
303   pkglibdir = grub_util_get_pkglibdir ();
304
305   if (!output_image)
306     grub_util_error ("%s", _("output file must be specified"));
307
308   if (!format)
309     grub_util_error ("%s", _("Target format not specified (use the -O option)."));
310
311   if (!grub_install_source_directory)
312     grub_install_source_directory = grub_util_path_concat (2, pkglibdir, grub_util_get_target_dirname (format));
313
314   enum grub_install_plat plat = grub_install_get_target (grub_install_source_directory);
315
316   char *memdisk_dir = grub_util_make_temporary_dir ();
317   char *boot_grub = grub_util_path_concat (3, memdisk_dir, "boot", "grub");
318   grub_install_copy_files (grub_install_source_directory,
319                            boot_grub, plat);
320
321   char *memdisk_img = grub_util_make_temporary_file ();
322
323   memdisk = grub_util_fopen (memdisk_img, "wb");
324
325   add_tar_file (memdisk_dir, "");
326   for (i = 0; i < nfiles; i++)
327     {
328       char *eq = grub_strchr (files[i], '=');
329       char *from, *to;
330       if (!eq)
331         {
332           from = files[i];
333           to = files[i];
334         }
335       else
336         {
337           *eq = '\0';
338           to = files[i];
339           from = eq + 1;
340         }
341       while (*to == '/')
342         to++;
343       add_tar_file (from, to);
344     }
345   write_zeros (512);
346
347   fclose (memdisk);
348
349   grub_util_unlink_recursive (memdisk_dir);
350
351   grub_install_push_module ("memdisk");
352   grub_install_push_module ("tar");
353
354   grub_install_make_image_wrap (grub_install_source_directory,
355                                 "(memdisk)/boot/grub", output_image,
356                                 memdisk_img, NULL,
357                                 grub_util_get_target_name (format), 0);
358
359   grub_util_unlink (memdisk_img);
360   return 0;
361 }