1 /* $OpenBSD: mkboot.c,v 1.21 2017/12/30 23:08:29 guenther Exp $ */ 2 3 /* 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)mkboot.c 8.1 (Berkeley) 7/15/93 32 */ 33 34 #include <sys/param.h> 35 #include <sys/exec.h> 36 #include <sys/exec_elf.h> 37 #include <sys/stat.h> 38 39 #include <ctype.h> 40 #include <err.h> 41 #include <fcntl.h> 42 #include <stdlib.h> 43 #include <stdio.h> 44 #include <string.h> 45 #include <time.h> 46 #include <unistd.h> 47 48 #ifndef hppa 49 /* hack for cross compile XXX */ 50 #include "../../include/disklabel.h" 51 #else 52 #include <sys/disklabel.h> 53 #endif 54 55 int putfile(char *, int); 56 void __dead usage(void); 57 void bcddate(char *, char *); 58 char *lifname(char *); 59 int cksum(int, int *, int); 60 61 char *to_file; 62 int loadpoint, verbose; 63 u_long entry; 64 65 /* 66 * Old Format: 67 * sector 0: LIF volume header (40 bytes) 68 * sector 1: <unused> 69 * sector 2: LIF directory (8 x 32 == 256 bytes) 70 * sector 3-: LIF file 0, LIF file 1, etc. 71 * where sectors are 256 bytes. 72 * 73 * New Format: 74 * sector 0: LIF volume header (40 bytes) 75 * sector 1: <unused> 76 * sector 2: LIF directory (8 x 32 == 256 bytes) 77 * sector 3: <unused> 78 * sector 4-31: disklabel (~300 bytes right now) 79 * sector 32-: LIF file 0, LIF file 1, etc. 80 */ 81 int 82 main(int argc, char **argv) 83 { 84 int to; 85 register int n, pos, c; 86 char buf[LIF_FILESTART]; 87 struct lifvol *lifv = (struct lifvol *)buf; 88 struct lifdir *lifd = (struct lifdir *)(buf + LIF_DIRSTART); 89 90 while ((c = getopt(argc, argv, "vl:")) != -1) { 91 switch (c) { 92 case 'v': 93 verbose++; 94 break; 95 case 'l': 96 sscanf(optarg, "0x%x", &loadpoint); 97 break; 98 default: 99 usage(); 100 } 101 } 102 if (argc - optind < 2) 103 usage(); 104 else if (argc - optind > 8) 105 errx(1, "too many boot programs (max 8 supported)"); 106 107 to_file = argv[--argc]; 108 if ((to = open(to_file, O_RDWR | O_TRUNC | O_CREAT, 0644)) < 0) 109 err(1, "%s: open", to_file); 110 111 bzero(buf, sizeof(buf)); 112 /* clear possibly unused directory entries */ 113 memset(lifd[1].dir_name, ' ', sizeof lifd[1].dir_name); 114 lifd[1].dir_type = -1; 115 lifd[1].dir_addr = 0; 116 lifd[1].dir_length = 0; 117 lifd[1].dir_flag = 0xFF; 118 lifd[1].dir_implement = 0; 119 lifd[7] = lifd[6] = lifd[5] = lifd[4] = lifd[3] = lifd[2] = lifd[1]; 120 121 /* record volume info */ 122 lifv->vol_id = htobe16(LIF_VOL_ID); 123 strncpy(lifv->vol_label, "BOOT44", 6); 124 lifv->vol_addr = htobe32(btolifs(LIF_DIRSTART)); 125 lifv->vol_oct = htobe16(LIF_VOL_OCT); 126 lifv->vol_dirsize = htobe32(btolifs(LIF_DIRSIZE)); 127 lifv->vol_version = htobe16(1); 128 lifv->vol_lastvol = lifv->vol_number = htobe16(1); 129 lifv->vol_length = LIF_FILESTART; 130 bcddate(to_file, lifv->vol_toc); 131 lifv->ipl_addr = htobe32(LIF_FILESTART); 132 lifv->ipl_size = 0; 133 lifv->ipl_entry = 0; 134 135 argv += optind; 136 argc -= optind; 137 optind = 0; 138 for (pos = LIF_FILESTART; optind < argc; optind++) { 139 140 /* output bootfile */ 141 lseek(to, pos, 0); 142 lifd[optind].dir_addr = htobe32(btolifs(pos)); 143 n = btolifs(putfile(argv[optind], to)); 144 if (lifv->ipl_entry == 0) { 145 lifv->ipl_entry = htobe32(loadpoint + entry); 146 lifv->ipl_size = htobe32(lifstob(n)); 147 lifd[optind].dir_type = htobe16(LIF_DIR_ISL); 148 lifd[optind].dir_implement = 0; 149 } else { 150 lifd[optind].dir_type = htobe16(LIF_DIR_TYPE); 151 lifd[1].dir_implement = htobe32(loadpoint + entry); 152 } 153 154 strlcpy(lifd[optind].dir_name, lifname(argv[optind]), 155 sizeof lifd[optind].dir_name); 156 lifd[optind].dir_length = htobe32(n); 157 bcddate(argv[optind], lifd[optind].dir_toc); 158 lifd[optind].dir_flag = htobe16(LIF_DIR_FLAG); 159 160 lifv->vol_length += n; 161 pos += lifstob(n); 162 } 163 164 lifv->vol_length = htobe32(lifv->vol_length); 165 166 /* output volume/directory header info */ 167 lseek(to, LIF_VOLSTART, 0); 168 if (write(to, buf, sizeof(buf)) != sizeof(buf)) 169 err(1, "%s: write LIF volume", to_file); 170 lseek(to, 0, SEEK_END); 171 172 if (close(to) < 0) 173 err(1, "%s", to_file); 174 175 return (0); 176 } 177 178 int 179 putfile(char *from_file, int to) 180 { 181 struct exec ex; 182 register int n, total; 183 char buf[2048]; 184 int from, check_sum = 0; 185 struct lif_load load; 186 187 if ((from = open(from_file, O_RDONLY)) < 0) 188 err(1, "%s", from_file); 189 190 n = read(from, &ex, sizeof(ex)); 191 if (n != sizeof(ex)) 192 err(1, "%s: reading file header", from_file); 193 194 entry = ex.a_entry; 195 if (N_GETMAGIC(ex) == OMAGIC || N_GETMAGIC(ex) == NMAGIC) 196 entry += sizeof(ex); 197 else if (IS_ELF(*(Elf32_Ehdr *)&ex)) { 198 Elf32_Ehdr elf_header; 199 Elf32_Phdr *elf_segments; 200 int i, header_count, memory_needed, elf_load_image_segment; 201 202 (void) lseek(from, 0, SEEK_SET); 203 n = read(from, &elf_header, sizeof(elf_header)); 204 if (n != sizeof (elf_header)) 205 err(1, "%s: reading ELF header", from_file); 206 header_count = ntohs(elf_header.e_phnum); 207 elf_segments = reallocarray(NULL, header_count, 208 sizeof(*elf_segments)); 209 if (elf_segments == NULL) 210 err(1, "malloc"); 211 memory_needed = header_count * sizeof(*elf_segments); 212 (void) lseek(from, ntohl(elf_header.e_phoff), SEEK_SET); 213 n = read(from, elf_segments, memory_needed); 214 if (n != memory_needed) 215 err(1, "%s: reading ELF segments", from_file); 216 elf_load_image_segment = -1; 217 for (i = 0; i < header_count; i++) { 218 if (elf_segments[i].p_filesz && 219 ntohl(elf_segments[i].p_flags) & PF_X) { 220 if (elf_load_image_segment != -1) 221 errx(1, "%s: more than one ELF program segment", from_file); 222 elf_load_image_segment = i; 223 } 224 } 225 if (elf_load_image_segment == -1) 226 errx(1, "%s: no suitable ELF program segment", from_file); 227 entry = ntohl(elf_header.e_entry) + 228 ntohl(elf_segments[elf_load_image_segment].p_offset) - 229 ntohl(elf_segments[elf_load_image_segment].p_vaddr); 230 free(elf_segments); 231 } else if (*(u_char *)&ex == 0x1f && ((u_char *)&ex)[1] == 0x8b) { 232 entry = 0; 233 } else 234 errx(1, "%s: bad magic number", from_file); 235 236 entry += sizeof(load); 237 lseek(to, sizeof(load), SEEK_CUR); 238 total = 0; 239 n = sizeof(buf) - sizeof(load); 240 /* copy the whole file */ 241 for (lseek(from, 0, 0); ; n = sizeof(buf)) { 242 bzero(buf, sizeof(buf)); 243 if ((n = read(from, buf, n)) < 0) 244 err(1, "%s", from_file); 245 else if (n == 0) 246 break; 247 248 if (write(to, buf, n) != n) 249 err(1, "%s", to_file); 250 251 total += n; 252 check_sum = cksum(check_sum, (int *)buf, n); 253 } 254 255 /* load header */ 256 load.address = htobe32(loadpoint + sizeof(load)); 257 load.count = htobe32(4 + total); 258 check_sum = cksum(check_sum, (int *)&load, sizeof(load)); 259 260 if (verbose) 261 warnx("wrote %d bytes of file \'%s\'", total, from_file); 262 263 total += sizeof(load); 264 /* insert the header */ 265 lseek(to, -total, SEEK_CUR); 266 if (write(to, &load, sizeof(load)) != sizeof(load)) 267 err(1, "%s", to_file); 268 lseek(to, total - sizeof(load), SEEK_CUR); 269 270 bzero(buf, sizeof(buf)); 271 /* pad to int */ 272 n = sizeof(int) - total % sizeof(int); 273 if (total % sizeof(int)) { 274 if (write(to, buf, n) != n) 275 err(1, "%s", to_file); 276 else 277 total += n; 278 } 279 280 /* pad to the blocksize */ 281 n = sizeof(buf) - total % sizeof(buf); 282 283 if (n < sizeof(int)) { 284 n += sizeof(buf); 285 total += sizeof(buf); 286 } else 287 total += n; 288 289 /* TODO should pad here to the 65k boundary for tape boot */ 290 291 if (verbose) 292 warnx("checksum is 0x%08x", -check_sum); 293 294 check_sum = htobe32(-check_sum); 295 if (write(to, &check_sum, sizeof(int)) != sizeof(int)) 296 err(1, "%s", to_file); 297 298 n -= sizeof(int); 299 300 if (write(to, buf, n) != n) 301 err(1, "%s", to_file); 302 303 if (close(from) < 0 ) 304 err(1, "%s", from_file); 305 306 return total; 307 } 308 309 int 310 cksum(int ck, int *p, int size) 311 { 312 /* we assume size is int-aligned */ 313 for (size = (size + sizeof(int) - 1) / sizeof(int); size--; p++ ) 314 ck += betoh32(*p); 315 316 return ck; 317 } 318 319 void __dead 320 usage(void) 321 { 322 extern char *__progname; 323 fprintf(stderr, 324 "usage: %s [-v] [-l loadpoint] prog1 {progN} outfile\n", 325 __progname); 326 exit(1); 327 } 328 329 char * 330 lifname(char *str) 331 { 332 static char lname[10] = "XXXXXXXXXX"; 333 register int i; 334 335 for (i = 0; i < 9; i++) { 336 if (islower(*str)) 337 lname[i] = toupper(*str); 338 else if (isalnum(*str) || *str == '_') 339 lname[i] = *str; 340 else 341 break; 342 str++; 343 } 344 for ( ; i < 10; i++) 345 lname[i] = ' '; 346 return(lname); 347 } 348 349 350 void 351 bcddate(char *file, char *toc) 352 { 353 struct stat statb; 354 struct tm *tm; 355 356 stat(file, &statb); 357 tm = localtime(&statb.st_ctime); 358 *toc = (tm->tm_year / 10) << 4; 359 *toc++ |= tm->tm_year % 10; 360 *toc = ((tm->tm_mon+1) / 10) << 4; 361 *toc++ |= (tm->tm_mon+1) % 10; 362 *toc = (tm->tm_mday / 10) << 4; 363 *toc++ |= tm->tm_mday % 10; 364 *toc = (tm->tm_hour / 10) << 4; 365 *toc++ |= tm->tm_hour % 10; 366 *toc = (tm->tm_min / 10) << 4; 367 *toc++ |= tm->tm_min % 10; 368 *toc = (tm->tm_sec / 10) << 4; 369 *toc |= tm->tm_sec % 10; 370 } 371