Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.sbin / boot98cfg / boot98cfg.c
1 /*
2  * Copyright (c) KATO Takenori, 2000.
3  * 
4  * All rights reserved.  Unpublished rights reserved under the copyright
5  * laws of Japan.
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  * 
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer as
13  *    the first lines of this file unmodified.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  * 
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $FreeBSD: src/usr.sbin/boot98cfg/boot98cfg.c,v 1.1.2.2 2001/07/30 10:22:58 dd Exp $
32  */
33
34 /*
35  * Copyright (c) 1999 Robert Nordier
36  * All rights reserved.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND
48  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
50  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
51  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
52  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
53  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
54  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
55  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
56  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
57  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58  */
59
60 #include <sys/param.h>
61 #include <sys/stat.h>
62
63 #include <err.h>
64 #include <errno.h>
65 #include <fcntl.h>
66 #include <paths.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <unistd.h>
71
72 #define IPLSIZE                 512             /* IPL size */
73 #define BOOTMENUSIZE            7168            /* Max HDD boot menu size */
74 #define BOOTMENUOFF             0x400
75
76 static  char *mkrdev(char *);
77 static  void usage(void);
78
79 u_char  boot0buf[0x2000];
80 char    ipl[IPLSIZE];
81 char    menu[BOOTMENUSIZE];
82
83 /*
84  * Produce a device path for a "canonical" name, where appropriate.
85  */
86 static char *
87 mkrdev(char *fname)
88 {
89     char buf[MAXPATHLEN];
90     struct stat sb;
91     char *s;
92
93     s = (char *)fname;
94     if (!strchr(fname, '/')) {
95         snprintf(buf, sizeof(buf), "%sr%s", _PATH_DEV, fname);
96         if (stat(buf, &sb))
97             snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);
98         if (!(s = strdup(buf)))
99             err(1, NULL);
100     }
101     return s;
102 }
103
104 static void
105 usage(void)
106 {
107         fprintf(stderr,
108             "boot98cfg [-B][-i boot0][-m boot0.5][-s secsize][-v version]\n"
109             "          [-f ipl.bak][-F menu.bak] disk\n");
110         exit(1);
111 }
112
113 int
114 main(int argc, char *argv[])
115 {
116         char    *endptr;
117         const   char *iplpath = "/boot/boot0", *menupath = "/boot/boot0.5";
118         char    *iplbakpath = NULL, *menubakpath = NULL;
119         char    *disk;
120         int     B_flag = 0;
121         int     c;
122         int     fd, fd1;
123         int     n;
124         int     secsize = 512;
125         int     v_flag = 0, version;
126
127         while ((c = getopt(argc, argv, "BF:f:i:m:s:v:")) != -1) {
128                 switch (c) {
129                 case 'B':
130                         B_flag = 1;
131                         break;
132                 case 'F':
133                         menubakpath = optarg;
134                         break;
135                 case 'f':
136                         iplbakpath = optarg;
137                         break;
138                 case 'i':
139                         iplpath = optarg;
140                         break;
141                 case 'm':
142                         menupath = optarg;
143                         break;
144                 case 's':
145                         secsize = strtol(optarg, &endptr, 0);
146                         if (errno || *optarg == NULL || *endptr)
147                                 errx(1, "%s: Bad argument to -s option",
148                                     optarg);
149                         switch (secsize) {
150                         case 256:
151                         case 512:
152                         case 1024:
153                         case 2048:
154                                 break;
155                         default:
156                                 errx(1, "%s: unsupported sector size", optarg);
157                                 break;
158                         }
159                         break;
160                 case 'v':
161                         v_flag = 1;
162                         version = strtol(optarg, &endptr, 0);
163                         if (errno || *optarg == NULL || *endptr ||
164                             version < 0 || version > 255)
165                                 errx(1, "%s: Bad argument to -s option",
166                                     optarg);
167                         break;
168                 default:
169                         usage();
170                         /* NOTREACHED */
171                         break;
172                 }
173         }
174         argc -= optind;
175         argv += optind;
176         if (argc != 1)
177                 usage();
178         disk = mkrdev(*argv);
179
180         /* Read IPL, partition table and HDD boot menu. */
181         fd = open(disk, O_RDWR);
182         if (fd < 0)
183                 err(1, "%s", disk);
184         n = read(fd, boot0buf, 0x2000);
185         if (n != 0x2000)
186                 errx(1, "%s: short read", disk);
187         if (!B_flag && !v_flag)
188                 close(fd);
189
190         if (iplbakpath != NULL) {
191                 fd1 = open(iplbakpath, O_WRONLY | O_CREAT | O_TRUNC, 0666);
192                 if (fd1 < 0)
193                         err(1, "%s", iplbakpath);
194                 n = write(fd1, boot0buf, IPLSIZE);
195                 if (n == -1)
196                         err(1, "%s", iplbakpath);
197                 if (n != IPLSIZE)
198                         errx(1, "%s: short write", iplbakpath);
199                 close(fd1);
200         }
201
202         if (menubakpath != NULL) {
203                 fd1 = open(menubakpath, O_WRONLY | O_CREAT | O_TRUNC, 0666);
204                 if (fd1 < 0)
205                         err(1, "%s", menubakpath);
206                 n = write(fd1, boot0buf + BOOTMENUOFF, BOOTMENUSIZE);
207                 if (n == -1)
208                         err(1, "%s", menubakpath);
209                 if (n != BOOTMENUSIZE)
210                         errx(1, "%s: short write", menubakpath);
211                 close(fd1);
212         }
213
214         if (B_flag) {
215                 /* Read IPL (boot0). */
216                 fd1 = open(iplpath, O_RDONLY);
217                 if (fd1 < 0)
218                         err(1, "%s", disk);
219                 n = read(fd1, ipl, IPLSIZE);
220                 if (n < 0)
221                         err(1, "%s", iplpath);
222                 if (n != IPLSIZE)
223                         errx(1, "%s: invalid file", iplpath);
224                 close(fd1);
225
226                 /* Read HDD boot menu (boot0.5). */
227                 fd1 = open(menupath, O_RDONLY);
228                 if (fd1 < 0)
229                         err(1, "%s", disk);
230                 n = read(fd1, menu, BOOTMENUSIZE);
231                 if (n < 0)
232                         err(1, "%s", menupath);
233                 if (n != BOOTMENUSIZE)
234                         errx(1, "%s: invalid file", menupath);
235                 close(fd1);
236
237                 memcpy(boot0buf, ipl, IPLSIZE);
238                 memcpy(boot0buf + BOOTMENUOFF, menu, BOOTMENUSIZE);
239         }
240
241         /* Set version number field. */
242         if (v_flag)
243                 *(boot0buf + secsize - 4) = (u_char)version;
244
245         if (B_flag || v_flag) {
246                 if (lseek(fd, 0, SEEK_SET) == -1 ||
247                     (n = write(fd, boot0buf, 0x2000)) < 0 ||
248                     close(fd))
249                         err(1, "%s", disk);
250                 if (n != 0x2000)
251                         errx(1, "%s: short write", disk);
252         }
253         
254         return 0;
255 }