source: mainline/uspace/app/sysinst/sysinst.c@ 9c4cf0d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 9c4cf0d was 80743a1, checked in by Jakub Jermar <jakub@…>, 9 years ago

Rename (un)mount to vfs_(un)mount_path

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