source: mainline/uspace/app/sysinst/sysinst.c@ d5c1051

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since d5c1051 was d5c1051, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

"Obviously harmless" error handling tweaks.

  • Property mode set to 100644
File size: 9.9 KB
Line 
1/*
2 * Copyright (c) 2014 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup sysinst
30 * @{
31 */
32/** @file System installer.
33 *
34 * Install the operating system onto a disk device. Note that this only works
35 * on ia32/amd64 with Grub platform 'pc'.
36 */
37
38#include <block.h>
39#include <byteorder.h>
40#include <cap.h>
41#include <errno.h>
42#include <fdisk.h>
43#include <loc.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <str_error.h>
47#include <task.h>
48#include <vfs/vfs.h>
49
50#include "futil.h"
51#include "grub.h"
52
53/** Device to install to
54 *
55 * Note that you cannot simply change this, because the installation
56 * device is hardcoded in core.img. If you wanted to install to another
57 * device, you must build your own core.img (e.g. using tools/grub/mkimage.sh
58 * and modifying tools/grub/load.cfg, supplying the device to boot from
59 * in Grub notation).
60 */
61#define DEFAULT_DEV "devices/\\hw\\pci0\\00:01.0\\ata-c1\\d0"
62//#define DEFAULT_DEV "devices/\\hw\\pci0\\00:01.2\\uhci_rh\\usb01_a1\\mass-storage0\\l0"
63
64/** Filysystem type. Cannot be changed without building a custom core.img */
65#define FS_TYPE "mfs"
66
67#define FS_SRV "/srv/mfs"
68#define MOUNT_POINT "/inst"
69
70/** Device containing HelenOS live CD */
71#define CD_DEV "devices/\\hw\\pci0\\00:01.0\\ata-c2\\d0"
72
73#define CD_FS_TYPE "cdfs"
74#define CD_FS_SRV "/srv/cdfs"
75#define CD_MOUNT_POINT "/cdrom"
76
77#define BOOT_FILES_SRC "/cdrom"
78#define BOOT_BLOCK_IDX 0 /* MBR */
79
80/** Label the destination device.
81 *
82 * @param dev Disk device to label
83 * @param pdev Place to store partition device name
84 *
85 * @return EOK on success or error code
86 */
87static int sysinst_label_dev(const char *dev, char **pdev)
88{
89 fdisk_t *fdisk;
90 fdisk_dev_t *fdev;
91 fdisk_part_t *part;
92 fdisk_part_spec_t pspec;
93 cap_spec_t cap;
94 service_id_t sid;
95 int rc;
96
97 printf("sysinst_label_dev(): get service ID '%s'\n", dev);
98 rc = loc_service_get_id(dev, &sid, 0);
99 if (rc != EOK)
100 return rc;
101
102 printf("sysinst_label_dev(): open device\n");
103
104 rc = fdisk_create(&fdisk);
105 if (rc != EOK) {
106 printf("Error initializing fdisk.\n");
107 return rc;
108 }
109
110 rc = fdisk_dev_open(fdisk, sid, &fdev);
111 if (rc != EOK) {
112 printf("Error opening device.\n");
113 return rc;
114 }
115
116 printf("sysinst_label_dev(): create label\n");
117
118 rc = fdisk_label_create(fdev, lt_mbr);
119 if (rc != EOK) {
120 printf("Error creating label: %s.\n", str_error(rc));
121 return rc;
122 }
123
124 printf("sysinst_label_dev(): create partition\n");
125
126 rc = fdisk_part_get_max_avail(fdev, spc_pri, &cap);
127 if (rc != EOK) {
128 printf("Error getting available capacity: %s.\n", str_error(rc));
129 return rc;
130 }
131
132 fdisk_pspec_init(&pspec);
133 pspec.capacity = cap;
134 pspec.pkind = lpk_primary;
135 pspec.fstype = fs_minix;
136
137 rc = fdisk_part_create(fdev, &pspec, &part);
138 if (rc != EOK) {
139 printf("Error creating partition.\n");
140 return rc;
141 }
142
143 /* XXX libfdisk should give us the service name */
144 if (asprintf(pdev, "%sp1", dev) < 0)
145 return ENOMEM;
146
147 printf("sysinst_label_dev(): OK\n");
148 return EOK;
149}
150
151/** Mount target file system.
152 *
153 * @param dev Partition device
154 * @return EOK on success or error code
155 */
156static int sysinst_fs_mount(const char *dev)
157{
158 task_wait_t twait;
159 task_exit_t texit;
160 int rc;
161 int trc;
162
163 printf("sysinst_fs_mount(): start filesystem server\n");
164 rc = task_spawnl(NULL, &twait, FS_SRV, FS_SRV, NULL);
165 if (rc != EOK)
166 return rc;
167
168 printf("sysinst_fs_mount(): wait for filesystem server\n");
169 rc = task_wait(&twait, &texit, &trc);
170 if (rc != EOK)
171 return rc;
172
173 printf("sysinst_fs_mount(): verify filesystem server result\n");
174 if (texit != TASK_EXIT_NORMAL || trc != 0) {
175 printf("sysinst_fs_mount(): not successful, but could be already loaded.\n");
176 }
177
178 rc = vfs_link_path(MOUNT_POINT, KIND_DIRECTORY, NULL);
179 if (rc != EOK)
180 return rc;
181
182 printf("sysinst_fs_mount(): mount filesystem\n");
183 rc = vfs_mount_path(MOUNT_POINT, FS_TYPE, dev, "", 0, 0);
184 if (rc != EOK)
185 return rc;
186
187 printf("sysinst_fs_mount(): OK\n");
188 return EOK;
189}
190
191/** Copy boot files.
192 *
193 * @return EOK on success or error code
194 */
195static int sysinst_copy_boot_files(void)
196{
197 task_wait_t twait;
198 task_exit_t texit;
199 int rc;
200 int trc;
201
202 printf("sysinst_copy_boot_files(): start filesystem server\n");
203 rc = task_spawnl(NULL, &twait, CD_FS_SRV, CD_FS_SRV, NULL);
204 if (rc != EOK)
205 return rc;
206
207 printf("sysinst_copy_boot_files(): wait for filesystem server\n");
208 rc = task_wait(&twait, &texit, &trc);
209 if (rc != EOK)
210 return rc;
211
212 printf("sysinst_copy_boot_files(): verify filesystem server result\n");
213 if (texit != TASK_EXIT_NORMAL || trc != 0) {
214 printf("sysinst_fs_mount(): not successful, but could be already loaded.\n");
215 }
216
217 printf("sysinst_copy_boot_files(): create CD mount point\n");
218 rc = vfs_link_path(CD_MOUNT_POINT, KIND_DIRECTORY, NULL);
219 if (rc != EOK)
220 return rc;
221
222 printf("sysinst_copy_boot_files(): mount CD filesystem\n");
223 rc = vfs_mount_path(CD_MOUNT_POINT, CD_FS_TYPE, CD_DEV, "", 0, 0);
224 if (rc != EOK)
225 return rc;
226
227 printf("sysinst_copy_boot_files(): copy bootloader files\n");
228 rc = futil_rcopy_contents(BOOT_FILES_SRC, MOUNT_POINT);
229 if (rc != EOK)
230 return rc;
231
232 printf("sysinst_copy_boot_files(): unmount %s\n", MOUNT_POINT);
233 rc = vfs_unmount_path(MOUNT_POINT);
234 if (rc != EOK)
235 return rc;
236
237 printf("sysinst_copy_boot_files(): OK\n");
238 return EOK;
239}
240
241/** Write unaligned 64-bit little-endian number.
242 *
243 * @param a Destination buffer
244 * @param data Number
245 */
246static void set_unaligned_u64le(uint8_t *a, uint64_t data)
247{
248 int i;
249
250 for (i = 0; i < 8; i++) {
251 a[i] = (data >> (i * 8)) & 0xff;
252 }
253}
254
255/** Copy boot blocks.
256 *
257 * Install Grub's boot blocks.
258 *
259 * @param devp Disk device
260 * @return EOK on success or error code
261 */
262static int sysinst_copy_boot_blocks(const char *devp)
263{
264 void *boot_img;
265 size_t boot_img_size;
266 void *core_img;
267 size_t core_img_size;
268 service_id_t sid;
269 size_t bsize;
270 uint8_t bbuf[512];
271 aoff64_t core_start;
272 aoff64_t core_blocks;
273 grub_boot_blocklist_t *first_bl, *bl;
274 int rc;
275
276 printf("sysinst_copy_boot_blocks: Read boot block image.\n");
277 rc = futil_get_file(BOOT_FILES_SRC "/boot/grub/i386-pc/boot.img",
278 &boot_img, &boot_img_size);
279 if (rc != EOK || boot_img_size != 512)
280 return EIO;
281
282 printf("sysinst_copy_boot_blocks: Read GRUB core image.\n");
283 rc = futil_get_file(BOOT_FILES_SRC "/boot/grub/i386-pc/core.img",
284 &core_img, &core_img_size);
285 if (rc != EOK)
286 return EIO;
287
288 printf("sysinst_copy_boot_blocks: get service ID.\n");
289 rc = loc_service_get_id(devp, &sid, 0);
290 if (rc != EOK)
291 return rc;
292
293 printf("sysinst_copy_boot_blocks: block_init.\n");
294 rc = block_init(sid, 512);
295 if (rc != EOK)
296 return rc;
297
298 printf("sysinst_copy_boot_blocks: get block size\n");
299 rc = block_get_bsize(sid, &bsize);
300 if (rc != EOK)
301 return rc;
302
303 if (bsize != 512) {
304 printf("Device block size != 512.\n");
305 return EIO;
306 }
307
308 printf("sysinst_copy_boot_blocks: read boot block\n");
309 rc = block_read_direct(sid, BOOT_BLOCK_IDX, 1, bbuf);
310 if (rc != EOK)
311 return EIO;
312
313 core_start = 16;
314 core_blocks = (core_img_size + 511) / 512;
315
316 /* Clean blocklists */
317 first_bl = core_img + 512 - sizeof(*first_bl);
318 bl = first_bl;
319 while (bl->len != 0) {
320 memset(bl, 0, sizeof(*bl));
321 --bl;
322 if ((void *)bl < core_img) {
323 printf("No block terminator in core image.\n");
324 return EIO;
325 }
326 }
327
328 first_bl->start = host2uint64_t_le(core_start + 1);
329 first_bl->len = host2uint16_t_le(core_blocks - 1);
330 first_bl->segment = grub_boot_i386_pc_kernel_seg + (512 >> 4);
331
332 /* Write boot code into boot block */
333 memcpy(bbuf, boot_img, 440); /* XXX 440 = sizeof(br_block_t.code_area) */
334 bbuf[grub_boot_machine_boot_drive] = 0xff;
335 set_unaligned_u64le(bbuf + grub_boot_machine_kernel_sector, core_start);
336
337 printf("sysinst_copy_boot_blocks: write boot block\n");
338 rc = block_write_direct(sid, BOOT_BLOCK_IDX, 1, bbuf);
339 if (rc != EOK)
340 return EIO;
341
342 printf("sysinst_copy_boot_blocks: write boot block\n");
343 /* XXX Must pad last block with zeros */
344 rc = block_write_direct(sid, core_start, core_blocks, core_img);
345 if (rc != EOK)
346 return EIO;
347
348 printf("sysinst_copy_boot_blocks: OK.\n");
349 return EOK;
350}
351
352/** Install system to a device.
353 *
354 * @param dev Device to install to.
355 * @return EOK on success or error code
356 */
357static int sysinst_install(const char *dev)
358{
359 int rc;
360 char *pdev;
361
362 rc = sysinst_label_dev(dev, &pdev);
363 if (rc != EOK)
364 return rc;
365
366 printf("Partition '%s'. Mount it.\n", pdev);
367 rc = sysinst_fs_mount(pdev);
368 if (rc != EOK)
369 return rc;
370
371 free(pdev);
372
373 printf("FS created and mounted. Copying boot files.\n");
374 rc = sysinst_copy_boot_files();
375 if (rc != EOK)
376 return rc;
377
378 printf("Boot files done. Installing boot blocks.\n");
379 rc = sysinst_copy_boot_blocks(dev);
380 if (rc != EOK)
381 return rc;
382
383 return EOK;
384}
385
386int main(int argc, char *argv[])
387{
388 const char *dev = DEFAULT_DEV;
389 return sysinst_install(dev);
390}
391
392/** @}
393 */
Note: See TracBrowser for help on using the repository browser.