ieee1275: split up grub_machine_get_bootlocation
[grub.git] / util / grub-install-common.c
1 /*
2  *  GRUB  --  GRand Unified Bootloader
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 #include <grub/types.h>
21 #include <grub/emu/misc.h>
22 #include <grub/util/misc.h>
23 #include <grub/misc.h>
24 #include <grub/device.h>
25 #include <grub/disk.h>
26 #include <grub/file.h>
27 #include <grub/fs.h>
28 #include <grub/env.h>
29 #include <grub/term.h>
30 #include <grub/mm.h>
31 #include <grub/lib/hexdump.h>
32 #include <grub/crypto.h>
33 #include <grub/command.h>
34 #include <grub/i18n.h>
35 #include <grub/zfs/zfs.h>
36 #include <grub/util/install.h>
37 #include <grub/util/resolve.h>
38 #include <grub/emu/hostfile.h>
39 #include <grub/emu/config.h>
40 #include <grub/emu/hostfile.h>
41
42 #include <stdio.h>
43 #include <unistd.h>
44 #include <string.h>
45 #include <stdlib.h>
46 #include <errno.h>
47
48 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
49
50 char *
51 grub_install_help_filter (int key, const char *text,
52                                  void *input __attribute__ ((unused)))
53 {
54   switch (key)
55     {
56     case GRUB_INSTALL_OPTIONS_INSTALL_THEMES:
57       return xasprintf(text, "starfield");
58     case GRUB_INSTALL_OPTIONS_INSTALL_FONTS:
59       return xasprintf(text, "unicode");
60     case GRUB_INSTALL_OPTIONS_DIRECTORY:
61     case GRUB_INSTALL_OPTIONS_DIRECTORY2:
62       return xasprintf(text, grub_util_get_pkglibdir ());      
63     case GRUB_INSTALL_OPTIONS_LOCALE_DIRECTORY:
64       return xasprintf(text, grub_util_get_localedir ());
65     case GRUB_INSTALL_OPTIONS_THEMES_DIRECTORY:
66       return grub_util_path_concat (2, grub_util_get_pkgdatadir (), "themes");
67     default:
68       return (char *) text;
69     }
70 }
71
72 #pragma GCC diagnostic error "-Wformat-nonliteral"
73
74 static int (*compress_func) (const char *src, const char *dest) = NULL;
75 char *grub_install_copy_buffer;
76 static char *dtb;
77
78 int
79 grub_install_copy_file (const char *src,
80                         const char *dst,
81                         int is_needed)
82 {
83   grub_util_fd_t in, out;  
84   ssize_t r;
85
86   grub_util_info ("copying `%s' -> `%s'", src, dst);
87
88   in = grub_util_fd_open (src, GRUB_UTIL_FD_O_RDONLY);
89   if (!GRUB_UTIL_FD_IS_VALID (in))
90     {
91       if (is_needed)
92         grub_util_error (_("cannot open `%s': %s"), src, grub_util_fd_strerror ());
93       else
94         grub_util_info (_("cannot open `%s': %s"), src, grub_util_fd_strerror ());
95       return 0;
96     }
97   out = grub_util_fd_open (dst, GRUB_UTIL_FD_O_WRONLY
98                            | GRUB_UTIL_FD_O_CREATTRUNC);
99   if (!GRUB_UTIL_FD_IS_VALID (out))
100     {
101       grub_util_error (_("cannot open `%s': %s"), dst,
102                        grub_util_fd_strerror ());
103       grub_util_fd_close (in);
104       return 0;
105     }
106
107   if (!grub_install_copy_buffer)
108     grub_install_copy_buffer = xmalloc (GRUB_INSTALL_COPY_BUFFER_SIZE);
109  
110   while (1)
111     {
112       r = grub_util_fd_read (in, grub_install_copy_buffer, GRUB_INSTALL_COPY_BUFFER_SIZE);
113       if (r <= 0)
114         break;
115       grub_util_fd_write (out, grub_install_copy_buffer, r);
116     }
117   grub_util_fd_sync (out);
118   grub_util_fd_close (in);
119   grub_util_fd_close (out);
120
121   if (r < 0)
122     grub_util_error (_("cannot copy `%s' to `%s': %s"),
123                      src, dst, grub_util_fd_strerror ());
124
125   return 1;
126 }
127
128 static int
129 grub_install_compress_file (const char *in_name,
130                             const char *out_name,
131                             int is_needed)
132 {
133   int ret;
134
135   if (!compress_func)
136     ret = grub_install_copy_file (in_name, out_name, is_needed);
137   else
138     {
139       grub_util_info ("compressing `%s' -> `%s'", in_name, out_name);
140       ret = !compress_func (in_name, out_name);
141       if (!ret && is_needed)
142         grub_util_warn (_("can't compress `%s' to `%s'"), in_name, out_name);
143     }
144
145   if (!ret && is_needed)
146     grub_util_error (_("cannot copy `%s' to `%s': %s"),
147                      in_name, out_name, grub_util_fd_strerror ());
148
149   return ret;
150 }
151
152 static int
153 is_path_separator (char c)
154 {
155 #if defined (__MINGW32__) || defined (__CYGWIN__)
156   if (c == '\\')
157     return 1;
158 #endif
159   if (c == '/')
160     return 1;
161   return 0;
162 }
163
164 void
165 grub_install_mkdir_p (const char *dst)
166 {
167   char *t = xstrdup (dst);
168   char *p;
169   for (p = t; *p; p++)
170     {
171       if (is_path_separator (*p))
172         {
173           char s = *p;
174           *p = '\0';
175           grub_util_mkdir (t);
176           *p = s;
177         }
178     }
179   grub_util_mkdir (t);
180   free (t);
181 }
182
183 static void
184 clean_grub_dir (const char *di)
185 {
186   grub_util_fd_dir_t d;
187   grub_util_fd_dirent_t de;
188
189   d = grub_util_fd_opendir (di);
190   if (!d)
191     grub_util_error (_("cannot open directory `%s': %s"),
192                      di, grub_util_fd_strerror ());
193
194   while ((de = grub_util_fd_readdir (d)))
195     {
196       const char *ext = strrchr (de->d_name, '.');
197       if ((ext && (strcmp (ext, ".mod") == 0
198                    || strcmp (ext, ".lst") == 0
199                    || strcmp (ext, ".img") == 0
200                    || strcmp (ext, ".mo") == 0)
201            && strcmp (de->d_name, "menu.lst") != 0)
202           || strcmp (de->d_name, "efiemu32.o") == 0
203           || strcmp (de->d_name, "efiemu64.o") == 0)
204         {
205           char *x = grub_util_path_concat (2, di, de->d_name);
206           if (grub_util_unlink (x) < 0)
207             grub_util_error (_("cannot delete `%s': %s"), x,
208                              grub_util_fd_strerror ());
209           free (x);
210         }
211     }
212   grub_util_fd_closedir (d);
213 }
214
215 struct install_list
216 {
217   int is_default;
218   char **entries;
219   size_t n_entries;
220   size_t n_alloc;
221 };
222
223 struct install_list install_modules = { 1, 0, 0, 0 };
224 struct install_list modules = { 1, 0, 0, 0 };
225 struct install_list install_locales = { 1, 0, 0, 0 };
226 struct install_list install_fonts = { 1, 0, 0, 0 };
227 struct install_list install_themes = { 1, 0, 0, 0 };
228 char *grub_install_source_directory = NULL;
229 char *grub_install_locale_directory = NULL;
230 char *grub_install_themes_directory = NULL;
231
232 void
233 grub_install_push_module (const char *val)
234 {
235   modules.is_default = 0;
236   if (modules.n_entries + 1 >= modules.n_alloc)
237     {
238       modules.n_alloc <<= 1;
239       if (modules.n_alloc < 16)
240         modules.n_alloc = 16;
241       modules.entries = xrealloc (modules.entries,
242                                   modules.n_alloc * sizeof (*modules.entries));
243     }
244   modules.entries[modules.n_entries++] = xstrdup (val);
245   modules.entries[modules.n_entries] = NULL;
246 }
247
248 void
249 grub_install_pop_module (void)
250 {
251   modules.n_entries--;
252   free (modules.entries[modules.n_entries]);
253   modules.entries[modules.n_entries] = NULL;
254 }
255
256
257 static void
258 handle_install_list (struct install_list *il, const char *val,
259                      int default_all)
260 {
261   const char *ptr;
262   char **ce;
263   il->is_default = 0;
264   free (il->entries);
265   il->entries = NULL;
266   il->n_entries = 0;
267   if (strcmp (val, "all") == 0 && default_all)
268     {
269       il->is_default = 1;
270       return;
271     }
272   ptr = val;
273   while (1)
274     {
275       while (*ptr && grub_isspace (*ptr))
276         ptr++;
277       if (!*ptr)
278         break;
279       while (*ptr && !grub_isspace (*ptr))
280         ptr++;
281       il->n_entries++;
282     }
283   il->n_alloc = il->n_entries + 1;
284   il->entries = xmalloc (il->n_alloc * sizeof (il->entries[0]));
285   ptr = val;
286   for (ce = il->entries; ; ce++)
287     {
288       const char *bptr;
289       while (*ptr && grub_isspace (*ptr))
290         ptr++;
291       if (!*ptr)
292         break;
293       bptr = ptr;
294       while (*ptr && !grub_isspace (*ptr))
295         ptr++;
296       *ce = xmalloc (ptr - bptr + 1);
297       memcpy (*ce, bptr, ptr - bptr);
298       (*ce)[ptr - bptr] = '\0';
299     }
300   *ce = NULL;
301 }
302
303 static char **pubkeys;
304 static size_t npubkeys;
305 static grub_compression_t compression;
306
307 int
308 grub_install_parse (int key, char *arg)
309 {
310   switch (key)
311     {
312     case 'C':
313       if (grub_strcmp (arg, "xz") == 0)
314         {
315 #ifdef HAVE_LIBLZMA
316           compression = GRUB_COMPRESSION_XZ;
317 #else
318           grub_util_error ("%s",
319                            _("grub-mkimage is compiled without XZ support"));
320 #endif
321         }
322       else if (grub_strcmp (arg, "none") == 0)
323         compression = GRUB_COMPRESSION_NONE;
324       else if (grub_strcmp (arg, "auto") == 0)
325         compression = GRUB_COMPRESSION_AUTO;
326       else
327         grub_util_error (_("Unknown compression format %s"), arg);
328       return 1;
329     case 'k':
330       pubkeys = xrealloc (pubkeys,
331                           sizeof (pubkeys[0])
332                           * (npubkeys + 1));
333       pubkeys[npubkeys++] = xstrdup (arg);
334       return 1;
335
336     case GRUB_INSTALL_OPTIONS_VERBOSITY:
337       verbosity++;
338       return 1;
339
340     case GRUB_INSTALL_OPTIONS_DIRECTORY:
341     case GRUB_INSTALL_OPTIONS_DIRECTORY2:
342       free (grub_install_source_directory);
343       grub_install_source_directory = xstrdup (arg);
344       return 1;
345     case GRUB_INSTALL_OPTIONS_LOCALE_DIRECTORY:
346       free (grub_install_locale_directory);
347       grub_install_locale_directory = xstrdup (arg);
348       return 1;
349     case GRUB_INSTALL_OPTIONS_THEMES_DIRECTORY:
350       free (grub_install_themes_directory);
351       grub_install_themes_directory = xstrdup (arg);
352       return 1;
353     case GRUB_INSTALL_OPTIONS_INSTALL_MODULES:
354       handle_install_list (&install_modules, arg, 0);
355       return 1;
356     case GRUB_INSTALL_OPTIONS_MODULES:
357       handle_install_list (&modules, arg, 0);
358       return 1;
359     case GRUB_INSTALL_OPTIONS_INSTALL_LOCALES:
360       handle_install_list (&install_locales, arg, 0);
361       return 1;
362     case GRUB_INSTALL_OPTIONS_INSTALL_THEMES:
363       handle_install_list (&install_themes, arg, 0);
364       return 1;
365     case GRUB_INSTALL_OPTIONS_INSTALL_FONTS:
366       handle_install_list (&install_fonts, arg, 0);
367       return 1;
368     case GRUB_INSTALL_OPTIONS_DTB:
369       if (dtb)
370         free (dtb);
371       dtb = xstrdup (arg);
372       return 1;
373     case GRUB_INSTALL_OPTIONS_INSTALL_COMPRESS:
374       if (strcmp (arg, "no") == 0
375           || strcmp (arg, "none") == 0)
376         {
377           compress_func = NULL;
378           return 1;
379         }
380       if (strcmp (arg, "gz") == 0)
381         {
382           compress_func = grub_install_compress_gzip;
383           return 1;
384         }
385       if (strcmp (arg, "xz") == 0)
386         {
387           compress_func = grub_install_compress_xz;
388           return 1;
389         }
390       if (strcmp (arg, "lzo") == 0)
391         {
392           compress_func = grub_install_compress_lzop;
393           return 1;
394         }
395       grub_util_error (_("Unrecognized compression `%s'"), arg);
396     case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE:
397       return 1;
398     default:
399       return 0;
400     }
401 }
402
403 static int
404 decompressors (void)
405 {
406   if (compress_func == grub_install_compress_gzip)
407     {
408       grub_install_push_module ("gzio");
409       return 1;
410     }
411   if (compress_func == grub_install_compress_xz)
412     {
413       grub_install_push_module ("xzio");
414       grub_install_push_module ("gcry_crc");
415       return 2;
416     }
417   if (compress_func == grub_install_compress_lzop)
418     {
419       grub_install_push_module ("lzopio");
420       grub_install_push_module ("adler32");
421       grub_install_push_module ("gcry_crc");
422       return 3;
423     }
424   return 0;
425 }
426
427 void
428 grub_install_make_image_wrap_file (const char *dir, const char *prefix,
429                                    FILE *fp, const char *outname,
430                                    char *memdisk_path,
431                                    char *config_path,
432                                    const char *mkimage_target, int note)
433 {
434   const struct grub_install_image_target_desc *tgt;
435   const char *const compnames[] = 
436     {
437       [GRUB_COMPRESSION_AUTO] = "auto",
438       [GRUB_COMPRESSION_NONE] = "none",
439       [GRUB_COMPRESSION_XZ] = "xz",
440       [GRUB_COMPRESSION_LZMA] = "lzma",
441     };
442   grub_size_t slen = 1;
443   char *s, *p;
444   char **pk, **md;
445   int dc = decompressors ();
446
447   if (memdisk_path)
448     slen += 20 + grub_strlen (memdisk_path);
449   if (config_path)
450     slen += 20 + grub_strlen (config_path);
451
452   for (pk = pubkeys; pk < pubkeys + npubkeys; pk++)
453     slen += 20 + grub_strlen (*pk);
454
455   for (md = modules.entries; *md; md++)
456     {
457       slen += 10 + grub_strlen (*md);
458     }
459
460   p = s = xmalloc (slen);
461   if (memdisk_path)
462     {
463       p = grub_stpcpy (p, "--memdisk '");
464       p = grub_stpcpy (p, memdisk_path);
465       *p++ = '\'';
466       *p++ = ' ';
467     }
468   if (config_path)
469     {
470       p = grub_stpcpy (p, "--config '");
471       p = grub_stpcpy (p, config_path);
472       *p++ = '\'';
473       *p++ = ' ';
474     }
475   for (pk = pubkeys; pk < pubkeys + npubkeys; pk++)
476     {
477       p = grub_stpcpy (p, "--pubkey '");
478       p = grub_stpcpy (p, *pk);
479       *p++ = '\'';
480       *p++ = ' ';
481     }
482
483   for (md = modules.entries; *md; md++)
484     {
485       *p++ = '\'';
486       p = grub_stpcpy (p, *md);
487       *p++ = '\'';
488       *p++ = ' ';
489     }
490
491   *p = '\0';
492
493   grub_util_info ("grub-mkimage --directory '%s' --prefix '%s'"
494                   " --output '%s' "
495                   " --dtb '%s' "
496                   "--format '%s' --compression '%s' %s %s\n",
497                   dir, prefix,
498                   outname, dtb ? : "", mkimage_target,
499                   compnames[compression], note ? "--note" : "", s);
500   free (s);
501
502   tgt = grub_install_get_image_target (mkimage_target);
503   if (!tgt)
504     grub_util_error (_("unknown target format %s"), mkimage_target);
505
506   grub_install_generate_image (dir, prefix, fp, outname,
507                                modules.entries, memdisk_path,
508                                pubkeys, npubkeys, config_path, tgt,
509                                note, compression, dtb);
510   while (dc--)
511     grub_install_pop_module ();
512 }
513
514 void
515 grub_install_make_image_wrap (const char *dir, const char *prefix,
516                               const char *outname, char *memdisk_path,
517                               char *config_path,
518                               const char *mkimage_target, int note)
519 {
520   FILE *fp;
521
522   fp = grub_util_fopen (outname, "wb");
523   if (! fp)
524     grub_util_error (_("cannot open `%s': %s"), outname,
525                      strerror (errno));
526   grub_install_make_image_wrap_file (dir, prefix, fp, outname,
527                                      memdisk_path, config_path,
528                                      mkimage_target, note);
529   grub_util_file_sync (fp);
530   fclose (fp);
531 }
532
533 static void
534 copy_by_ext (const char *srcd,
535              const char *dstd,
536              const char *extf,
537              int req)
538 {
539   grub_util_fd_dir_t d;
540   grub_util_fd_dirent_t de;
541
542   d = grub_util_fd_opendir (srcd);
543   if (!d && !req)
544     return;
545   if (!d)
546     grub_util_error (_("cannot open directory `%s': %s"),
547                      srcd, grub_util_fd_strerror ());
548
549   while ((de = grub_util_fd_readdir (d)))
550     {
551       const char *ext = strrchr (de->d_name, '.');
552       if (ext && strcmp (ext, extf) == 0)
553         {
554           char *srcf = grub_util_path_concat (2, srcd, de->d_name);
555           char *dstf = grub_util_path_concat (2, dstd, de->d_name);
556           grub_install_compress_file (srcf, dstf, 1);
557           free (srcf);
558           free (dstf);
559         }
560     }
561   grub_util_fd_closedir (d);
562 }
563
564 static void
565 copy_all (const char *srcd,
566              const char *dstd)
567 {
568   grub_util_fd_dir_t d;
569   grub_util_fd_dirent_t de;
570
571   d = grub_util_fd_opendir (srcd);
572   if (!d)
573     grub_util_error (_("cannot open directory `%s': %s"),
574                      srcd, grub_util_fd_strerror ());
575
576   while ((de = grub_util_fd_readdir (d)))
577     {
578       char *srcf;
579       char *dstf;
580       if (strcmp (de->d_name, ".") == 0
581           || strcmp (de->d_name, "..") == 0)
582         continue;
583       srcf = grub_util_path_concat (2, srcd, de->d_name);
584       if (grub_util_is_special_file (srcf)
585           || grub_util_is_directory (srcf))
586         continue;
587       dstf = grub_util_path_concat (2, dstd, de->d_name);
588       grub_install_compress_file (srcf, dstf, 1);
589       free (srcf);
590       free (dstf);
591     }
592   grub_util_fd_closedir (d);
593 }
594
595 static const char *
596 get_localedir (void)
597 {
598   if (grub_install_locale_directory)
599     return grub_install_locale_directory;
600   else
601     return grub_util_get_localedir ();
602 }
603
604 static void
605 copy_locales (const char *dstd)
606 {
607   grub_util_fd_dir_t d;
608   grub_util_fd_dirent_t de;
609   const char *locale_dir = get_localedir ();
610
611   d = grub_util_fd_opendir (locale_dir);
612   if (!d)
613     {
614       grub_util_warn (_("cannot open directory `%s': %s"),
615                       locale_dir, grub_util_fd_strerror ());
616       return;
617     }
618
619   while ((de = grub_util_fd_readdir (d)))
620     {
621       char *srcf;
622       char *dstf;
623       char *ext;
624       if (strcmp (de->d_name, ".") == 0)
625         continue;
626       if (strcmp (de->d_name, "..") == 0)
627         continue;
628       ext = grub_strrchr (de->d_name, '.');
629       if (ext && (grub_strcmp (ext, ".mo") == 0
630                   || grub_strcmp (ext, ".gmo") == 0))
631         {
632           srcf = grub_util_path_concat (2, locale_dir, de->d_name);
633           dstf = grub_util_path_concat (2, dstd, de->d_name);
634           ext = grub_strrchr (dstf, '.');
635           grub_strcpy (ext, ".mo");
636         }
637       else
638         {
639           srcf = grub_util_path_concat_ext (4, locale_dir, de->d_name,
640                                             "LC_MESSAGES", PACKAGE, ".mo");
641           dstf = grub_util_path_concat_ext (2, dstd, de->d_name, ".mo");
642         }
643       grub_install_compress_file (srcf, dstf, 0);
644       free (srcf);
645       free (dstf);
646     }
647   grub_util_fd_closedir (d);
648 }
649
650 static struct
651 {
652   const char *cpu;
653   const char *platform;
654 } platforms[GRUB_INSTALL_PLATFORM_MAX] =
655   {
656     [GRUB_INSTALL_PLATFORM_I386_PC] =          { "i386",    "pc"        },
657     [GRUB_INSTALL_PLATFORM_I386_EFI] =         { "i386",    "efi"       },
658     [GRUB_INSTALL_PLATFORM_I386_QEMU] =        { "i386",    "qemu"      },
659     [GRUB_INSTALL_PLATFORM_I386_COREBOOT] =    { "i386",    "coreboot"  },
660     [GRUB_INSTALL_PLATFORM_I386_MULTIBOOT] =   { "i386",    "multiboot" },
661     [GRUB_INSTALL_PLATFORM_I386_IEEE1275] =    { "i386",    "ieee1275"  },
662     [GRUB_INSTALL_PLATFORM_X86_64_EFI] =       { "x86_64",  "efi"       },
663     [GRUB_INSTALL_PLATFORM_I386_XEN] =         { "i386",    "xen"       },
664     [GRUB_INSTALL_PLATFORM_X86_64_XEN] =       { "x86_64",  "xen"       },
665     [GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON] =  { "mipsel",  "loongson"  },
666     [GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS] = { "mipsel",  "qemu_mips" },
667     [GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS] =   { "mips",    "qemu_mips" },
668     [GRUB_INSTALL_PLATFORM_MIPSEL_ARC] =       { "mipsel",  "arc"       },
669     [GRUB_INSTALL_PLATFORM_MIPS_ARC] =         { "mips",    "arc"       },
670     [GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275] = { "sparc64", "ieee1275"  },
671     [GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275] = { "powerpc", "ieee1275"  },
672     [GRUB_INSTALL_PLATFORM_IA64_EFI] =         { "ia64",    "efi"       },
673     [GRUB_INSTALL_PLATFORM_ARM_EFI] =          { "arm",     "efi"       },
674     [GRUB_INSTALL_PLATFORM_ARM64_EFI] =        { "arm64",   "efi"       },
675     [GRUB_INSTALL_PLATFORM_ARM_UBOOT] =        { "arm",     "uboot"     },
676     [GRUB_INSTALL_PLATFORM_ARM_COREBOOT] =     { "arm",     "coreboot"  },
677   }; 
678
679 char *
680 grub_install_get_platforms_string (void)
681 {
682   char **arr = xmalloc (sizeof (char *) * ARRAY_SIZE (platforms));
683   int platform_strins_len = 0;
684   char *platforms_string;
685   char *ptr;
686   unsigned i;
687   for (i = 0; i < ARRAY_SIZE (platforms); i++)
688     {
689       arr[i] = xasprintf ("%s-%s", platforms[i].cpu,
690                           platforms[i].platform);
691       platform_strins_len += strlen (arr[i]) + 2;
692     }
693   ptr = platforms_string = xmalloc (platform_strins_len);
694   qsort (arr, ARRAY_SIZE (platforms), sizeof (char *), grub_qsort_strcmp);
695   for (i = 0; i < ARRAY_SIZE (platforms); i++)
696     {
697       strcpy (ptr, arr[i]);
698       ptr += strlen (arr[i]);
699       *ptr++ = ',';
700       *ptr++ = ' ';
701       free (arr[i]);
702     }
703   ptr[-2] = 0;
704   free (arr);
705  
706   return platforms_string;
707 }
708
709 char *
710 grub_install_get_platform_name (enum grub_install_plat platid)
711 {
712   return xasprintf ("%s-%s", platforms[platid].cpu,
713                     platforms[platid].platform);
714 }
715
716 const char *
717 grub_install_get_platform_cpu (enum grub_install_plat platid)
718 {
719   return platforms[platid].cpu;
720 }
721
722 const char *
723 grub_install_get_platform_platform (enum grub_install_plat platid)
724 {
725   return platforms[platid].platform;
726 }
727
728
729 void
730 grub_install_copy_files (const char *src,
731                          const char *dst,
732                          enum grub_install_plat platid)
733 {
734   char *dst_platform, *dst_locale, *dst_fonts;
735   const char *pkgdatadir = grub_util_get_pkgdatadir ();
736   char *themes_dir;
737
738   {
739     char *platform;
740     platform = xasprintf ("%s-%s", platforms[platid].cpu,
741                           platforms[platid].platform);
742     dst_platform = grub_util_path_concat (2, dst, platform);
743     free (platform);
744   }
745   dst_locale = grub_util_path_concat (2, dst, "locale");
746   dst_fonts = grub_util_path_concat (2, dst, "fonts");
747   grub_install_mkdir_p (dst_platform);
748   grub_install_mkdir_p (dst_locale);
749   clean_grub_dir (dst);
750   clean_grub_dir (dst_platform);
751   clean_grub_dir (dst_locale);
752
753   if (install_modules.is_default)
754     copy_by_ext (src, dst_platform, ".mod", 1);
755   else
756     {
757       struct grub_util_path_list *path_list, *p;
758
759       path_list = grub_util_resolve_dependencies (src, "moddep.lst",
760                                                   install_modules.entries);
761       for (p = path_list; p; p = p->next)
762         {
763           const char *srcf = p->name;
764           const char *dir;
765           char *dstf;
766
767           dir = grub_strrchr (srcf, '/');
768           if (dir)
769             dir++;
770           else
771             dir = srcf;
772           dstf = grub_util_path_concat (2, dst_platform, dir);
773           grub_install_compress_file (srcf, dstf, 1);
774           free (dstf);
775         }
776
777       grub_util_free_path_list (path_list);
778     }
779
780   const char *pkglib_DATA[] = {"efiemu32.o", "efiemu64.o",
781                                "moddep.lst", "command.lst",
782                                "fs.lst", "partmap.lst",
783                                "parttool.lst",
784                                "video.lst", "crypto.lst",
785                                "terminal.lst", "modinfo.sh" };
786   size_t i;
787
788   for (i = 0; i < ARRAY_SIZE (pkglib_DATA); i++)
789     {
790       char *srcf = grub_util_path_concat (2, src, pkglib_DATA[i]);
791       char *dstf = grub_util_path_concat (2, dst_platform, pkglib_DATA[i]);
792       if (i == 0 || i == 1)
793         grub_install_compress_file (srcf, dstf, 0);
794       else
795         grub_install_compress_file (srcf, dstf, 1);
796       free (srcf);
797       free (dstf);
798     }
799
800   if (install_locales.is_default)
801     {
802       char *srcd = grub_util_path_concat (2, src, "po");
803       copy_by_ext (srcd, dst_locale, ".mo", 0);
804       copy_locales (dst_locale);
805       free (srcd);
806     }
807   else
808     {
809       const char *locale_dir = get_localedir ();
810
811       for (i = 0; i < install_locales.n_entries; i++)
812         {
813           char *srcf = grub_util_path_concat_ext (3, src,
814                                                 "po",
815                                                 install_locales.entries[i],
816                                                 ".mo");
817           char *dstf = grub_util_path_concat_ext (2, dst_locale,
818                                                 install_locales.entries[i],
819                                                 ".mo");
820           if (grub_install_compress_file (srcf, dstf, 0))
821             {
822               free (srcf);
823               free (dstf);
824               continue;
825             }
826           free (srcf);
827           srcf = grub_util_path_concat_ext (4,
828                                                  locale_dir,
829                                                  install_locales.entries[i],
830                                                  "LC_MESSAGES",
831                                                  PACKAGE,
832                                                  ".mo");
833           if (grub_install_compress_file (srcf, dstf, 0))
834             {
835               free (srcf);
836               free (dstf);
837               continue;
838             }
839           grub_util_error (_("cannot find locale `%s'"),
840                            install_locales.entries[i]);
841         }
842     }
843
844   if (install_themes.is_default)
845     {
846       install_themes.is_default = 0;
847       install_themes.n_entries = 1;
848       install_themes.entries = xmalloc (2 * sizeof (install_themes.entries[0]));
849       install_themes.entries[0] = xstrdup ("starfield");
850       install_themes.entries[1] = NULL;
851     }
852
853   if (grub_install_themes_directory)
854     themes_dir = xstrdup (grub_install_themes_directory);
855   else
856     themes_dir = grub_util_path_concat (2, grub_util_get_pkgdatadir (),
857                                         "themes");
858
859   for (i = 0; i < install_themes.n_entries; i++)
860     {
861       char *srcf = grub_util_path_concat (3, themes_dir,
862                                         install_themes.entries[i],
863                                         "theme.txt");
864       if (grub_util_is_regular (srcf))
865         {
866           char *srcd = grub_util_path_concat (2, themes_dir,
867                                             install_themes.entries[i]);
868           char *dstd = grub_util_path_concat (3, dst, "themes",
869                                             install_themes.entries[i]);
870           grub_install_mkdir_p (dstd);
871           copy_all (srcd, dstd);
872           free (srcd);
873           free (dstd);
874         }
875       free (srcf);
876     }
877
878   free (themes_dir);
879
880   if (install_fonts.is_default)
881     {
882       install_fonts.is_default = 0;
883       install_fonts.n_entries = 1;
884       install_fonts.entries = xmalloc (2 * sizeof (install_fonts.entries[0]));
885       install_fonts.entries[0] = xstrdup ("unicode");
886       install_fonts.entries[1] = NULL;
887     }
888
889   grub_install_mkdir_p (dst_fonts);
890
891   for (i = 0; i < install_fonts.n_entries; i++)
892     {
893       char *srcf = grub_util_path_concat_ext (2, pkgdatadir,
894                                                    install_fonts.entries[i],
895                                                    ".pf2");
896       char *dstf = grub_util_path_concat_ext (2, dst_fonts,
897                                                    install_fonts.entries[i],
898                                                    ".pf2");
899
900       grub_install_compress_file (srcf, dstf, 0);
901       free (srcf);
902       free (dstf);
903     }
904
905   free (dst_platform);
906   free (dst_locale);
907   free (dst_fonts);
908 }
909
910 enum grub_install_plat
911 grub_install_get_target (const char *src)
912 {
913   char *fn;
914   grub_util_fd_t f;
915   char buf[8192];
916   ssize_t r;
917   char *c, *pl, *p;
918   size_t i;
919   fn = grub_util_path_concat (2, src, "modinfo.sh");
920   f = grub_util_fd_open (fn, GRUB_UTIL_FD_O_RDONLY);
921   if (!GRUB_UTIL_FD_IS_VALID (f))
922     grub_util_error (_("%s doesn't exist. Please specify --target or --directory"), 
923                      fn);
924   r = grub_util_fd_read (f, buf, sizeof (buf) - 1);
925   if (r < 0)
926     grub_util_error (_("cannot read `%s': %s"), fn, strerror (errno));
927   grub_util_fd_close (f);
928   buf[r] = '\0';
929   c = strstr (buf, "grub_modinfo_target_cpu=");
930   if (!c || (c != buf && !grub_isspace (*(c-1))))
931     grub_util_error (_("invalid modinfo file `%s'"), fn);
932   pl = strstr (buf, "grub_modinfo_platform=");
933   if (!pl || (pl != buf && !grub_isspace (*(pl-1))))
934     grub_util_error (_("invalid modinfo file `%s'"), fn);
935   c += sizeof ("grub_modinfo_target_cpu=") - 1;
936   pl += sizeof ("grub_modinfo_platform=") - 1;
937   for (p = c; *p && !grub_isspace (*p); p++);
938   *p = '\0';
939   for (p = pl; *p && !grub_isspace (*p); p++);
940   *p = '\0';
941
942   for (i = 0; i < ARRAY_SIZE (platforms); i++)
943     if (strcmp (platforms[i].cpu, c) == 0
944         && strcmp (platforms[i].platform, pl) == 0)
945       {
946         free (fn);
947         return i;
948       }
949   grub_util_error (_("Unknown platform `%s-%s'"), c, pl);
950 }
951
952
953 void
954 grub_util_unlink_recursive (const char *name)
955 {
956   grub_util_fd_dir_t d;
957   grub_util_fd_dirent_t de;
958
959   d = grub_util_fd_opendir (name);
960
961   while ((de = grub_util_fd_readdir (d)))
962     {
963       char *fp;
964       if (strcmp (de->d_name, ".") == 0)
965         continue;
966       if (strcmp (de->d_name, "..") == 0)
967         continue;
968       fp = grub_util_path_concat (2, name, de->d_name);
969       if (grub_util_is_special_file (fp))
970         {
971           free (fp);
972           continue;
973         }
974       if (grub_util_is_regular (fp))
975         grub_util_unlink (fp);
976       else if (grub_util_is_directory (fp))
977         grub_util_unlink_recursive (fp);
978       free (fp);
979     }
980   grub_util_rmdir (name);
981   grub_util_fd_closedir (d);
982 }