source: mainline/uspace/app/sysinst/sysinst.c@ 1d6dd2a

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

Remove unnecessary includes from <stdio.h>.

  • Property mode set to 100644
File size: 10.0 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#include <str.h>
50
51#include "futil.h"
52#include "grub.h"
53
54/** Device to install to
55 *
56 * Note that you cannot simply change this, because the installation
57 * device is hardcoded in core.img. If you wanted to install to another
58 * device, you must build your own core.img (e.g. using tools/grub/mkimage.sh
59 * and modifying tools/grub/load.cfg, supplying the device to boot from
60 * in Grub notation).
61 */
62#define DEFAULT_DEV "devices/\\hw\\pci0\\00:01.0\\ata-c1\\d0"
63//#define DEFAULT_DEV "devices/\\hw\\pci0\\00:01.2\\uhci_rh\\usb01_a1\\mass-storage0\\l0"
64
65/** Filysystem type. Cannot be changed without building a custom core.img */
66#define FS_TYPE "mfs"
67
68#define FS_SRV "/srv/mfs"
69#define MOUNT_POINT "/inst"
70
71/** Device containing HelenOS live CD */
72#define CD_DEV "devices/\\hw\\pci0\\00:01.0\\ata-c2\\d0"
73
74#define CD_FS_TYPE "cdfs"
75#define CD_FS_SRV "/srv/cdfs"
76#define CD_MOUNT_POINT "/cdrom"
77
78#define BOOT_FILES_SRC "/cdrom"
79#define BOOT_BLOCK_IDX 0 /* MBR */
80
81/** Label the destination device.
82 *
83 * @param dev Disk device to label
84 * @param pdev Place to store partition device name
85 *
86 * @return EOK on success or an error code
87 */
88static errno_t sysinst_label_dev(const char *dev, char **pdev)
89{
90 fdisk_t *fdisk;
91 fdisk_dev_t *fdev;
92 fdisk_part_t *part;
93 fdisk_part_spec_t pspec;
94 cap_spec_t cap;
95 service_id_t sid;
96 errno_t rc;
97
98 printf("sysinst_label_dev(): get service ID '%s'\n", dev);
99 rc = loc_service_get_id(dev, &sid, 0);
100 if (rc != EOK)
101 return rc;
102
103 printf("sysinst_label_dev(): open device\n");
104
105 rc = fdisk_create(&fdisk);
106 if (rc != EOK) {
107 printf("Error initializing fdisk.\n");
108 return rc;
109 }
110
111 rc = fdisk_dev_open(fdisk, sid, &fdev);
112 if (rc != EOK) {
113 printf("Error opening device.\n");
114 return rc;
115 }
116
117 printf("sysinst_label_dev(): create label\n");
118
119 rc = fdisk_label_create(fdev, lt_mbr);
120 if (rc != EOK) {
121 printf("Error creating label: %s.\n", str_error(rc));
122 return rc;
123 }
124
125 printf("sysinst_label_dev(): create partition\n");
126
127 rc = fdisk_part_get_max_avail(fdev, spc_pri, &cap);
128 if (rc != EOK) {
129 printf("Error getting available capacity: %s.\n", str_error(rc));
130 return rc;
131 }
132
133 fdisk_pspec_init(&pspec);
134 pspec.capacity = cap;
135 pspec.pkind = lpk_primary;
136 pspec.fstype = fs_minix;
137
138 rc = fdisk_part_create(fdev, &pspec, &part);
139 if (rc != EOK) {
140 printf("Error creating partition.\n");
141 return rc;
142 }
143
144 /* XXX libfdisk should give us the service name */
145 if (asprintf(pdev, "%sp1", dev) < 0)
146 return ENOMEM;
147
148 printf("sysinst_label_dev(): OK\n");
149 return EOK;
150}
151
152/** Mount target file system.
153 *
154 * @param dev Partition device
155 * @return EOK on success or an error code
156 */
157static errno_t sysinst_fs_mount(const char *dev)
158{
159 task_wait_t twait;
160 task_exit_t texit;
161 errno_t rc;
162 int trc;
163
164 printf("sysinst_fs_mount(): start filesystem server\n");
165 rc = task_spawnl(NULL, &twait, FS_SRV, FS_SRV, NULL);
166 if (rc != EOK)
167 return rc;
168
169 printf("sysinst_fs_mount(): wait for filesystem server\n");
170 rc = task_wait(&twait, &texit, &trc);
171 if (rc != EOK)
172 return rc;
173
174 printf("sysinst_fs_mount(): verify filesystem server result\n");
175 if (texit != TASK_EXIT_NORMAL || trc != 0) {
176 printf("sysinst_fs_mount(): not successful, but could be already loaded.\n");
177 }
178
179 rc = vfs_link_path(MOUNT_POINT, KIND_DIRECTORY, NULL);
180 if (rc != EOK)
181 return rc;
182
183 printf("sysinst_fs_mount(): mount filesystem\n");
184 rc = vfs_mount_path(MOUNT_POINT, FS_TYPE, dev, "", 0, 0);
185 if (rc != EOK)
186 return rc;
187
188 printf("sysinst_fs_mount(): OK\n");
189 return EOK;
190}
191
192/** Copy boot files.
193 *
194 * @return EOK on success or an error code
195 */
196static errno_t sysinst_copy_boot_files(void)
197{
198 task_wait_t twait;
199 task_exit_t texit;
200 errno_t rc;
201 int trc;
202
203 printf("sysinst_copy_boot_files(): start filesystem server\n");
204 rc = task_spawnl(NULL, &twait, CD_FS_SRV, CD_FS_SRV, NULL);
205 if (rc != EOK)
206 return rc;
207
208 printf("sysinst_copy_boot_files(): wait for filesystem server\n");
209 rc = task_wait(&twait, &texit, &trc);
210 if (rc != EOK)
211 return rc;
212
213 printf("sysinst_copy_boot_files(): verify filesystem server result\n");
214 if (texit != TASK_EXIT_NORMAL || trc != 0) {
215 printf("sysinst_fs_mount(): not successful, but could be already loaded.\n");
216 }
217
218 printf("sysinst_copy_boot_files(): create CD mount point\n");
219 rc = vfs_link_path(CD_MOUNT_POINT, KIND_DIRECTORY, NULL);
220 if (rc != EOK)
221 return rc;
222
223 printf("sysinst_copy_boot_files(): mount CD filesystem\n");
224 rc = vfs_mount_path(CD_MOUNT_POINT, CD_FS_TYPE, CD_DEV, "", 0, 0);
225 if (rc != EOK)
226 return rc;
227
228 printf("sysinst_copy_boot_files(): copy bootloader files\n");
229 rc = futil_rcopy_contents(BOOT_FILES_SRC, MOUNT_POINT);
230 if (rc != EOK)
231 return rc;
232
233 printf("sysinst_copy_boot_files(): unmount %s\n", MOUNT_POINT);
234 rc = vfs_unmount_path(MOUNT_POINT);
235 if (rc != EOK)
236 return rc;
237
238 printf("sysinst_copy_boot_files(): OK\n");
239 return EOK;
240}
241
242/** Write unaligned 64-bit little-endian number.
243 *
244 * @param a Destination buffer
245 * @param data Number
246 */
247static void set_unaligned_u64le(uint8_t *a, uint64_t data)
248{
249 int i;
250
251 for (i = 0; i < 8; i++) {
252 a[i] = (data >> (i * 8)) & 0xff;
253 }
254}
255
256/** Copy boot blocks.
257 *
258 * Install Grub's boot blocks.
259 *
260 * @param devp Disk device
261 * @return EOK on success or an error code
262 */
263static errno_t sysinst_copy_boot_blocks(const char *devp)
264{
265 void *boot_img;
266 size_t boot_img_size;
267 void *core_img;
268 size_t core_img_size;
269 service_id_t sid;
270 size_t bsize;
271 uint8_t bbuf[512];
272 aoff64_t core_start;
273 aoff64_t core_blocks;
274 grub_boot_blocklist_t *first_bl, *bl;
275 errno_t rc;
276
277 printf("sysinst_copy_boot_blocks: Read boot block image.\n");
278 rc = futil_get_file(BOOT_FILES_SRC "/boot/grub/i386-pc/boot.img",
279 &boot_img, &boot_img_size);
280 if (rc != EOK || boot_img_size != 512)
281 return EIO;
282
283 printf("sysinst_copy_boot_blocks: Read GRUB core image.\n");
284 rc = futil_get_file(BOOT_FILES_SRC "/boot/grub/i386-pc/core.img",
285 &core_img, &core_img_size);
286 if (rc != EOK)
287 return EIO;
288
289 printf("sysinst_copy_boot_blocks: get service ID.\n");
290 rc = loc_service_get_id(devp, &sid, 0);
291 if (rc != EOK)
292 return rc;
293
294 printf("sysinst_copy_boot_blocks: block_init.\n");
295 rc = block_init(sid, 512);
296 if (rc != EOK)
297 return rc;
298
299 printf("sysinst_copy_boot_blocks: get block size\n");
300 rc = block_get_bsize(sid, &bsize);
301 if (rc != EOK)
302 return rc;
303
304 if (bsize != 512) {
305 printf("Device block size != 512.\n");
306 return EIO;
307 }
308
309 printf("sysinst_copy_boot_blocks: read boot block\n");
310 rc = block_read_direct(sid, BOOT_BLOCK_IDX, 1, bbuf);
311 if (rc != EOK)
312 return EIO;
313
314 core_start = 16;
315 core_blocks = (core_img_size + 511) / 512;
316
317 /* Clean blocklists */
318 first_bl = core_img + 512 - sizeof(*first_bl);
319 bl = first_bl;
320 while (bl->len != 0) {
321 memset(bl, 0, sizeof(*bl));
322 --bl;
323 if ((void *)bl < core_img) {
324 printf("No block terminator in core image.\n");
325 return EIO;
326 }
327 }
328
329 first_bl->start = host2uint64_t_le(core_start + 1);
330 first_bl->len = host2uint16_t_le(core_blocks - 1);
331 first_bl->segment = grub_boot_i386_pc_kernel_seg + (512 >> 4);
332
333 /* Write boot code into boot block */
334 memcpy(bbuf, boot_img, 440); /* XXX 440 = sizeof(br_block_t.code_area) */
335 bbuf[grub_boot_machine_boot_drive] = 0xff;
336 set_unaligned_u64le(bbuf + grub_boot_machine_kernel_sector, core_start);
337
338 printf("sysinst_copy_boot_blocks: write boot block\n");
339 rc = block_write_direct(sid, BOOT_BLOCK_IDX, 1, bbuf);
340 if (rc != EOK)
341 return EIO;
342
343 printf("sysinst_copy_boot_blocks: write boot block\n");
344 /* XXX Must pad last block with zeros */
345 rc = block_write_direct(sid, core_start, core_blocks, core_img);
346 if (rc != EOK)
347 return EIO;
348
349 printf("sysinst_copy_boot_blocks: OK.\n");
350 return EOK;
351}
352
353/** Install system to a device.
354 *
355 * @param dev Device to install to.
356 * @return EOK on success or an error code
357 */
358static errno_t sysinst_install(const char *dev)
359{
360 errno_t rc;
361 char *pdev;
362
363 rc = sysinst_label_dev(dev, &pdev);
364 if (rc != EOK)
365 return rc;
366
367 printf("Partition '%s'. Mount it.\n", pdev);
368 rc = sysinst_fs_mount(pdev);
369 if (rc != EOK)
370 return rc;
371
372 free(pdev);
373
374 printf("FS created and mounted. Copying boot files.\n");
375 rc = sysinst_copy_boot_files();
376 if (rc != EOK)
377 return rc;
378
379 printf("Boot files done. Installing boot blocks.\n");
380 rc = sysinst_copy_boot_blocks(dev);
381 if (rc != EOK)
382 return rc;
383
384 return EOK;
385}
386
387int main(int argc, char *argv[])
388{
389 const char *dev = DEFAULT_DEV;
390 return sysinst_install(dev);
391}
392
393/** @}
394 */
Note: See TracBrowser for help on using the repository browser.