xref: /illumos-gate/usr/src/tools/btxld/version.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
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
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