1 /* $NetBSD: setnetbootinfo.c,v 1.12 2002/09/22 05:38:30 mycroft Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Christopher G. Demetriou 5 * 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Christopher G. Demetriou 18 * for the NetBSD Project. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/fcntl.h> 35 #include <sys/stat.h> 36 #include <sys/socket.h> /* XXX */ 37 #include <net/if.h> /* XXX */ 38 #include <net/if_ether.h> 39 #include <err.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 #include "stand/common/bbinfo.h" 46 47 static void usage(void); 48 int main(int argc, char *argv[]); 49 50 int verbose, force, unset; 51 char *netboot, *outfile, *addr, *host; 52 53 char *outfilename; 54 55 struct ether_addr *ether_addr, _ether_addr; 56 57 static void 58 usage(void) 59 { 60 61 fprintf(stderr, "usage:\n"); 62 fprintf(stderr, "\tsetnetboot [-v] [-f] [-o outfile] \\\n"); 63 fprintf(stderr, "\t [-a ether-address | -h ether-host] infile\n"); 64 fprintf(stderr, "\tsetnetboot [-v] -u -o outfile infile\n"); 65 exit(1); 66 } 67 68 int 69 main(argc, argv) 70 int argc; 71 char *argv[]; 72 { 73 struct netbbinfo *netbbinfop; 74 struct stat sb; 75 u_int64_t *qp, csum; 76 char *netbb; 77 int c, fd, i; 78 79 while ((c = getopt(argc, argv, "a:fh:o:uv")) != -1) { 80 switch (c) { 81 case 'a': 82 /* use the argument as an ethernet address */ 83 addr = optarg; 84 break; 85 case 'f': 86 /* set force flag in network boot block */ 87 force = 1; 88 break; 89 case 'h': 90 /* use the argument as a host to find in /etc/ethers */ 91 host = optarg; 92 break; 93 case 'o': 94 /* use the argument as the output file name */ 95 outfile = optarg; 96 break; 97 case 'u': 98 /* remove configuration information */ 99 unset = 1; 100 break; 101 case 'v': 102 /* Chat */ 103 verbose = 1; 104 break; 105 default: 106 usage(); 107 } 108 } 109 110 if ((argc - optind) != 1) 111 usage(); 112 netboot = argv[optind]; 113 114 if (unset && (force || host != NULL || addr != NULL)) 115 errx(1, "-u can't be used with -f, -h, or -a"); 116 117 if (unset) { 118 if (force || host != NULL || addr != NULL) 119 errx(1, "-u can't be used with -f, -h, or -a"); 120 if (outfile == NULL) 121 errx(1, "-u cannot be used without -o"); 122 } else { 123 if ((host == NULL && addr == NULL) || 124 (host != NULL && addr != NULL)) 125 usage(); 126 127 if (host != NULL) { 128 if (ether_hostton(host, &_ether_addr) == -1) 129 errx(1, "ethernet address couldn't be found for \"%s\"", 130 host); 131 ether_addr = &_ether_addr; 132 } else { /* addr != NULL */ 133 ether_addr = ether_aton(addr); 134 if (ether_addr == NULL) 135 errx(1, "ethernet address \"%s\" is invalid", 136 addr); 137 } 138 } 139 140 if (outfile != NULL) 141 outfilename = outfile; 142 else { 143 /* name + 12 for enet addr + '.' before enet addr + NUL */ 144 outfilename = malloc(strlen(netboot) + 14); 145 if (outfilename == NULL) 146 err(1, "malloc of output file name failed"); 147 sprintf(outfilename, "%s.%02x%02x%02x%02x%02x%02x", netboot, 148 ether_addr->ether_addr_octet[0], 149 ether_addr->ether_addr_octet[1], 150 ether_addr->ether_addr_octet[2], 151 ether_addr->ether_addr_octet[3], 152 ether_addr->ether_addr_octet[4], 153 ether_addr->ether_addr_octet[5]); 154 } 155 156 if (verbose) { 157 printf("netboot: %s\n", netboot); 158 if (unset) 159 printf("unsetting configuration\n"); 160 else 161 printf("ethernet address: %s (%s), force = %d\n", 162 ether_ntoa(ether_addr), host ? host : addr, force); 163 printf("output netboot: %s\n", outfilename); 164 } 165 166 167 if (verbose) 168 printf("opening %s...\n", netboot); 169 if ((fd = open(netboot, O_RDONLY, 0)) == -1) 170 err(1, "open: %s", netboot); 171 if (fstat(fd, &sb) == -1) 172 err(1, "fstat: %s", netboot); 173 if (!S_ISREG(sb.st_mode)) 174 errx(1, "%s must be a regular file", netboot); 175 176 if (verbose) 177 printf("reading %s...\n", netboot); 178 netbb = malloc(sb.st_size); 179 if (netbb == NULL) 180 err(1, "malloc of %lu for %s failed", 181 (unsigned long)sb.st_size, netboot); 182 if (read(fd, netbb, sb.st_size) != sb.st_size) 183 err(1, "read of %lu from %s failed", 184 (unsigned long)sb.st_size, netboot); 185 186 if (verbose) 187 printf("closing %s...\n", netboot); 188 close(fd); 189 190 if (verbose) 191 printf("looking for netbbinfo...\n"); 192 netbbinfop = NULL; 193 for (qp = (u_int64_t *)netbb; qp < (u_int64_t *)(netbb + sb.st_size); 194 qp++) { 195 if (((struct netbbinfo *)qp)->magic1 == 0xfeedbabedeadbeefLL && 196 ((struct netbbinfo *)qp)->magic2 == 0xfeedbeefdeadbabeLL) { 197 netbbinfop = (struct netbbinfo *)qp; 198 break; 199 } 200 } 201 if (netbbinfop == NULL) 202 errx(1, "netboot information structure not found in %s", 203 netboot); 204 if (verbose) 205 printf("found netbbinfo structure at offset 0x%lx.\n", 206 (unsigned long)((char *)netbbinfop - netbb)); 207 208 if (verbose) 209 printf("setting netbbinfo structure...\n"); 210 memset(netbbinfop, 0, sizeof *netbbinfop); 211 netbbinfop->magic1 = 0xfeedbabedeadbeefLL; 212 netbbinfop->magic2 = 0xfeedbeefdeadbabeLL; 213 netbbinfop->set = unset ? 0 : 1; 214 if (netbbinfop->set) { 215 for (i = 0; i < 6; i++) 216 netbbinfop->ether_addr[i] = 217 ether_addr->ether_addr_octet[i]; 218 netbbinfop->force = force; 219 } 220 netbbinfop->cksum = 0; 221 222 if (verbose) 223 printf("setting netbbinfo checksum...\n"); 224 csum = 0; 225 for (i = 0, qp = (u_int64_t *)netbbinfop; 226 i < (sizeof *netbbinfop / sizeof (u_int64_t)); i++, qp++) 227 csum += *qp; 228 netbbinfop->cksum = -csum; 229 230 if (verbose) 231 printf("opening %s...\n", outfilename); 232 if ((fd = open(outfilename, O_WRONLY | O_CREAT, 0666)) == -1) 233 err(1, "open: %s", outfilename); 234 235 if (verbose) 236 printf("writing %s...\n", outfilename); 237 if (write(fd, netbb, sb.st_size) != sb.st_size) 238 err(1, "write of %lu to %s failed", 239 (unsigned long)sb.st_size, outfilename); 240 241 if (verbose) 242 printf("closing %s...\n", outfilename); 243 close(fd); 244 245 free(netbb); 246 if (outfile == NULL) 247 free(outfilename); 248 249 exit (0); 250 } 251