a3fcfcacaa814d3ab62104f0dd406ef0c2163613
[grub.git] / grub-core / osdep / unix / platform.c
1 /*
2  *  GRUB  --  GRand Unified Bootloader
3  *  Copyright (C) 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/emu/hostdisk.h>
23 #include <grub/util/misc.h>
24 #include <grub/misc.h>
25 #include <grub/i18n.h>
26 #include <grub/emu/exec.h>
27 #include <sys/types.h>
28 #include <dirent.h>
29 #include <string.h>
30 #include <errno.h>
31
32 static char *
33 get_ofpathname (const char *dev)
34 {
35   size_t alloced = 4096;
36   char *ret = xmalloc (alloced);
37   size_t offset = 0;
38   int fd;
39   pid_t pid;
40
41   pid = grub_util_exec_pipe ((const char * []){ "ofpathname", dev, NULL }, &fd);
42   if (!pid)
43     goto fail;
44
45   FILE *fp = fdopen (fd, "r");
46   if (!fp)
47     goto fail;
48
49   while (!feof (fp))
50     {
51       size_t r;
52       if (alloced == offset)
53        {
54          alloced *= 2;
55          ret = xrealloc (ret, alloced);
56        }
57       r = fread (ret + offset, 1, alloced - offset, fp);
58       offset += r;
59     }
60
61   if (offset > 0 && ret[offset - 1] == '\n')
62     offset--;
63   if (offset > 0 && ret[offset - 1] == '\r')
64     offset--;
65   if (alloced == offset)
66     {
67       alloced++;
68       ret = xrealloc (ret, alloced);
69     }
70   ret[offset] = '\0';
71
72   fclose (fp);
73
74   return ret;
75
76  fail:
77   grub_util_error (_("couldn't find IEEE1275 device path for %s.\nYou will have to set `boot-device' variable manually"),
78                    dev);
79 }
80
81 static void
82 grub_install_remove_efi_entries_by_distributor (const char *efi_distributor)
83 {
84   int fd;
85   pid_t pid = grub_util_exec_pipe ((const char * []){ "efibootmgr", NULL }, &fd);
86   char *line = NULL;
87   size_t len = 0;
88
89   if (!pid)
90     {
91       grub_util_warn (_("Unable to open stream from %s: %s"),
92                       "efibootmgr", strerror (errno));
93       return;
94     }
95
96   FILE *fp = fdopen (fd, "r");
97   if (!fp)
98     {
99       grub_util_warn (_("Unable to open stream from %s: %s"),
100                       "efibootmgr", strerror (errno));
101       return;
102     }
103
104   line = xmalloc (80);
105   len = 80;
106   while (1)
107     {
108       int ret;
109       char *bootnum;
110       ret = getline (&line, &len, fp);
111       if (ret == -1)
112         break;
113       if (grub_memcmp (line, "Boot", sizeof ("Boot") - 1) != 0
114           || line[sizeof ("Boot") - 1] < '0'
115           || line[sizeof ("Boot") - 1] > '9')
116         continue;
117       if (!strcasestr (line, efi_distributor))
118         continue;
119       bootnum = line + sizeof ("Boot") - 1;
120       bootnum[4] = '\0';
121       if (!verbosity)
122         grub_util_exec ((const char * []){ "efibootmgr", "-q",
123               "-b", bootnum,  "-B", NULL });
124       else
125         grub_util_exec ((const char * []){ "efibootmgr",
126               "-b", bootnum, "-B", NULL });
127     }
128
129   free (line);
130 }
131
132 void
133 grub_install_register_efi (grub_device_t efidir_grub_dev,
134                            const char *efifile_path,
135                            const char *efi_distributor)
136 {
137   const char * efidir_disk;
138   int efidir_part;
139   efidir_disk = grub_util_biosdisk_get_osdev (efidir_grub_dev->disk);
140   efidir_part = efidir_grub_dev->disk->partition ? efidir_grub_dev->disk->partition->number + 1 : 1;
141
142   if (grub_util_exec_redirect_null ((const char * []){ "efibootmgr", "--version", NULL }))
143     {
144       /* TRANSLATORS: This message is shown when required executable `%s'
145          isn't found.  */
146       grub_util_error (_("%s: not found"), "efibootmgr");
147     }
148
149   /* On Linux, we need the efivars kernel modules.  */
150 #ifdef __linux__
151   grub_util_exec ((const char * []){ "modprobe", "-q", "efivars", NULL });
152 #endif
153   /* Delete old entries from the same distributor.  */
154   grub_install_remove_efi_entries_by_distributor (efi_distributor);
155
156   char *efidir_part_str = xasprintf ("%d", efidir_part);
157
158   if (!verbosity)
159     grub_util_exec ((const char * []){ "efibootmgr", "-q",
160           "-c", "-d", efidir_disk,
161           "-p", efidir_part_str, "-w",
162           "-L", efi_distributor, "-l", 
163           efifile_path, NULL });
164   else
165     grub_util_exec ((const char * []){ "efibootmgr",
166           "-c", "-d", efidir_disk,
167           "-p", efidir_part_str, "-w",
168           "-L", efi_distributor, "-l", 
169           efifile_path, NULL });
170   free (efidir_part_str);
171 }
172
173 void
174 grub_install_register_ieee1275 (int is_prep, const char *install_device,
175                                 int partno, const char *relpath)
176 {
177   char *boot_device;
178
179   if (grub_util_exec_redirect_null ((const char * []){ "ofpathname", "--version", NULL }))
180     {
181       /* TRANSLATORS: This message is shown when required executable `%s'
182          isn't found.  */
183       grub_util_error (_("%s: not found"), "ofpathname");
184     }
185
186   /* Get the Open Firmware device tree path translation.  */
187   if (!is_prep)
188     {
189       char *ptr;
190       char *ofpath;
191       const char *iptr;
192
193       ofpath = get_ofpathname (install_device);
194       boot_device = xmalloc (strlen (ofpath) + 1
195                              + sizeof ("XXXXXXXXXXXXXXXXXXXX")
196                              + 1 + strlen (relpath) + 1);
197       ptr = grub_stpcpy (boot_device, ofpath);
198       *ptr++ = ':';
199       grub_snprintf (ptr, sizeof ("XXXXXXXXXXXXXXXXXXXX"), "%d",
200                      partno);
201       ptr += strlen (ptr);
202       *ptr++ = ',';
203       for (iptr = relpath; *iptr; iptr++, ptr++)
204         {
205           if (*iptr == '/')
206             *ptr = '\\';
207           else
208             *ptr = *iptr;
209         }
210       *ptr = '\0';
211     }
212   else
213     boot_device = get_ofpathname (install_device);
214
215   if (grub_util_exec ((const char * []){ "nvsetenv", "boot-device",
216           boot_device, NULL }))
217     {
218       char *cmd = xasprintf ("setenv boot-device %s", boot_device);
219       grub_util_error (_("`nvsetenv' failed. \nYou will have to set `boot-device' variable manually.  At the IEEE1275 prompt, type:\n  %s\n"),
220                        cmd);
221       free (cmd);
222     }
223
224   free (boot_device);
225 }
226
227 void
228 grub_install_sgi_setup (const char *install_device,
229                         const char *imgfile, const char *destname)
230 {
231   grub_util_exec ((const char * []){ "dvhtool", "-d",
232         install_device, "--unix-to-vh", 
233         imgfile, destname, NULL });
234   grub_util_warn ("%s", _("You will have to set `SystemPartition' and `OSLoader' manually."));
235 }