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