cd9660.c revision 1.2 1 1.2 tsutsui /* $NetBSD: cd9660.c,v 1.2 2024/05/24 09:59:42 tsutsui Exp $ */
2 1.1 tsutsui
3 1.1 tsutsui /*-
4 1.1 tsutsui * Copyright (c) 2005 Izumi Tsutsui. All rights reserved.
5 1.1 tsutsui *
6 1.1 tsutsui * Redistribution and use in source and binary forms, with or without
7 1.1 tsutsui * modification, are permitted provided that the following conditions
8 1.1 tsutsui * are met:
9 1.1 tsutsui * 1. Redistributions of source code must retain the above copyright
10 1.1 tsutsui * notice, this list of conditions and the following disclaimer.
11 1.1 tsutsui * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 tsutsui * notice, this list of conditions and the following disclaimer in the
13 1.1 tsutsui * documentation and/or other materials provided with the distribution.
14 1.1 tsutsui *
15 1.1 tsutsui * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 1.1 tsutsui * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 1.1 tsutsui * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 1.1 tsutsui * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 1.1 tsutsui * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 1.1 tsutsui * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 1.1 tsutsui * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 1.1 tsutsui * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 1.1 tsutsui * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 1.1 tsutsui * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 1.1 tsutsui */
26 1.1 tsutsui
27 1.1 tsutsui #if HAVE_NBTOOL_CONFIG_H
28 1.1 tsutsui #include "nbtool_config.h"
29 1.1 tsutsui #endif
30 1.1 tsutsui
31 1.1 tsutsui #include <sys/cdefs.h>
32 1.1 tsutsui #if defined(__RCSID) && !defined(__lint)
33 1.2 tsutsui __RCSID("$NetBSD: cd9660.c,v 1.2 2024/05/24 09:59:42 tsutsui Exp $");
34 1.1 tsutsui #endif /* !__lint */
35 1.1 tsutsui
36 1.1 tsutsui #include <sys/param.h>
37 1.1 tsutsui
38 1.1 tsutsui #if !HAVE_NBTOOL_CONFIG_H
39 1.1 tsutsui #include <sys/mount.h>
40 1.1 tsutsui #endif
41 1.2 tsutsui #if !HAVE_NBTOOL_CONFIG_H || HAVE_SYS_ENDIAN_H
42 1.2 tsutsui #include <sys/endian.h>
43 1.2 tsutsui #endif
44 1.1 tsutsui
45 1.1 tsutsui #include <assert.h>
46 1.1 tsutsui #include <err.h>
47 1.1 tsutsui #include <errno.h>
48 1.1 tsutsui #include <fcntl.h>
49 1.1 tsutsui #include <stdarg.h>
50 1.1 tsutsui #include <stdio.h>
51 1.1 tsutsui #include <stdlib.h>
52 1.1 tsutsui #include <string.h>
53 1.1 tsutsui #include <unistd.h>
54 1.1 tsutsui #include <dirent.h>
55 1.1 tsutsui
56 1.1 tsutsui #include <fs/cd9660/iso.h>
57 1.1 tsutsui #include <fs/cd9660/cd9660_extern.h>
58 1.1 tsutsui
59 1.1 tsutsui #include "installboot.h"
60 1.1 tsutsui
61 1.1 tsutsui #define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
62 1.1 tsutsui #define MAXLEN 16
63 1.1 tsutsui
64 1.1 tsutsui
65 1.1 tsutsui int
66 1.1 tsutsui cd9660_match(ib_params *params)
67 1.1 tsutsui {
68 1.1 tsutsui int rv, blocksize;
69 1.1 tsutsui struct iso_primary_descriptor ipd;
70 1.1 tsutsui
71 1.1 tsutsui assert(params != NULL);
72 1.1 tsutsui assert(params->fstype != NULL);
73 1.1 tsutsui assert(params->fsfd != -1);
74 1.1 tsutsui
75 1.1 tsutsui rv = pread(params->fsfd, &ipd, sizeof(ipd),
76 1.1 tsutsui ISO_DEFAULT_BLOCK_SIZE * 16);
77 1.1 tsutsui if (rv == -1) {
78 1.1 tsutsui warn("Reading primary descriptor in `%s'", params->filesystem);
79 1.1 tsutsui return 0;
80 1.1 tsutsui } else if (rv != sizeof(ipd)) {
81 1.1 tsutsui warnx("Reading primary descriptor in `%s': short read",
82 1.1 tsutsui params->filesystem);
83 1.1 tsutsui return 0;
84 1.1 tsutsui }
85 1.1 tsutsui
86 1.1 tsutsui if (ipd.type[0] != ISO_VD_PRIMARY ||
87 1.1 tsutsui strncmp(ipd.id, ISO_STANDARD_ID, sizeof(ipd.id)) != 0 ||
88 1.1 tsutsui ipd.version[0] != 1) {
89 1.1 tsutsui warnx("Filesystem `%s' is not ISO9660 format",
90 1.1 tsutsui params->filesystem);
91 1.1 tsutsui return 0;
92 1.1 tsutsui }
93 1.1 tsutsui
94 1.1 tsutsui blocksize = isonum_723((u_char *)ipd.logical_block_size);
95 1.1 tsutsui if (blocksize != ISO_DEFAULT_BLOCK_SIZE) {
96 1.1 tsutsui warnx("Invalid blocksize %d in `%s'",
97 1.1 tsutsui blocksize, params->filesystem);
98 1.1 tsutsui return 0;
99 1.1 tsutsui }
100 1.1 tsutsui
101 1.1 tsutsui params->fstype->blocksize = blocksize;
102 1.1 tsutsui params->fstype->needswap = 0;
103 1.1 tsutsui
104 1.1 tsutsui return 1;
105 1.1 tsutsui }
106 1.1 tsutsui
107 1.1 tsutsui int
108 1.1 tsutsui cd9660_findstage2(ib_params *params, uint32_t *maxblk, ib_block *blocks)
109 1.1 tsutsui {
110 1.1 tsutsui uint8_t buf[ISO_DEFAULT_BLOCK_SIZE];
111 1.1 tsutsui char name[ISO_MAXNAMLEN];
112 1.1 tsutsui char *stage2;
113 1.1 tsutsui off_t loc;
114 1.1 tsutsui int rv, blocksize, found;
115 1.1 tsutsui u_int i;
116 1.1 tsutsui struct iso_primary_descriptor ipd;
117 1.1 tsutsui struct iso_directory_record *idr;
118 1.1 tsutsui
119 1.1 tsutsui assert(params != NULL);
120 1.1 tsutsui assert(params->stage2 != NULL);
121 1.1 tsutsui assert(maxblk != NULL);
122 1.1 tsutsui assert(blocks != NULL);
123 1.1 tsutsui
124 1.1 tsutsui #if 0
125 1.1 tsutsui if (params->flags & IB_STAGE2START)
126 1.1 tsutsui return hardcode_stage2(params, maxblk, blocks);
127 1.1 tsutsui #endif
128 1.1 tsutsui
129 1.1 tsutsui /* The secondary bootstrap must be clearly in /. */
130 1.1 tsutsui strlcpy(name, params->stage2, ISO_MAXNAMLEN);
131 1.1 tsutsui stage2 = name;
132 1.1 tsutsui if (stage2[0] == '/')
133 1.1 tsutsui stage2++;
134 1.1 tsutsui if (strchr(stage2, '/') != NULL) {
135 1.1 tsutsui warnx("The secondary bootstrap `%s' must be in / "
136 1.1 tsutsui "on filesystem `%s'", params->stage2, params->filesystem);
137 1.1 tsutsui return 0;
138 1.1 tsutsui }
139 1.1 tsutsui if (strchr(stage2, '.') == NULL) {
140 1.1 tsutsui /*
141 1.1 tsutsui * XXX should fix isofncmp()?
142 1.1 tsutsui */
143 1.1 tsutsui strlcat(name, ".", ISO_MAXNAMLEN);
144 1.1 tsutsui }
145 1.1 tsutsui
146 1.1 tsutsui rv = pread(params->fsfd, &ipd, sizeof(ipd),
147 1.1 tsutsui ISO_DEFAULT_BLOCK_SIZE * 16);
148 1.1 tsutsui if (rv == -1) {
149 1.1 tsutsui warn("Reading primary descriptor in `%s'", params->filesystem);
150 1.1 tsutsui return 0;
151 1.1 tsutsui } else if (rv != sizeof(ipd)) {
152 1.1 tsutsui warnx("Reading primary descriptor in `%s': short read",
153 1.1 tsutsui params->filesystem);
154 1.1 tsutsui return 0;
155 1.1 tsutsui }
156 1.1 tsutsui blocksize = isonum_723((u_char *)ipd.logical_block_size);
157 1.1 tsutsui
158 1.1 tsutsui idr = (void *)ipd.root_directory_record;
159 1.1 tsutsui loc = (off_t)isonum_733(idr->extent) * blocksize;
160 1.1 tsutsui rv = pread(params->fsfd, buf, blocksize, loc);
161 1.1 tsutsui if (rv == -1) {
162 1.1 tsutsui warn("Reading root directory record in `%s'",
163 1.1 tsutsui params->filesystem);
164 1.1 tsutsui return 0;
165 1.1 tsutsui } else if (rv != sizeof(ipd)) {
166 1.1 tsutsui warnx("Reading root directory record in `%s': short read",
167 1.1 tsutsui params->filesystem);
168 1.1 tsutsui return 0;
169 1.1 tsutsui }
170 1.1 tsutsui
171 1.1 tsutsui found = 0;
172 1.1 tsutsui for (i = 0; i < blocksize - sizeof(struct iso_directory_record);
173 1.1 tsutsui i += (u_char)idr->length[0]) {
174 1.1 tsutsui idr = (void *)&buf[i];
175 1.1 tsutsui
176 1.1 tsutsui #ifdef DEBUG
177 1.1 tsutsui printf("i = %d, idr->length[0] = %3d\n",
178 1.1 tsutsui i, (u_char)idr->length[0]);
179 1.1 tsutsui #endif
180 1.1 tsutsui /* check end of entries */
181 1.1 tsutsui if (idr->length[0] == 0) {
182 1.1 tsutsui #ifdef DEBUG
183 1.1 tsutsui printf("end of entries\n");
184 1.1 tsutsui #endif
185 1.1 tsutsui break;
186 1.1 tsutsui }
187 1.1 tsutsui
188 1.1 tsutsui if (idr->flags[0] & 2) {
189 1.1 tsutsui /* skip directory entries */
190 1.1 tsutsui #ifdef DEBUG
191 1.1 tsutsui printf("skip directory entry\n");
192 1.1 tsutsui #endif
193 1.1 tsutsui continue;
194 1.1 tsutsui }
195 1.1 tsutsui if (idr->name_len[0] == 1 &&
196 1.1 tsutsui (idr->name[0] == 0 || idr->name[0] == 1)) {
197 1.1 tsutsui /* skip "." and ".." */
198 1.1 tsutsui #ifdef DEBUG
199 1.1 tsutsui printf("skip dot dot\n");
200 1.1 tsutsui #endif
201 1.1 tsutsui continue;
202 1.1 tsutsui }
203 1.1 tsutsui #ifdef DEBUG
204 1.1 tsutsui {
205 1.1 tsutsui int j;
206 1.1 tsutsui
207 1.1 tsutsui printf("filename:");
208 1.1 tsutsui for (j = 0; j < isonum_711(idr->name_len); j++)
209 1.1 tsutsui printf("%c", idr->name[j]);
210 1.1 tsutsui printf("\n");
211 1.1 tsutsui }
212 1.1 tsutsui #endif
213 1.1 tsutsui if (isofncmp((u_char *)stage2, strlen(stage2),
214 1.1 tsutsui (u_char *)idr->name,
215 1.1 tsutsui isonum_711((u_char *)idr->name_len), 0) == 0) {
216 1.1 tsutsui found = 1;
217 1.1 tsutsui /* ISO filesystem always has contiguous file blocks */
218 1.1 tsutsui blocks[0].block = (int64_t)isonum_733(idr->extent);
219 1.1 tsutsui blocks[0].blocksize =
220 1.1 tsutsui roundup(isonum_733(idr->size), blocksize);
221 1.1 tsutsui *maxblk = 1;
222 1.1 tsutsui #ifdef DEBUG
223 1.1 tsutsui printf("block = %ld, blocksize = %ld\n",
224 1.1 tsutsui (long)blocks[0].block, blocks[0].blocksize);
225 1.1 tsutsui #endif
226 1.1 tsutsui break;
227 1.1 tsutsui }
228 1.1 tsutsui }
229 1.1 tsutsui
230 1.1 tsutsui if (found == 0) {
231 1.1 tsutsui warnx("Can't find secondary bootstrap `%s' in filesystem `%s'",
232 1.1 tsutsui params->stage2, params->filesystem);
233 1.1 tsutsui return 0;
234 1.1 tsutsui }
235 1.1 tsutsui
236 1.1 tsutsui return 1;
237 1.1 tsutsui }
238