1 /* $OpenBSD: mkboot.c,v 1.16 2009/10/27 23:59:34 deraadt 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/file.h> 36 #include <sys/stat.h> 37 #include <string.h> 38 #include <stdlib.h> 39 #include <unistd.h> 40 #include <time.h> 41 #ifdef __OpenBSD__ 42 #include <err.h> 43 #endif 44 45 #include <sys/exec_aout.h> 46 #include <sys/exec_elf.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 #include <stdio.h> 56 #include <ctype.h> 57 58 int putfile(char *, int); 59 void __dead usage(void); 60 void bcddate(char *, char *); 61 char *lifname(char *); 62 int cksum(int, int *, int); 63 64 char *to_file; 65 int loadpoint, verbose; 66 u_long entry; 67 #ifndef __OpenBSD__ 68 char *__progname = "mkboot"; 69 #endif 70 71 /* 72 * Old Format: 73 * sector 0: LIF volume header (40 bytes) 74 * sector 1: <unused> 75 * sector 2: LIF directory (8 x 32 == 256 bytes) 76 * sector 3-: LIF file 0, LIF file 1, etc. 77 * where sectors are 256 bytes. 78 * 79 * New Format: 80 * sector 0: LIF volume header (40 bytes) 81 * sector 1: <unused> 82 * sector 2: LIF directory (8 x 32 == 256 bytes) 83 * sector 3: <unused> 84 * sector 4-31: disklabel (~300 bytes right now) 85 * sector 32-: LIF file 0, LIF file 1, etc. 86 */ 87 int 88 main(int argc, char **argv) 89 { 90 int to; 91 register int n, pos, c; 92 char buf[LIF_FILESTART]; 93 struct lifvol *lifv = (struct lifvol *)buf; 94 struct lifdir *lifd = (struct lifdir *)(buf + LIF_DIRSTART); 95 96 while ((c = getopt(argc, argv, "vl:")) != -1) { 97 switch (c) { 98 case 'v': 99 verbose++; 100 break; 101 case 'l': 102 sscanf(optarg, "0x%x", &loadpoint); 103 break; 104 default: 105 usage(); 106 } 107 } 108 if (argc - optind < 2) 109 usage(); 110 else if (argc - optind > 8) 111 errx(1, "too many boot programs (max 8 supported)"); 112 113 to_file = argv[--argc]; 114 if ((to = open(to_file, O_RDWR | O_TRUNC | O_CREAT, 0644)) < 0) 115 err(1, "%s: open", to_file); 116 117 bzero(buf, sizeof(buf)); 118 /* clear possibly unused directory entries */ 119 memset(lifd[1].dir_name, ' ', sizeof lifd[1].dir_name); 120 lifd[1].dir_type = -1; 121 lifd[1].dir_addr = 0; 122 lifd[1].dir_length = 0; 123 lifd[1].dir_flag = 0xFF; 124 lifd[1].dir_implement = 0; 125 lifd[7] = lifd[6] = lifd[5] = lifd[4] = lifd[3] = lifd[2] = lifd[1]; 126 127 /* record volume info */ 128 lifv->vol_id = htobe16(LIF_VOL_ID); 129 strncpy(lifv->vol_label, "BOOT44", 6); 130 lifv->vol_addr = htobe32(btolifs(LIF_DIRSTART)); 131 lifv->vol_oct = htobe16(LIF_VOL_OCT); 132 lifv->vol_dirsize = htobe32(btolifs(LIF_DIRSIZE)); 133 lifv->vol_version = htobe16(1); 134 lifv->vol_lastvol = lifv->vol_number = htobe16(1); 135 lifv->vol_length = LIF_FILESTART; 136 bcddate(to_file, lifv->vol_toc); 137 lifv->ipl_addr = htobe32(LIF_FILESTART); 138 lifv->ipl_size = 0; 139 lifv->ipl_entry = 0; 140 141 argv += optind; 142 argc -= optind; 143 optind = 0; 144 for (pos = LIF_FILESTART; optind < argc; optind++) { 145 146 /* output bootfile */ 147 lseek(to, pos, 0); 148 lifd[optind].dir_addr = htobe32(btolifs(pos)); 149 n = btolifs(putfile(argv[optind], to)); 150 if (lifv->ipl_entry == 0) { 151 lifv->ipl_entry = htobe32(loadpoint + entry); 152 lifv->ipl_size = htobe32(lifstob(n)); 153 lifd[optind].dir_type = htobe16(LIF_DIR_ISL); 154 lifd[optind].dir_implement = 0; 155 } else { 156 lifd[optind].dir_type = htobe16(LIF_DIR_TYPE); 157 lifd[1].dir_implement = htobe32(loadpoint + entry); 158 } 159 160 strlcpy(lifd[optind].dir_name, lifname(argv[optind]), 161 sizeof lifd[optind].dir_name); 162 lifd[optind].dir_length = htobe32(n); 163 bcddate(argv[optind], lifd[optind].dir_toc); 164 lifd[optind].dir_flag = htobe16(LIF_DIR_FLAG); 165 166 lifv->vol_length += n; 167 pos += lifstob(n); 168 } 169 170 lifv->vol_length = htobe32(lifv->vol_length); 171 172 /* output volume/directory header info */ 173 lseek(to, LIF_VOLSTART, 0); 174 if (write(to, buf, sizeof(buf)) != sizeof(buf)) 175 err(1, "%s: write LIF volume", to_file); 176 lseek(to, 0, SEEK_END); 177 178 if (close(to) < 0) 179 err(1, "%s", to_file); 180 181 return(0); 182 } 183 184 int 185 putfile(from_file, to) 186 char *from_file; 187 int to; 188 { 189 struct exec ex; 190 register int n, total; 191 char buf[2048]; 192 int from, check_sum = 0; 193 struct lif_load load; 194 195 if ((from = open(from_file, O_RDONLY)) < 0) 196 err(1, "%s", from_file); 197 198 n = read(from, &ex, sizeof(ex)); 199 if (n != sizeof(ex)) 200 err(1, "%s: reading file header", from_file); 201 202 entry = ex.a_entry; 203 if (N_GETMAGIC(ex) == OMAGIC || N_GETMAGIC(ex) == NMAGIC) 204 entry += sizeof(ex); 205 else if (IS_ELF(*(Elf32_Ehdr *)&ex)) { 206 Elf32_Ehdr elf_header; 207 Elf32_Phdr *elf_segments; 208 int i,header_count, memory_needed, elf_load_image_segment; 209 210 (void) lseek(from, 0, SEEK_SET); 211 n = read(from, &elf_header, sizeof (elf_header)); 212 if (n != sizeof (elf_header)) 213 err(1, "%s: reading ELF header", from_file); 214 header_count = ntohs(elf_header.e_phnum); 215 memory_needed = header_count * sizeof (*elf_segments); 216 elf_segments = malloc(memory_needed); 217 if (elf_segments == NULL) 218 err(1, "malloc"); 219 (void) lseek(from, ntohl(elf_header.e_phoff), SEEK_SET); 220 n = read(from, elf_segments, memory_needed); 221 if (n != memory_needed) 222 err(1, "%s: reading ELF segments", from_file); 223 elf_load_image_segment = -1; 224 for (i = 0; i < header_count; i++) { 225 if (elf_segments[i].p_filesz && 226 ntohl(elf_segments[i].p_flags) & PF_X) { 227 if (elf_load_image_segment != -1) 228 errx(1, "%s: more than one ELF program segment", from_file); 229 elf_load_image_segment = i; 230 } 231 if (elf_load_image_segment == -1) 232 errx(1, "%s: no suitable ELF program segment", from_file); 233 } 234 entry = ntohl(elf_header.e_entry) + 235 ntohl(elf_segments[elf_load_image_segment].p_offset) - 236 ntohl(elf_segments[elf_load_image_segment].p_vaddr); 237 } else if (*(u_char *)&ex == 0x1f && ((u_char *)&ex)[1] == 0x8b) { 238 entry = 0; 239 } else 240 errx(1, "%s: bad magic number", from_file); 241 242 entry += sizeof(load); 243 lseek(to, sizeof(load), SEEK_CUR); 244 total = 0; 245 n = sizeof(buf) - sizeof(load); 246 /* copy the whole file */ 247 for (lseek(from, 0, 0); ; n = sizeof(buf)) { 248 bzero(buf, sizeof(buf)); 249 if ((n = read(from, buf, n)) < 0) 250 err(1, "%s", from_file); 251 else if (n == 0) 252 break; 253 254 if (write(to, buf, n) != n) 255 err(1, "%s", to_file); 256 257 total += n; 258 check_sum = cksum(check_sum, (int *)buf, n); 259 } 260 261 /* load header */ 262 load.address = htobe32(loadpoint + sizeof(load)); 263 load.count = htobe32(4 + total); 264 check_sum = cksum(check_sum, (int *)&load, sizeof(load)); 265 266 if (verbose) 267 warnx("wrote %d bytes of file \'%s\'", total, from_file); 268 269 total += sizeof(load); 270 /* insert the header */ 271 lseek(to, -total, SEEK_CUR); 272 if (write(to, &load, sizeof(load)) != sizeof(load)) 273 err(1, "%s", to_file); 274 lseek(to, total - sizeof(load), SEEK_CUR); 275 276 bzero(buf, sizeof(buf)); 277 /* pad to int */ 278 n = sizeof(int) - total % sizeof(int); 279 if (total % sizeof(int)) { 280 if (write(to, buf, n) != n) 281 err(1, "%s", to_file); 282 else 283 total += n; 284 } 285 286 /* pad to the blocksize */ 287 n = sizeof(buf) - total % sizeof(buf); 288 289 if (n < sizeof(int)) { 290 n += sizeof(buf); 291 total += sizeof(buf); 292 } else 293 total += n; 294 295 /* TODO should pad here to the 65k boundary for tape boot */ 296 297 if (verbose) 298 warnx("checksum is 0x%08x", -check_sum); 299 300 check_sum = htobe32(-check_sum); 301 if (write(to, &check_sum, sizeof(int)) != sizeof(int)) 302 err(1, "%s", to_file); 303 304 n -= sizeof(int); 305 306 if (write(to, buf, n) != n) 307 err(1, "%s", to_file); 308 309 if (close(from) < 0 ) 310 err(1, "%s", from_file); 311 312 return total; 313 } 314 315 int 316 cksum(ck, p, size) 317 int ck; 318 int *p; 319 int size; 320 { 321 /* we assume size is int-aligned */ 322 for (size = (size + sizeof(int) - 1) / sizeof(int); size--; p++ ) 323 ck += betoh32(*p); 324 325 return ck; 326 } 327 328 void __dead 329 usage() 330 { 331 extern char *__progname; 332 fprintf(stderr, 333 "usage: %s [-v] [-l loadpoint] prog1 {progN} outfile\n", 334 __progname); 335 exit(1); 336 } 337 338 char * 339 lifname(str) 340 char *str; 341 { 342 static char lname[10] = "XXXXXXXXXX"; 343 register int i; 344 345 for (i = 0; i < 9; i++) { 346 if (islower(*str)) 347 lname[i] = toupper(*str); 348 else if (isalnum(*str) || *str == '_') 349 lname[i] = *str; 350 else 351 break; 352 str++; 353 } 354 for ( ; i < 10; i++) 355 lname[i] = ' '; 356 return(lname); 357 } 358 359 360 void 361 bcddate(file, toc) 362 char *file; 363 char *toc; 364 { 365 struct stat statb; 366 #ifndef __OpenBSD__ 367 struct tm { 368 int tm_sec; /* second (0-61, allows for leap seconds) */ 369 int tm_min; /* minute (0-59) */ 370 int tm_hour; /* hour (0-23) */ 371 int tm_mday; /* day of the month (1-31) */ 372 int tm_mon; /* month (0-11) */ 373 int tm_year; /* years since 1900 */ 374 int tm_wday; /* day of the week (0-6) */ 375 int tm_yday; /* day of the year (0-365) */ 376 int tm_isdst; /* non-0 if daylight saving time is in effect */ 377 } *tm; 378 #else 379 struct tm *tm; 380 #endif 381 382 stat(file, &statb); 383 tm = localtime(&statb.st_ctime); 384 *toc = (tm->tm_year / 10) << 4; 385 *toc++ |= tm->tm_year % 10; 386 *toc = ((tm->tm_mon+1) / 10) << 4; 387 *toc++ |= (tm->tm_mon+1) % 10; 388 *toc = (tm->tm_mday / 10) << 4; 389 *toc++ |= tm->tm_mday % 10; 390 *toc = (tm->tm_hour / 10) << 4; 391 *toc++ |= tm->tm_hour % 10; 392 *toc = (tm->tm_min / 10) << 4; 393 *toc++ |= tm->tm_min % 10; 394 *toc = (tm->tm_sec / 10) << 4; 395 *toc |= tm->tm_sec % 10; 396 } 397 398 #ifndef __OpenBSD__ 399 int 400 err(ex, str) 401 int ex; 402 char *str; 403 { 404 perror(str); 405 exit(ex); 406 } 407 408 int 409 errx(ex, str) 410 int ex; 411 char *str; 412 { 413 perror(str); 414 exit(ex); 415 } 416 #endif 417