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