source: mainline/uspace/app/sysinst/sysinst.c@ 51b2693

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

Let vfs_link() and vfs_link_path() return the linked file handle

Add an output argument to both vfs_link() and vfs_link_path() so that the
client may receive the file handle of the linked file or directory. This
makes it easy to work with the new file or directory as it is ready to be
opened or in case of a directory to use it as a parent for further
operations without the need for additional vfs_lookup().

  • 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, NULL);
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, NULL);
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.