1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2016 Toomas Soome <tsoome@me.com>
14 */
15
16 #include <stdio.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <sys/sysmacros.h>
22 #include <sys/multiboot.h>
23
24 #include "bblk_einfo.h"
25 #include "boot_utils.h"
26 #include "mboot_extra.h"
27
28 /*
29 * Add version to loader bootblock file. The file should have fake
30 * multiboot header and version data will be added at the end of the file.
31 * MB header is fake in sense that this bootblock is *not* MB compatible,
32 * and MB header will only include load_addr and load_end_addr components.
33 * load_addr will be set to value 0 to indicate the beginning of the file
34 * and load_end_addr will be set to the size of the original file.
35 * The flags value in header must be exactly AOUT kludge.
36 *
37 * version data is aligned by 8 bytes and whole blootblock will be padded to
38 * 512B sector size.
39 *
40 * To use and verify version data, first find MB header, then load_end_addr
41 * will point to the end of the original file, aligned up by 8, is version
42 * data implemented as bblk einfo.
43 */
44
45 void
add_version(const char * ifile,const char * ofile,char * version)46 add_version(const char *ifile, const char *ofile, char *version)
47 {
48 int fd;
49 int ret;
50 uint32_t buf_size;
51 uint32_t mboot_off;
52 uint32_t extra;
53 uint32_t avail_space;
54 multiboot_header_t *mboot;
55 struct stat sb;
56 char *buf;
57 bblk_hs_t hs;
58
59 fd = open(ifile, O_RDONLY);
60 if (fd == -1) {
61 perror("open");
62 return;
63 }
64 if (fstat(fd, &sb) == -1) {
65 perror("fstat");
66 close(fd);
67 return;
68 }
69
70 /*
71 * make sure we have enough space to append EINFO.
72 */
73 buf_size = P2ROUNDUP(sb.st_size + SECTOR_SIZE, SECTOR_SIZE);
74 buf = malloc(buf_size);
75 if (buf == NULL) {
76 perror("malloc");
77 close(fd);
78 return;
79 }
80
81 /*
82 * read in whole file. we need to access MB header and einfo
83 * will create MD5 hash.
84 */
85 ret = read(fd, buf, sb.st_size);
86 if (ret != sb.st_size) {
87 perror("read");
88 free(buf);
89 close(fd);
90 return;
91 }
92 close(fd);
93
94 if (find_multiboot(buf, MBOOT_SCAN_SIZE, &mboot_off)
95 != BC_SUCCESS) {
96 printf("Unable to find multiboot header\n");
97 free(buf);
98 return;
99 }
100
101 mboot = (multiboot_header_t *)(buf + mboot_off);
102 mboot->load_addr = 0;
103 mboot->load_end_addr = sb.st_size;
104
105
106 hs.src_buf = (unsigned char *)buf;
107 hs.src_size = sb.st_size;
108
109 /*
110 * this is location for EINFO data
111 */
112 extra = P2ROUNDUP(sb.st_size, 8);
113 avail_space = buf_size - extra;
114 memset(buf+sb.st_size, 0, buf_size - sb.st_size);
115 add_einfo(buf + extra, version, &hs, avail_space);
116
117 fd = open(ofile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
118 if (fd == -1) {
119 perror("open");
120 free(buf);
121 return;
122 }
123 ret = write(fd, buf, buf_size);
124 close(fd);
125 free(buf);
126 }
127