Fail if xorriso failed.
[grub.git] / util / grub-mkrescue.c
1 /*
2  *  Make GRUB rescue image
3  *
4  *  GRUB  --  GRand Unified Bootloader
5  *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010  Free Software Foundation, Inc.
6  *
7  *  GRUB is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  GRUB is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #include <grub/util/install.h>
24 #include <grub/util/misc.h>
25 #include <grub/emu/exec.h>
26 #include <grub/emu/config.h>
27 #include <grub/emu/hostdisk.h>
28 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
29 #pragma GCC diagnostic ignored "-Wmissing-declarations"
30 #include <argp.h>
31 #pragma GCC diagnostic error "-Wmissing-prototypes"
32 #pragma GCC diagnostic error "-Wmissing-declarations"
33
34 #include <sys/types.h>
35 #include <sys/wait.h>
36
37 #include <string.h>
38 #include <time.h>
39
40 static char *source_dirs[GRUB_INSTALL_PLATFORM_MAX];
41 static char *rom_directory;
42 static char *label_font;
43 static char *label_color;
44 static char *label_bgcolor;
45 static char *product_name;
46 static char *product_version;
47 static char *output_image;
48 static char *xorriso;
49 static char *boot_grub;
50 static int xorriso_argc;
51 static int xorriso_arg_alloc;
52 static char **xorriso_argv;
53 static char *iso_uuid;
54 static char *iso9660_dir;
55
56 static void
57 xorriso_push (const char *val)
58 {
59   if (xorriso_arg_alloc <= xorriso_argc + 1)
60     {
61       xorriso_arg_alloc = 2 * (4 + xorriso_argc);
62       xorriso_argv = xrealloc (xorriso_argv,
63                                sizeof (xorriso_argv[0])
64                                * xorriso_arg_alloc);
65     }
66   xorriso_argv[xorriso_argc++] = xstrdup (val);
67 }
68
69 static void
70 xorriso_link (const char *from, const char *to)
71 {
72   char *tof = grub_util_path_concat (2, iso9660_dir, to);
73   char *val = xasprintf ("%s=%s", from, tof);
74   xorriso_push (val);
75   free (val);
76   free (tof);
77 }
78
79 enum
80   {
81     OPTION_OUTPUT = 'o',
82     OPTION_ROM_DIRECTORY = 0x301,
83     OPTION_XORRISO,
84     OPTION_GLUE_EFI,
85     OPTION_RENDER_LABEL,
86     OPTION_LABEL_FONT,
87     OPTION_LABEL_COLOR,
88     OPTION_LABEL_BGCOLOR,
89     OPTION_PRODUCT_NAME,
90     OPTION_PRODUCT_VERSION,
91     OPTION_SPARC_BOOT,
92     OPTION_ARCS_BOOT
93   };
94
95 static struct argp_option options[] = {
96   GRUB_INSTALL_OPTIONS,
97   {"output", 'o', N_("FILE"),
98    0, N_("save output in FILE [required]"), 2},
99   {"rom-directory", OPTION_ROM_DIRECTORY, N_("DIR"),
100    0, N_("save ROM images in DIR [optional]"), 2},
101   {"xorriso", OPTION_XORRISO, N_("FILE"),
102    /* TRANSLATORS: xorriso is a program for creating ISOs and burning CDs.  */
103    0, N_("use FILE as xorriso [optional]"), 2},
104   {"grub-glue-efi", OPTION_GLUE_EFI, N_("FILE"), OPTION_HIDDEN, 0, 2},
105   {"grub-render-label", OPTION_RENDER_LABEL, N_("FILE"), OPTION_HIDDEN, 0, 2},
106   {"label-font", OPTION_LABEL_FONT, N_("FILE"), 0, N_("use FILE as font for label"), 2},
107   {"label-color", OPTION_LABEL_COLOR, N_("COLOR"), 0, N_("use COLOR for label"), 2},
108   {"label-bgcolor", OPTION_LABEL_BGCOLOR, N_("COLOR"), 0, N_("use COLOR for label background"), 2},
109   {"product-name", OPTION_PRODUCT_NAME, N_("STRING"), 0, N_("use STRING as product name"), 2},
110   {"product-version", OPTION_PRODUCT_VERSION, N_("STRING"), 0, N_("use STRING as product version"), 2},
111   {"sparc-boot", OPTION_SPARC_BOOT, 0, 0, N_("enable sparc boot. Disables HFS+, APM, ARCS and boot as disk image for i386-pc"), 2},
112   {"arcs-boot", OPTION_ARCS_BOOT, 0, 0, N_("enable ARCS (big-endian mips machines, mostly SGI) boot. Disables HFS+, APM, sparc64 and boot as disk image for i386-pc"), 2},
113   {0, 0, 0, 0, 0, 0}
114 };
115
116 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
117
118 static char *
119 help_filter (int key, const char *text, void *input __attribute__ ((unused)))
120 {
121   switch (key)
122     {
123     case ARGP_KEY_HELP_PRE_DOC:
124       /* TRANSLATORS: it generates one single image which is bootable through any method. */
125       return strdup (_("Make GRUB CD-ROM, disk, pendrive and floppy bootable image."));
126     case ARGP_KEY_HELP_POST_DOC:
127       {
128         char *p1, *out;
129
130         p1 = xasprintf (_("Generates a bootable CD/USB/floppy image.  Arguments other than options to this program"
131       " are passed to xorriso, and indicate source files, source directories, or any of the "
132       "mkisofs options listed by the output of `%s'."), "xorriso -as mkisofs -help");
133         out = xasprintf ("%s\n\n%s\n\n%s", p1,
134           _("Option -- switches to native xorriso command mode."),
135           _("Mail xorriso support requests to <bug-xorriso@gnu.org>."));
136         free (p1);
137         return out;
138       }
139     default:
140       return grub_install_help_filter (key, text, input);
141     }
142 }
143
144 #pragma GCC diagnostic error "-Wformat-nonliteral"
145
146 enum {
147   SYS_AREA_AUTO,
148   SYS_AREA_COMMON,
149   SYS_AREA_SPARC,
150   SYS_AREA_ARCS
151 } system_area = SYS_AREA_AUTO;
152
153 static error_t 
154 argp_parser (int key, char *arg, struct argp_state *state)
155 {
156   if (grub_install_parse (key, arg))
157     return 0;
158   switch (key)
159     {
160     case OPTION_OUTPUT:
161       free (output_image);
162       output_image = xstrdup (arg);
163       return 0;
164     case OPTION_ROM_DIRECTORY:
165       free (rom_directory);
166       rom_directory = xstrdup (arg);
167       return 0;
168
169       /*
170        FIXME:
171     # Intentionally undocumented
172     --grub-mkimage-extra)
173         mkimage_extra_arg="$mkimage_extra_arg `argument $option "$@"`"; shift ;;
174     --grub-mkimage-extra=*)
175         mkimage_extra_arg="$mkimage_extra_arg `echo "$option" | sed 's/--grub-mkimage-extra=//'`" ;;
176       */
177     case OPTION_SPARC_BOOT:
178       system_area = SYS_AREA_SPARC;
179       return 0;
180     case OPTION_ARCS_BOOT:
181       system_area = SYS_AREA_ARCS;
182       return 0;
183     case OPTION_PRODUCT_NAME:
184       free (product_name);
185       product_name = xstrdup (arg);
186       return 0;
187     case OPTION_PRODUCT_VERSION:
188       free (product_version);
189       product_version = xstrdup (arg);
190       return 0;
191       /* Accept and ignore for compatibility.  */
192     case OPTION_GLUE_EFI:
193     case OPTION_RENDER_LABEL:
194       return 0;
195     case OPTION_LABEL_FONT:
196       free (label_font);
197       label_font = xstrdup (arg);
198       return 0;
199
200     case OPTION_LABEL_COLOR:
201       free (label_color);
202       label_color = xstrdup (arg);
203       return 0;
204
205     case OPTION_LABEL_BGCOLOR:
206       free (label_bgcolor);
207       label_bgcolor = xstrdup (arg);
208       return 0;
209
210     case OPTION_XORRISO:
211       free (xorriso);
212       xorriso = xstrdup (arg);
213       return 0;
214
215     default:
216       return ARGP_ERR_UNKNOWN;
217     }
218 }
219
220 struct argp argp = {
221   options, argp_parser, N_("[OPTION] SOURCE..."),
222   NULL, NULL, help_filter, NULL
223 };
224
225 static void
226 write_part (FILE *f, const char *srcdir)
227 {
228   FILE *in;
229   char *inname = grub_util_path_concat (2, srcdir, "partmap.lst");
230   char buf[260];
231   in = grub_util_fopen (inname, "rb");
232   if (!in)
233     return;
234   while (fgets (buf, 256, in))
235     {
236       char *ptr;
237       for (ptr = buf + strlen (buf) - 1;
238            ptr >= buf && (*ptr == '\n' || *ptr == '\r');
239            ptr--);
240       ptr[1] = '\0';
241       fprintf (f, "insmod %s\n", buf);
242     }
243   fclose (in);
244 }
245
246 static void
247 make_image_abs (enum grub_install_plat plat,
248                 const char *mkimage_target,
249                 const char *output)
250 {
251   char *load_cfg;
252   FILE *load_cfg_f;
253
254   if (!source_dirs[plat])
255     return;
256
257   grub_util_info (N_("enabling %s support ..."),
258                   mkimage_target);
259
260   load_cfg = grub_util_make_temporary_file ();
261
262   load_cfg_f = grub_util_fopen (load_cfg, "wb");
263   fprintf (load_cfg_f, "search --fs-uuid --set=root %s\n", iso_uuid);
264   fprintf (load_cfg_f, "set prefix=(${root})/boot/grub\n");
265
266   write_part (load_cfg_f, source_dirs[plat]);
267   fclose (load_cfg_f);
268
269   grub_install_push_module ("search");
270   grub_install_push_module ("iso9660");
271   grub_install_make_image_wrap (source_dirs[plat], "/boot/grub", output,
272                                 0, load_cfg,
273                                 mkimage_target, 0);
274   grub_install_pop_module ();
275   grub_install_pop_module ();
276   grub_util_unlink (load_cfg);
277 }
278
279 static void
280 make_image (enum grub_install_plat plat,
281             const char *mkimage_target,
282             const char *output_sub)
283 {
284   char *out = grub_util_path_concat (2, boot_grub, output_sub);
285   make_image_abs (plat, mkimage_target, out);
286   free (out);
287 }
288
289 static void
290 make_image_fwdisk_abs (enum grub_install_plat plat,
291                        const char *mkimage_target,
292                        const char *output)
293 {
294   char *load_cfg;
295   FILE *load_cfg_f;
296
297   if (!source_dirs[plat])
298     return;
299
300   grub_util_info (N_("enabling %s support ..."),
301                   mkimage_target);
302
303   load_cfg = grub_util_make_temporary_file ();
304
305   load_cfg_f = grub_util_fopen (load_cfg, "wb");
306   write_part (load_cfg_f, source_dirs[plat]);
307   fclose (load_cfg_f);
308
309   grub_install_push_module ("iso9660");
310   grub_install_make_image_wrap (source_dirs[plat], "()/boot/grub", output,
311                                 0, load_cfg, mkimage_target, 0);
312   grub_install_pop_module ();
313   grub_util_unlink (load_cfg);
314 }
315
316 static int
317 check_xorriso (const char *val)
318 {
319   const char *argv[5];
320   int fd;
321   pid_t pid;
322   FILE *mdadm;
323   char *buf = NULL;
324   size_t len = 0;
325   int ret = 0;
326   int wstatus = 0;
327
328   argv[0] = xorriso;
329   argv[1] = "-as";
330   argv[2] = "mkisofs";
331   argv[3] = "-help";
332   argv[4] = NULL;
333
334   pid = grub_util_exec_pipe_stderr (argv, &fd);
335
336   if (!pid)
337     return 0;
338
339   /* Parent.  Read mdadm's output.  */
340   mdadm = fdopen (fd, "r");
341   if (! mdadm)
342     return 0;
343
344   while (getline (&buf, &len, mdadm) > 0)
345     {
346       if (grub_strstr (buf, val))
347         ret = 1;
348     }
349
350   close (fd);
351   waitpid (pid, &wstatus, 0);
352   free (buf);
353   if (!WIFEXITED (wstatus) || WEXITSTATUS(wstatus) != 0)
354     return 0;
355   return ret;
356 }
357
358 static void
359 make_image_fwdisk (enum grub_install_plat plat,
360                    const char *mkimage_target,
361                    const char *output_sub)
362 {
363   char *out = grub_util_path_concat (2, boot_grub, output_sub);
364   make_image_fwdisk_abs (plat, mkimage_target, out);
365   free (out);
366 }
367
368 static int
369 option_is_end (const struct argp_option *opt)
370 {
371   return !opt->key && !opt->name && !opt->doc && !opt->group;
372 }
373
374
375 static int
376 args_to_eat (const char *arg)
377 {
378   int j;
379
380   if (arg[0] != '-')
381     return 0;
382
383   if (arg[1] == '-')
384     {
385       for (j = 0; !option_is_end(&options[j]); j++)
386         {
387           size_t len = strlen (options[j].name);
388           if (strncmp (arg + 2, options[j].name, len) == 0)
389             {
390               if (arg[2 + len] == '=')
391                 return 1;
392               if (arg[2 + len] == '\0' && options[j].arg)
393                 return 2;
394               if (arg[2 + len] == '\0')
395                 return 1;
396             }
397         }
398       if (strcmp (arg, "--help") == 0)
399         return 1;
400       if (strcmp (arg, "--usage") == 0)
401         return 1;
402       if (strcmp (arg, "--version") == 0)
403         return 1;
404       return 0;
405     }
406   if (arg[2] && arg[3])
407     return 0;
408   for (j = 0; !option_is_end(&options[j]); j++)
409     {
410       if (options[j].key > 0 && options[j].key < 128 && arg[1] == options[j].key)
411         {
412           if (options[j].arg)
413             return 2;
414           return 1;
415         }
416       if (arg[1] == '?')
417         return 1;
418     }
419   return 0;
420 }
421
422 int
423 main (int argc, char *argv[])
424 {
425   char *romdir;
426   char *sysarea_img = NULL;
427   const char *pkgdatadir;
428   int argp_argc;
429   char **argp_argv;
430   int xorriso_tail_argc;
431   char **xorriso_tail_argv;
432   int rv;
433
434   grub_util_host_init (&argc, &argv);
435   grub_util_disable_fd_syncs ();
436
437   pkgdatadir = grub_util_get_pkgdatadir ();
438
439   product_name = xstrdup (PACKAGE_NAME);
440   product_version = xstrdup (PACKAGE_VERSION);
441   xorriso = xstrdup ("xorriso");
442   label_font = grub_util_path_concat (2, pkgdatadir, "unicode.pf2");
443
444   argp_argv = xmalloc (sizeof (argp_argv[0]) * argc);
445   xorriso_tail_argv = xmalloc (sizeof (argp_argv[0]) * argc);
446
447   xorriso_tail_argc = 0;
448   /* Program name */
449   argp_argv[0] = argv[0];
450   argp_argc = 1;
451
452   /* argp doesn't allow us to catch unknwon arguments,
453      so catch them before passing to argp
454    */
455   {
456     int i;
457     for (i = 1; i < argc; i++)
458       {
459         if (strcmp (argv[i], "-output") == 0) {
460           argp_argv[argp_argc++] = (char *) "--output";
461           i++;
462           argp_argv[argp_argc++] = argv[i];
463           continue;
464         }
465         switch (args_to_eat (argv[i]))
466           {
467           case 2:
468             argp_argv[argp_argc++] = argv[i++];
469             /* Fallthrough  */
470           case 1:
471             argp_argv[argp_argc++] = argv[i];
472             break;
473           case 0:
474             xorriso_tail_argv[xorriso_tail_argc++] = argv[i];
475             break;
476           }
477       }
478   }
479
480   argp_parse (&argp, argp_argc, argp_argv, 0, 0, 0);
481
482   if (!output_image)
483     grub_util_error ("%s", _("output file must be specified"));
484
485   if (!check_xorriso ("graft-points")) {
486     grub_util_error ("%s", _("xorriso not found"));
487   }
488
489   grub_init_all ();
490   grub_hostfs_init ();
491   grub_host_init ();
492
493   xorriso_push (xorriso);
494   xorriso_push ("-as");
495   xorriso_push ("mkisofs");
496   xorriso_push ("-graft-points");
497   
498   iso9660_dir = grub_util_make_temporary_dir ();
499   grub_util_info ("temporary iso9660 dir is `%s'", iso9660_dir);
500   boot_grub = grub_util_path_concat (3, iso9660_dir, "boot", "grub");
501   grub_install_mkdir_p (boot_grub);
502   romdir = grub_util_path_concat (2, boot_grub, "roms");
503   grub_util_mkdir (romdir);
504
505   if (!grub_install_source_directory)
506     {
507       const char *pkglibdir = grub_util_get_pkglibdir ();
508       enum grub_install_plat plat;
509
510       for (plat = 0; plat < GRUB_INSTALL_PLATFORM_MAX; plat++)
511         {
512           char *platdir = grub_util_path_concat (2, pkglibdir,
513                                                  grub_install_get_platform_name (plat));
514
515           if (!grub_util_is_directory (platdir))
516             {
517               free (platdir);
518               continue;
519             }
520           source_dirs[plat] = platdir;
521           grub_install_copy_files (platdir,
522                                    boot_grub, plat);
523         }
524     }
525   else
526     {
527       enum grub_install_plat plat;
528       plat = grub_install_get_target (grub_install_source_directory);
529       grub_install_copy_files (grub_install_source_directory,
530                                boot_grub, plat);
531       source_dirs[plat] = xstrdup (grub_install_source_directory);
532     }
533   if (system_area == SYS_AREA_AUTO || grub_install_source_directory)
534     {
535       if (source_dirs[GRUB_INSTALL_PLATFORM_I386_PC]
536           || source_dirs[GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275]
537           || source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI]
538           || source_dirs[GRUB_INSTALL_PLATFORM_IA64_EFI]
539           || source_dirs[GRUB_INSTALL_PLATFORM_ARM_EFI]
540           || source_dirs[GRUB_INSTALL_PLATFORM_ARM64_EFI]
541           || source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI])
542         system_area = SYS_AREA_COMMON;
543       else if (source_dirs[GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275])
544         system_area = SYS_AREA_SPARC;
545       else if (source_dirs[GRUB_INSTALL_PLATFORM_MIPS_ARC])
546         system_area = SYS_AREA_ARCS;
547     }
548
549   /* obtain date-based UUID.  */
550   {
551     time_t tim;
552     struct tm *tmm;
553     tim = time (NULL);
554     tmm = gmtime (&tim);
555     iso_uuid = xmalloc (55);
556     grub_snprintf (iso_uuid, 50,
557                    "%04d-%02d-%02d-%02d-%02d-%02d-00",
558                    tmm->tm_year + 1900,
559                    tmm->tm_mon + 1,
560                    tmm->tm_mday,
561                    tmm->tm_hour,
562                    tmm->tm_min,
563                    tmm->tm_sec);
564   }
565   {
566     char *uuid_out = xmalloc (strlen (iso_uuid) + 1 + 40);
567     char *optr;
568     const char *iptr;
569     optr = grub_stpcpy (uuid_out, "--modification-date=");
570     for (iptr = iso_uuid; *iptr; iptr++)
571       if (*iptr != '-')
572         *optr++ = *iptr;
573     *optr = '\0';
574     xorriso_push (uuid_out);
575     free (uuid_out);
576   }
577
578   /* build BIOS core.img.  */
579   if (source_dirs[GRUB_INSTALL_PLATFORM_I386_PC])
580     {
581       char *load_cfg;
582       FILE *load_cfg_f;
583       char *output = grub_util_path_concat (3, boot_grub, "i386-pc", "eltorito.img");
584       load_cfg = grub_util_make_temporary_file ();
585
586       grub_util_info (N_("enabling %s support ..."), "BIOS");
587       load_cfg_f = grub_util_fopen (load_cfg, "wb");
588       write_part (load_cfg_f, source_dirs[GRUB_INSTALL_PLATFORM_I386_PC]);
589       fclose (load_cfg_f);
590
591       grub_install_push_module ("biosdisk");
592       grub_install_push_module ("iso9660");
593       grub_install_make_image_wrap (source_dirs[GRUB_INSTALL_PLATFORM_I386_PC],
594                                     "/boot/grub", output,
595                                     0, load_cfg,
596                                     "i386-pc-eltorito", 0);
597
598       xorriso_push ("-b");
599       xorriso_push ("boot/grub/i386-pc/eltorito.img");
600       xorriso_push ("-no-emul-boot");
601       xorriso_push ("-boot-load-size");
602       xorriso_push ("4");
603       xorriso_push ("-boot-info-table");
604       if (system_area == SYS_AREA_COMMON)
605         {
606           if (check_xorriso ("grub2-boot-info"))
607             {
608               char *boot_hybrid = grub_util_path_concat (2, source_dirs[GRUB_INSTALL_PLATFORM_I386_PC],
609                                                          "boot_hybrid.img");
610               xorriso_push ("--grub2-boot-info");
611               xorriso_push ("--grub2-mbr");
612               xorriso_push (boot_hybrid);
613             }
614           else
615             {
616               FILE *sa, *bi;
617               size_t sz;
618               char buf[512];
619               char *bin = grub_util_path_concat (2, source_dirs[GRUB_INSTALL_PLATFORM_I386_PC],
620                                                  "boot.img");
621               grub_util_warn ("%s", _("Your xorriso doesn't support `--grub2-boot-info'. Some features are disabled. Please use xorriso 1.2.9 or later."));
622               sysarea_img = grub_util_make_temporary_file ();
623               sa = grub_util_fopen (sysarea_img, "wb");
624               if (!sa)
625                 grub_util_error (_("cannot open `%s': %s"), sysarea_img,
626                                  strerror (errno));
627               bi = grub_util_fopen (bin, "rb");
628               if (!bi)
629                 grub_util_error (_("cannot open `%s': %s"), bin,
630                                  strerror (errno));
631               if (fread (buf, 1, 512, bi) != 512)
632                 grub_util_error (_("cannot read `%s': %s"), bin,
633                                  strerror (errno));
634               fclose (bi);
635               fwrite (buf, 1, 512, sa);
636               
637               grub_install_make_image_wrap_file (source_dirs[GRUB_INSTALL_PLATFORM_I386_PC],
638                                                  "/boot/grub", sa, sysarea_img,
639                                                  0, load_cfg,
640                                                  "i386-pc", 0);
641               sz = ftello (sa);
642               fflush (sa);
643               grub_util_fd_sync (fileno (sa));
644               fclose (sa);
645               
646               if (sz > 32768)
647                 {
648                   grub_util_warn ("%s", _("Your xorriso doesn't support `--grub2-boot-info'. Your core image is too big. Boot as disk is disabled. Please use xorriso 1.2.9 or later."));
649                 }
650               else
651                 {
652                   xorriso_push ("-G");
653                   xorriso_push (sysarea_img);
654                 }
655             }
656         }
657       grub_install_pop_module ();
658       grub_install_pop_module ();
659       grub_util_unlink (load_cfg);
660     }
661
662   /** build multiboot core.img */
663   grub_install_push_module ("pata");
664   grub_install_push_module ("ahci");
665   grub_install_push_module ("at_keyboard");
666   make_image (GRUB_INSTALL_PLATFORM_I386_MULTIBOOT, "i386-multiboot", "i386-multiboot/core.elf");
667   grub_install_pop_module ();
668   grub_install_pop_module ();
669   grub_install_pop_module ();
670
671   make_image_fwdisk (GRUB_INSTALL_PLATFORM_I386_IEEE1275, "i386-ieee1275", "ofwx86.elf");
672
673   char *core_services = NULL;
674
675   if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI]
676       || source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI]
677       || source_dirs[GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275])
678     {
679       char *mach_ker, *sv, *label, *label_text;
680       FILE *f;
681       core_services = grub_util_path_concat (4, iso9660_dir, "System", "Library", "CoreServices");
682       grub_install_mkdir_p (core_services);
683
684       mach_ker = grub_util_path_concat (2, iso9660_dir, "mach_kernel");
685       f = grub_util_fopen (mach_ker, "wb");
686       fclose (f);
687       free (mach_ker);
688
689       sv = grub_util_path_concat (2, core_services, "SystemVersion.plist");
690       f = grub_util_fopen (sv, "wb");
691       fprintf (f, "<plist version=\"1.0\">\n"
692                "<dict>\n"
693                "        <key>ProductBuildVersion</key>\n"
694                "        <string></string>\n"
695                "        <key>ProductName</key>\n"
696                "        <string>%s</string>\n"
697                "        <key>ProductVersion</key>\n"
698                "        <string>%s</string>\n"
699                "</dict>\n"
700                "</plist>\n", product_name, product_version);
701       fclose (f);
702       free (sv);
703       label = grub_util_path_concat (2, core_services, ".disk_label");
704       char *label_string = xasprintf ("%s %s", product_name, product_version);
705       grub_util_render_label (label_font, label_bgcolor ? : "white",
706                               label_color ? : "black", label_string, label);
707       free (label);
708       label_text = grub_util_path_concat (2, core_services, ".disk_label.contentDetails");
709       f = grub_util_fopen (label_text, "wb");
710       fprintf (f, "%s\n", label_string);
711       fclose (f);
712       free (label_string);
713       free (label_text);
714       if (system_area == SYS_AREA_COMMON)
715         {
716           xorriso_push ("-hfsplus");
717           xorriso_push ("-apm-block-size");
718           xorriso_push ("2048");
719           xorriso_push ("-hfsplus-file-creator-type");
720           xorriso_push ("chrp");
721           xorriso_push ("tbxj");
722           xorriso_push ("/System/Library/CoreServices/.disk_label");
723
724           if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI]
725               || source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI])
726             {
727               xorriso_push ("-hfs-bless-by");
728               xorriso_push ("i");
729               xorriso_push ("/System/Library/CoreServices/boot.efi");
730             }
731         }
732     }
733
734   if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI]
735       || source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI]
736       || source_dirs[GRUB_INSTALL_PLATFORM_IA64_EFI]
737       || source_dirs[GRUB_INSTALL_PLATFORM_ARM_EFI]
738       || source_dirs[GRUB_INSTALL_PLATFORM_ARM64_EFI])
739     {
740       char *efidir = grub_util_make_temporary_dir ();
741       char *efidir_efi = grub_util_path_concat (2, efidir, "efi");
742       char *efidir_efi_boot = grub_util_path_concat (3, efidir, "efi", "boot");
743       char *imgname, *img32, *img64, *img_mac = NULL;
744       char *efiimgfat;
745       grub_install_mkdir_p (efidir_efi_boot);
746
747       grub_install_push_module ("part_gpt");
748       grub_install_push_module ("part_msdos");
749
750       imgname = grub_util_path_concat (2, efidir_efi_boot, "bootia64.efi");
751       make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_IA64_EFI, "ia64-efi", imgname);
752       free (imgname);
753
754       grub_install_push_module ("part_apple");
755       img64 = grub_util_path_concat (2, efidir_efi_boot, "bootx64.efi");
756       make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_X86_64_EFI, "x86_64-efi", img64);
757       grub_install_pop_module ();
758
759       grub_install_push_module ("part_apple");
760       img32 = grub_util_path_concat (2, efidir_efi_boot, "bootia32.efi");
761       make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_I386_EFI, "i386-efi", img32);
762       grub_install_pop_module ();
763
764       imgname = grub_util_path_concat (2, efidir_efi_boot, "bootarm.efi");
765       make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_ARM_EFI, "arm-efi", imgname);
766       free (imgname);
767
768       imgname = grub_util_path_concat (2, efidir_efi_boot, "bootaa64.efi");
769       make_image_fwdisk_abs (GRUB_INSTALL_PLATFORM_ARM64_EFI, "arm64-efi",
770                              imgname);
771       free (imgname);
772
773       if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI])
774         {
775           imgname = grub_util_path_concat (2, efidir_efi_boot, "boot.efi");
776           /* For old macs. Suggested by Peter Jones.  */
777           grub_install_copy_file (img32, imgname, 1);
778         }
779
780       if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI]
781           || source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI])
782         img_mac = grub_util_path_concat (2, core_services, "boot.efi");
783
784       if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI]
785           && source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI])
786         grub_util_glue_efi (img32, img64, img_mac);
787       else if (source_dirs[GRUB_INSTALL_PLATFORM_X86_64_EFI])
788         grub_install_copy_file (img64, img_mac, 1);
789       else if (source_dirs[GRUB_INSTALL_PLATFORM_I386_EFI])
790         grub_install_copy_file (img32, img_mac, 1);
791
792       free (img_mac);
793       free (img32);
794       free (img64);
795       free (efidir_efi_boot);
796
797       efiimgfat = grub_util_path_concat (2, iso9660_dir, "efi.img");
798       rv = grub_util_exec ((const char * []) { "mformat", "-C", "-f", "2880", "-L", "16", "-i",
799             efiimgfat, "::", NULL });
800       if (rv != 0)
801         grub_util_error ("`%s` invocation failed\n", "mformat");
802       rv = grub_util_exec ((const char * []) { "mcopy", "-s", "-i", efiimgfat, efidir_efi, "::/", NULL });
803       if (rv != 0)
804         grub_util_error ("`%s` invocation failed\n", "mformat");
805       xorriso_push ("--efi-boot");
806       xorriso_push ("efi.img");
807       xorriso_push ("-efi-boot-part");
808       xorriso_push ("--efi-boot-image");
809
810       grub_util_unlink_recursive (efidir);
811       free (efiimgfat);
812       free (efidir_efi);
813       free (efidir);
814       grub_install_pop_module ();
815       grub_install_pop_module ();
816     }
817
818   grub_install_push_module ("part_apple");
819   make_image_fwdisk (GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275, "powerpc-ieee1275", "powerpc-ieee1275/core.elf");
820   grub_install_pop_module ();
821
822   if (source_dirs[GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275])
823     {
824       char *grub_chrp = grub_util_path_concat (2, source_dirs[GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275],
825                                                "grub.chrp");
826       char *bisrc = grub_util_path_concat (2, source_dirs[GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275],
827                                            "bootinfo.txt");
828       char *bootx = grub_util_path_concat (2, core_services, "BootX");
829       char *ppc_chrp = grub_util_path_concat (3, iso9660_dir, "ppc", "chrp");
830       char *bitgt = grub_util_path_concat (3, iso9660_dir, "ppc", "bootinfo.txt");
831       grub_install_copy_file (grub_chrp, bootx, 1);
832       grub_install_mkdir_p (ppc_chrp);
833       grub_install_copy_file (bisrc, bitgt, 1);
834       xorriso_link ("/System/Library/CoreServices/grub.elf", "/boot/grub/powerpc-ieee1275/core.elf");
835       xorriso_link ("/boot/grub/powerpc.elf", "/boot/grub/powerpc-ieee1275/core.elf");
836       /* FIXME: add PreP */
837       if (system_area == SYS_AREA_COMMON)
838         {
839           xorriso_push ("-hfsplus-file-creator-type");
840           xorriso_push ("chrp");
841           xorriso_push ("tbxi");
842           xorriso_push ("/System/Library/CoreServices/BootX");
843           xorriso_push ("-hfs-bless-by");
844           xorriso_push ("p");
845           xorriso_push ("/System/Library/CoreServices");
846         }
847       xorriso_push ("-sysid");
848       xorriso_push ("PPC");
849     }
850
851   make_image_fwdisk (GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275,
852                      "sparc64-ieee1275-cdcore", "sparc64-ieee1275/core.img");
853
854   if (source_dirs[GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275]
855       && system_area == SYS_AREA_SPARC)
856     {
857       char *cdboot;
858       FILE *in, *out;
859       char buf[512];
860       sysarea_img = grub_util_make_temporary_file ();
861       cdboot = grub_util_path_concat (2, source_dirs[GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275],
862                                       "cdboot.img");
863       in = grub_util_fopen (cdboot, "rb");
864       if (!in)
865         grub_util_error (_("cannot open `%s': %s"), cdboot,
866                          strerror (errno));
867       out = grub_util_fopen (sysarea_img, "wb");
868       if (!out)
869         grub_util_error (_("cannot open `%s': %s"), sysarea_img,
870                          strerror (errno));
871       memset (buf, 0, 512);
872       fwrite (buf, 1, 512, out);
873       if (fread (buf, 1, 512, in) != 512)
874         grub_util_error (_("cannot read `%s': %s"), cdboot,
875                          strerror (errno));
876       fwrite (buf, 1, 512, out);
877       fclose (in);
878       fclose (out);
879       xorriso_push ("-G");
880       xorriso_push (sysarea_img);
881       xorriso_push ("-B");
882       xorriso_push (",");
883       xorriso_push ("--grub2-sparc-core");
884       xorriso_push ("/boot/grub/sparc64-ieee1275/core.img");
885     }
886
887   make_image_fwdisk (GRUB_INSTALL_PLATFORM_MIPS_ARC, "mips-arc", "mips-arc/core.img");
888
889   if (source_dirs[GRUB_INSTALL_PLATFORM_MIPS_ARC])
890     {
891       xorriso_link ("/boot/grub/mips-arc/grub", "/boot/grub/mips-arc/core.img");
892       xorriso_link ("/boot/grub/mips-arc/sashARCS", "/boot/grub/mips-arc/core.img");
893       xorriso_link ("/boot/grub/mips-arc/sash", "/boot/grub/mips-arc/core.img");
894     }
895   if (source_dirs[GRUB_INSTALL_PLATFORM_MIPS_ARC] && system_area == SYS_AREA_ARCS)
896     {
897       xorriso_push ("-mips-boot");
898       xorriso_push ("/boot/grub/mips-arc/sashARCS");
899       xorriso_push ("-mips-boot");
900       xorriso_push ("/boot/grub/mips-arc/sash");
901       xorriso_push ("-mips-boot");
902       xorriso_push ("/boot/grub/mips-arc/grub");
903     }
904
905   make_image_fwdisk (GRUB_INSTALL_PLATFORM_MIPSEL_ARC, "mipsel-arc", "arc.exe");
906
907   grub_install_push_module ("pata");
908   make_image (GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS, "mipsel-qemu_mips-elf", "roms/mipsel-qemu_mips.elf");
909
910   make_image (GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, "mipsel-loongson-elf", "loongson.elf");
911
912   make_image (GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, "mipsel-yeeloong-flash", "mipsel-yeeloong.bin");
913   make_image (GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, "mipsel-fuloong2f-flash", "mipsel-fuloong2f.bin");
914
915   make_image (GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS, "mips-qemu_mips-elf", "roms/mips-qemu_mips.elf");
916
917   grub_install_push_module ("at_keyboard");
918
919   make_image (GRUB_INSTALL_PLATFORM_I386_QEMU, "i386-qemu", "roms/qemu.img");
920
921   grub_install_push_module ("ahci");
922
923   make_image (GRUB_INSTALL_PLATFORM_I386_COREBOOT, "i386-coreboot", "roms/coreboot.elf");
924   grub_install_pop_module ();
925   grub_install_pop_module ();
926   grub_install_pop_module ();
927
928   if (rom_directory)
929     {
930       const struct
931       {
932         enum grub_install_plat plat;
933         const char *from, *to;
934       } roms[] =
935           {
936             {GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS, "roms/mipsel-qemu_mips.elf", "mipsel-qemu_mips.elf"},
937             {GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, "loongson.elf", "mipsel-loongson.elf"},
938             {GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, "roms/mipsel-yeeloong.bin", "mipsel-yeeloong.bin"},
939             {GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON, "roms/mipsel-fulong.bin", "mipsel-fulong.bin"},
940             {GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS, "roms/mips-qemu_mips.elf", "mips-qemu_mips.elf"},
941             {GRUB_INSTALL_PLATFORM_I386_QEMU, "roms/qemu.img", "qemu.img"},
942             {GRUB_INSTALL_PLATFORM_I386_COREBOOT, "roms/coreboot.elf", "coreboot.elf"},
943           };
944       grub_size_t i;
945       for (i = 0; i < ARRAY_SIZE (roms); i++)
946         {
947           char *from = grub_util_path_concat (2, boot_grub, roms[i].from);
948           char *to = grub_util_path_concat (2, rom_directory, roms[i].to);
949           grub_install_copy_file (from, to, 0);
950         }
951     }
952
953   xorriso_push ("--protective-msdos-label");
954   xorriso_push ("-o");
955   xorriso_push (output_image);
956   xorriso_push ("-r");
957   xorriso_push (iso9660_dir);
958   xorriso_push ("--sort-weight");
959   xorriso_push ("0");
960   xorriso_push ("/");
961   xorriso_push ("--sort-weight");
962   xorriso_push ("1");
963   xorriso_push ("/boot");
964   int i;
965   for (i = 0; i < xorriso_tail_argc; i++)
966     xorriso_push (xorriso_tail_argv[i]);
967
968   xorriso_argv[xorriso_argc] = NULL;
969
970   rv = grub_util_exec ((const char *const *)xorriso_argv);
971   if (rv != 0)
972     grub_util_error ("`%s` invocation failed\n", "xorriso");
973
974   grub_util_unlink_recursive (iso9660_dir);
975
976   if (sysarea_img)
977     grub_util_unlink (sysarea_img);
978
979   free (core_services);
980   free (romdir);
981   return 0;
982 }