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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ef0a3375 was 09d1b6fa, checked in by Maurizio Lombardi <mlombard@…>, 7 years ago

sysinst: fix the default dev path

\hw\pci0 has been replaced by \w\sys

This fixes commit b25970fdaa53055fe44afdf414204a77d77efbf1

  • Property mode set to 100644
File size: 11.6 KB
RevLine 
[3a34852]1/*
[e2625b1a]2 * Copyright (c) 2018 Jiri Svoboda
[3a34852]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>
[6c4eedf]40#include <cap.h>
[3a34852]41#include <errno.h>
42#include <fdisk.h>
43#include <loc.h>
44#include <stdio.h>
45#include <stdlib.h>
[3cdd876]46#include <str.h>
[c1694b6b]47#include <str_error.h>
[3a34852]48#include <vfs/vfs.h>
[3cdd876]49#include <vol.h>
[3a34852]50
51#include "futil.h"
52#include "grub.h"
[df8eaba]53#include "rdimg.h"
54#include "volume.h"
[3a34852]55
56/** Device to install to
57 *
58 * Note that you cannot simply change this, because the installation
59 * device is hardcoded in core.img. If you wanted to install to another
60 * device, you must build your own core.img (e.g. using tools/grub/mkimage.sh
61 * and modifying tools/grub/load.cfg, supplying the device to boot from
62 * in Grub notation).
63 */
[09d1b6fa]64#define DEFAULT_DEV "devices/\\hw\\sys\\00:01.0\\ata-c1\\d0"
[3a34852]65//#define DEFAULT_DEV "devices/\\hw\\pci0\\00:01.2\\uhci_rh\\usb01_a1\\mass-storage0\\l0"
[1bb43d5]66/** Volume label for the new file system */
67#define INST_VOL_LABEL "HelenOS"
[df8eaba]68/** Mount point of system partition when running installed system */
69#define INST_VOL_MP "/w"
[3a34852]70
71#define MOUNT_POINT "/inst"
72
[5f36841]73/** HelenOS live CD volume label */
74#define CD_VOL_LABEL "HelenOS-CD"
[e2625b1a]75/** XXX Should get this from the volume server */
[5f36841]76#define CD_MOUNT_POINT "/vol/" CD_VOL_LABEL
[3a34852]77
[5f36841]78#define BOOT_FILES_SRC CD_MOUNT_POINT
[3a34852]79#define BOOT_BLOCK_IDX 0 /* MBR */
80
[63c1dd5]81static const char *sys_dirs[] = {
82 "/cfg",
83 "/data"
84};
85
[3a34852]86/** Label the destination device.
87 *
88 * @param dev Disk device to label
[3cdd876]89 * @param psvc_id Place to store service ID of the created partition
[3a34852]90 *
[cde999a]91 * @return EOK on success or an error code
[3a34852]92 */
[3cdd876]93static errno_t sysinst_label_dev(const char *dev, service_id_t *psvc_id)
[3a34852]94{
95 fdisk_t *fdisk;
96 fdisk_dev_t *fdev;
97 fdisk_part_t *part;
98 fdisk_part_spec_t pspec;
[3cdd876]99 fdisk_part_info_t pinfo;
[6c4eedf]100 cap_spec_t cap;
[3a34852]101 service_id_t sid;
[b7fd2a0]102 errno_t rc;
[3a34852]103
104 printf("sysinst_label_dev(): get service ID '%s'\n", dev);
105 rc = loc_service_get_id(dev, &sid, 0);
106 if (rc != EOK)
107 return rc;
108
109 printf("sysinst_label_dev(): open device\n");
110
111 rc = fdisk_create(&fdisk);
112 if (rc != EOK) {
113 printf("Error initializing fdisk.\n");
114 return rc;
115 }
116
117 rc = fdisk_dev_open(fdisk, sid, &fdev);
118 if (rc != EOK) {
119 printf("Error opening device.\n");
120 return rc;
121 }
122
[3cdd876]123 printf("sysinst_label_dev(): create mount directory\n");
124
125 rc = vfs_link_path(MOUNT_POINT, KIND_DIRECTORY, NULL);
126 if (rc != EOK)
127 return rc;
128
[3a34852]129 printf("sysinst_label_dev(): create label\n");
130
131 rc = fdisk_label_create(fdev, lt_mbr);
132 if (rc != EOK) {
[c1694b6b]133 printf("Error creating label: %s.\n", str_error(rc));
[3a34852]134 return rc;
135 }
136
137 printf("sysinst_label_dev(): create partition\n");
138
139 rc = fdisk_part_get_max_avail(fdev, spc_pri, &cap);
140 if (rc != EOK) {
[c1694b6b]141 printf("Error getting available capacity: %s.\n", str_error(rc));
[3a34852]142 return rc;
143 }
144
145 fdisk_pspec_init(&pspec);
146 pspec.capacity = cap;
147 pspec.pkind = lpk_primary;
[1bb43d5]148 pspec.fstype = fs_ext4; /* Cannot be changed without modifying core.img */
[3cdd876]149 pspec.mountp = MOUNT_POINT;
[1bb43d5]150 pspec.label = INST_VOL_LABEL;
[3a34852]151
152 rc = fdisk_part_create(fdev, &pspec, &part);
153 if (rc != EOK) {
154 printf("Error creating partition.\n");
155 return rc;
156 }
157
[3cdd876]158 rc = fdisk_part_get_info(part, &pinfo);
159 if (rc != EOK) {
160 printf("Error getting partition information.\n");
[3a34852]161 return rc;
[89e2aac]162 }
[3a34852]163
[3cdd876]164 printf("sysinst_label_dev(): OK\n");
165 *psvc_id = pinfo.svc_id;
[3a34852]166 return EOK;
167}
168
[63c1dd5]169/** Set up system volume structure.
170 *
171 * @return EOK on success or an error code
172 */
173static errno_t sysinst_setup_sysvol(void)
174{
175 errno_t rc;
176 char *path = NULL;
177 const char **cp;
178 int rv;
179
180 cp = sys_dirs;
181 while (*cp != NULL) {
182 rv = asprintf(&path, "%s%s", MOUNT_POINT, *cp);
183 if (rv < 0) {
184 rc = ENOMEM;
185 goto error;
186 }
187
188 rc = vfs_link_path(path, KIND_DIRECTORY, NULL);
189 if (rc != EOK) {
190 printf("Error creating directory '%s'.\n", path);
191 goto error;
192 }
193
194 free(path);
195 path = NULL;
196 ++cp;
197 }
198
199 free(path);
200 path = NULL;
201
202 return EOK;
203error:
204 if (path != NULL)
205 free(path);
206 return rc;
207}
208
[3a34852]209/** Copy boot files.
210 *
[cde999a]211 * @return EOK on success or an error code
[3a34852]212 */
[b7fd2a0]213static errno_t sysinst_copy_boot_files(void)
[3a34852]214{
[b7fd2a0]215 errno_t rc;
[3a34852]216
217 printf("sysinst_copy_boot_files(): copy bootloader files\n");
218 rc = futil_rcopy_contents(BOOT_FILES_SRC, MOUNT_POINT);
219 if (rc != EOK)
220 return rc;
221
222 printf("sysinst_copy_boot_files(): OK\n");
223 return EOK;
224}
225
[df8eaba]226/** Set up configuration in the initial RAM disk.
227 *
228 * @return EOK on success or an error code
229 */
230static errno_t sysinst_customize_initrd(void)
231{
232 errno_t rc;
233 rd_img_t *rd = NULL;
234 char *rdpath = NULL;
235 char *path = NULL;
236 vol_volumes_t *volumes = NULL;
237 vol_volume_t *volume = NULL;
238 int rv;
239
240 rc = rd_img_open(MOUNT_POINT "/boot/initrd.img", &rdpath, &rd);
241 if (rc != EOK) {
242 printf("Error opening initial RAM disk image.\n");
243 goto error;
244 }
245
246 rv = asprintf(&path, "%s%s", rdpath, "/cfg/volsrv.sif");
247 if (rv < 0) {
248 rc = ENOMEM;
249 goto error;
250 }
251
252 printf("Configuring volume server.\n");
253 rc = vol_volumes_create(path, &volumes);
254 if (rc != EOK) {
255 printf("Error creating volume server configuration.\n");
256 rc = EIO;
257 goto error;
258 }
259
260 printf("Configuring volume server: look up volume\n");
261 rc = vol_volume_lookup_ref(volumes, INST_VOL_LABEL, &volume);
262 if (rc != EOK) {
263 printf("Error creating volume server configuration.\n");
264 rc = EIO;
265 goto error;
266 }
267
268 printf("Configuring volume server: set mount point\n");
269 rc = vol_volume_set_mountp(volume, INST_VOL_MP);
270 if (rc != EOK) {
271 printf("Error creating system partition configuration.\n");
272 rc = EIO;
273 goto error;
274 }
275
276 printf("Configuring volume server: delete reference\n");
277 vol_volume_del_ref(volume);
278 volume = NULL;
279 printf("Configuring volume server: destroy volumes object\n");
280 vol_volumes_destroy(volumes);
281 volumes = NULL;
282
283 rc = rd_img_close(rd);
284 if (rc != EOK) {
285 printf("Error closing initial RAM disk image.\n");
286 rc = EIO;
287 goto error;
288 }
289
290 free(rdpath);
291 rdpath = NULL;
292 free(path);
293 path = NULL;
294
295 return EOK;
296error:
297 if (volume != NULL)
298 vol_volume_del_ref(volume);
299 if (volumes != NULL)
300 vol_volumes_destroy(volumes);
301 if (rd != NULL)
302 (void) rd_img_close(rd);
303 if (path != NULL)
304 free(path);
305 if (rdpath != NULL)
306 free(rdpath);
307 return rc;
308}
309
[3a34852]310/** Write unaligned 64-bit little-endian number.
311 *
312 * @param a Destination buffer
313 * @param data Number
314 */
315static void set_unaligned_u64le(uint8_t *a, uint64_t data)
316{
317 int i;
318
319 for (i = 0; i < 8; i++) {
320 a[i] = (data >> (i * 8)) & 0xff;
321 }
322}
323
324/** Copy boot blocks.
325 *
326 * Install Grub's boot blocks.
327 *
328 * @param devp Disk device
[cde999a]329 * @return EOK on success or an error code
[3a34852]330 */
[b7fd2a0]331static errno_t sysinst_copy_boot_blocks(const char *devp)
[3a34852]332{
333 void *boot_img;
334 size_t boot_img_size;
335 void *core_img;
336 size_t core_img_size;
337 service_id_t sid;
338 size_t bsize;
339 uint8_t bbuf[512];
340 aoff64_t core_start;
341 aoff64_t core_blocks;
342 grub_boot_blocklist_t *first_bl, *bl;
[b7fd2a0]343 errno_t rc;
[3a34852]344
345 printf("sysinst_copy_boot_blocks: Read boot block image.\n");
346 rc = futil_get_file(BOOT_FILES_SRC "/boot/grub/i386-pc/boot.img",
347 &boot_img, &boot_img_size);
348 if (rc != EOK || boot_img_size != 512)
349 return EIO;
350
351 printf("sysinst_copy_boot_blocks: Read GRUB core image.\n");
352 rc = futil_get_file(BOOT_FILES_SRC "/boot/grub/i386-pc/core.img",
353 &core_img, &core_img_size);
354 if (rc != EOK)
355 return EIO;
356
357 printf("sysinst_copy_boot_blocks: get service ID.\n");
358 rc = loc_service_get_id(devp, &sid, 0);
359 if (rc != EOK)
360 return rc;
361
362 printf("sysinst_copy_boot_blocks: block_init.\n");
363 rc = block_init(sid, 512);
364 if (rc != EOK)
365 return rc;
366
367 printf("sysinst_copy_boot_blocks: get block size\n");
368 rc = block_get_bsize(sid, &bsize);
369 if (rc != EOK)
370 return rc;
371
372 if (bsize != 512) {
373 printf("Device block size != 512.\n");
374 return EIO;
375 }
376
377 printf("sysinst_copy_boot_blocks: read boot block\n");
378 rc = block_read_direct(sid, BOOT_BLOCK_IDX, 1, bbuf);
379 if (rc != EOK)
380 return EIO;
381
382 core_start = 16;
383 core_blocks = (core_img_size + 511) / 512;
384
385 /* Clean blocklists */
386 first_bl = core_img + 512 - sizeof(*first_bl);
387 bl = first_bl;
388 while (bl->len != 0) {
389 memset(bl, 0, sizeof(*bl));
390 --bl;
391 if ((void *)bl < core_img) {
392 printf("No block terminator in core image.\n");
393 return EIO;
394 }
395 }
396
397 first_bl->start = host2uint64_t_le(core_start + 1);
398 first_bl->len = host2uint16_t_le(core_blocks - 1);
399 first_bl->segment = grub_boot_i386_pc_kernel_seg + (512 >> 4);
400
401 /* Write boot code into boot block */
402 memcpy(bbuf, boot_img, 440); /* XXX 440 = sizeof(br_block_t.code_area) */
403 bbuf[grub_boot_machine_boot_drive] = 0xff;
404 set_unaligned_u64le(bbuf + grub_boot_machine_kernel_sector, core_start);
405
406 printf("sysinst_copy_boot_blocks: write boot block\n");
407 rc = block_write_direct(sid, BOOT_BLOCK_IDX, 1, bbuf);
408 if (rc != EOK)
409 return EIO;
410
[e2625b1a]411 printf("sysinst_copy_boot_blocks: write core blocks\n");
[3a34852]412 /* XXX Must pad last block with zeros */
413 rc = block_write_direct(sid, core_start, core_blocks, core_img);
414 if (rc != EOK)
415 return EIO;
416
417 printf("sysinst_copy_boot_blocks: OK.\n");
418 return EOK;
419}
420
[3cdd876]421/** Eject installation volume.
422 *
423 * @param psvc_id Partition service ID
424 */
425static errno_t sysinst_eject_dev(service_id_t part_id)
426{
427 vol_t *vol = NULL;
428 errno_t rc;
429
430 rc = vol_create(&vol);
431 if (rc != EOK) {
432 printf("Error contacting volume service.\n");
433 goto out;
434 }
435
436 rc = vol_part_eject(vol, part_id);
437 if (rc != EOK) {
438 printf("Error ejecting volume.\n");
439 goto out;
440 }
441
442 rc = EOK;
443out:
444 vol_destroy(vol);
445 return rc;
446}
447
[3a34852]448/** Install system to a device.
449 *
450 * @param dev Device to install to.
[cde999a]451 * @return EOK on success or an error code
[3a34852]452 */
[b7fd2a0]453static errno_t sysinst_install(const char *dev)
[3a34852]454{
[b7fd2a0]455 errno_t rc;
[3cdd876]456 service_id_t psvc_id;
[3a34852]457
[3cdd876]458 rc = sysinst_label_dev(dev, &psvc_id);
[3a34852]459 if (rc != EOK)
460 return rc;
461
[63c1dd5]462 printf("FS created and mounted. Creating system directory structure.\n");
463 rc = sysinst_setup_sysvol();
464 if (rc != EOK)
465 return rc;
466
467 printf("Directories created. Copying boot files.\n");
[3a34852]468 rc = sysinst_copy_boot_files();
469 if (rc != EOK)
470 return rc;
471
[df8eaba]472 printf("Boot files done. Configuring the system.\n");
473 rc = sysinst_customize_initrd();
474 if (rc != EOK)
475 return rc;
476
[3a34852]477 printf("Boot files done. Installing boot blocks.\n");
478 rc = sysinst_copy_boot_blocks(dev);
479 if (rc != EOK)
480 return rc;
481
[3cdd876]482 printf("Ejecting device.\n");
483 rc = sysinst_eject_dev(psvc_id);
484 if (rc != EOK)
485 return rc;
486
[3a34852]487 return EOK;
488}
489
490int main(int argc, char *argv[])
491{
492 const char *dev = DEFAULT_DEV;
493 return sysinst_install(dev);
494}
495
496/** @}
497 */
Note: See TracBrowser for help on using the repository browser.