1*2e1ec386Stsutsui /* $NetBSD: cd9660.c,v 1.2 2024/05/24 09:59:42 tsutsui Exp $ */
24882e3f0Stsutsui
34882e3f0Stsutsui /*-
44882e3f0Stsutsui * Copyright (c) 2005 Izumi Tsutsui. All rights reserved.
54882e3f0Stsutsui *
64882e3f0Stsutsui * Redistribution and use in source and binary forms, with or without
74882e3f0Stsutsui * modification, are permitted provided that the following conditions
84882e3f0Stsutsui * are met:
94882e3f0Stsutsui * 1. Redistributions of source code must retain the above copyright
104882e3f0Stsutsui * notice, this list of conditions and the following disclaimer.
114882e3f0Stsutsui * 2. Redistributions in binary form must reproduce the above copyright
124882e3f0Stsutsui * notice, this list of conditions and the following disclaimer in the
134882e3f0Stsutsui * documentation and/or other materials provided with the distribution.
144882e3f0Stsutsui *
154882e3f0Stsutsui * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
164882e3f0Stsutsui * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
174882e3f0Stsutsui * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
184882e3f0Stsutsui * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
194882e3f0Stsutsui * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
204882e3f0Stsutsui * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
214882e3f0Stsutsui * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
224882e3f0Stsutsui * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
234882e3f0Stsutsui * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
244882e3f0Stsutsui * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
254882e3f0Stsutsui */
264882e3f0Stsutsui
274882e3f0Stsutsui #if HAVE_NBTOOL_CONFIG_H
284882e3f0Stsutsui #include "nbtool_config.h"
294882e3f0Stsutsui #endif
304882e3f0Stsutsui
314882e3f0Stsutsui #include <sys/cdefs.h>
324882e3f0Stsutsui #if defined(__RCSID) && !defined(__lint)
33*2e1ec386Stsutsui __RCSID("$NetBSD: cd9660.c,v 1.2 2024/05/24 09:59:42 tsutsui Exp $");
344882e3f0Stsutsui #endif /* !__lint */
354882e3f0Stsutsui
364882e3f0Stsutsui #include <sys/param.h>
374882e3f0Stsutsui
384882e3f0Stsutsui #if !HAVE_NBTOOL_CONFIG_H
394882e3f0Stsutsui #include <sys/mount.h>
404882e3f0Stsutsui #endif
41*2e1ec386Stsutsui #if !HAVE_NBTOOL_CONFIG_H || HAVE_SYS_ENDIAN_H
42*2e1ec386Stsutsui #include <sys/endian.h>
43*2e1ec386Stsutsui #endif
444882e3f0Stsutsui
454882e3f0Stsutsui #include <assert.h>
464882e3f0Stsutsui #include <err.h>
474882e3f0Stsutsui #include <errno.h>
484882e3f0Stsutsui #include <fcntl.h>
494882e3f0Stsutsui #include <stdarg.h>
504882e3f0Stsutsui #include <stdio.h>
514882e3f0Stsutsui #include <stdlib.h>
524882e3f0Stsutsui #include <string.h>
534882e3f0Stsutsui #include <unistd.h>
544882e3f0Stsutsui #include <dirent.h>
554882e3f0Stsutsui
564882e3f0Stsutsui #include <fs/cd9660/iso.h>
574882e3f0Stsutsui #include <fs/cd9660/cd9660_extern.h>
584882e3f0Stsutsui
594882e3f0Stsutsui #include "installboot.h"
604882e3f0Stsutsui
614882e3f0Stsutsui #define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
624882e3f0Stsutsui #define MAXLEN 16
634882e3f0Stsutsui
644882e3f0Stsutsui
654882e3f0Stsutsui int
cd9660_match(ib_params * params)664882e3f0Stsutsui cd9660_match(ib_params *params)
674882e3f0Stsutsui {
684882e3f0Stsutsui int rv, blocksize;
694882e3f0Stsutsui struct iso_primary_descriptor ipd;
704882e3f0Stsutsui
714882e3f0Stsutsui assert(params != NULL);
724882e3f0Stsutsui assert(params->fstype != NULL);
734882e3f0Stsutsui assert(params->fsfd != -1);
744882e3f0Stsutsui
754882e3f0Stsutsui rv = pread(params->fsfd, &ipd, sizeof(ipd),
764882e3f0Stsutsui ISO_DEFAULT_BLOCK_SIZE * 16);
774882e3f0Stsutsui if (rv == -1) {
784882e3f0Stsutsui warn("Reading primary descriptor in `%s'", params->filesystem);
794882e3f0Stsutsui return 0;
804882e3f0Stsutsui } else if (rv != sizeof(ipd)) {
814882e3f0Stsutsui warnx("Reading primary descriptor in `%s': short read",
824882e3f0Stsutsui params->filesystem);
834882e3f0Stsutsui return 0;
844882e3f0Stsutsui }
854882e3f0Stsutsui
864882e3f0Stsutsui if (ipd.type[0] != ISO_VD_PRIMARY ||
874882e3f0Stsutsui strncmp(ipd.id, ISO_STANDARD_ID, sizeof(ipd.id)) != 0 ||
884882e3f0Stsutsui ipd.version[0] != 1) {
894882e3f0Stsutsui warnx("Filesystem `%s' is not ISO9660 format",
904882e3f0Stsutsui params->filesystem);
914882e3f0Stsutsui return 0;
924882e3f0Stsutsui }
934882e3f0Stsutsui
944882e3f0Stsutsui blocksize = isonum_723((u_char *)ipd.logical_block_size);
954882e3f0Stsutsui if (blocksize != ISO_DEFAULT_BLOCK_SIZE) {
964882e3f0Stsutsui warnx("Invalid blocksize %d in `%s'",
974882e3f0Stsutsui blocksize, params->filesystem);
984882e3f0Stsutsui return 0;
994882e3f0Stsutsui }
1004882e3f0Stsutsui
1014882e3f0Stsutsui params->fstype->blocksize = blocksize;
1024882e3f0Stsutsui params->fstype->needswap = 0;
1034882e3f0Stsutsui
1044882e3f0Stsutsui return 1;
1054882e3f0Stsutsui }
1064882e3f0Stsutsui
1074882e3f0Stsutsui int
cd9660_findstage2(ib_params * params,uint32_t * maxblk,ib_block * blocks)1084882e3f0Stsutsui cd9660_findstage2(ib_params *params, uint32_t *maxblk, ib_block *blocks)
1094882e3f0Stsutsui {
1104882e3f0Stsutsui uint8_t buf[ISO_DEFAULT_BLOCK_SIZE];
1114882e3f0Stsutsui char name[ISO_MAXNAMLEN];
1124882e3f0Stsutsui char *stage2;
1134882e3f0Stsutsui off_t loc;
1144882e3f0Stsutsui int rv, blocksize, found;
1154882e3f0Stsutsui u_int i;
1164882e3f0Stsutsui struct iso_primary_descriptor ipd;
1174882e3f0Stsutsui struct iso_directory_record *idr;
1184882e3f0Stsutsui
1194882e3f0Stsutsui assert(params != NULL);
1204882e3f0Stsutsui assert(params->stage2 != NULL);
1214882e3f0Stsutsui assert(maxblk != NULL);
1224882e3f0Stsutsui assert(blocks != NULL);
1234882e3f0Stsutsui
1244882e3f0Stsutsui #if 0
1254882e3f0Stsutsui if (params->flags & IB_STAGE2START)
1264882e3f0Stsutsui return hardcode_stage2(params, maxblk, blocks);
1274882e3f0Stsutsui #endif
1284882e3f0Stsutsui
1294882e3f0Stsutsui /* The secondary bootstrap must be clearly in /. */
1304882e3f0Stsutsui strlcpy(name, params->stage2, ISO_MAXNAMLEN);
1314882e3f0Stsutsui stage2 = name;
1324882e3f0Stsutsui if (stage2[0] == '/')
1334882e3f0Stsutsui stage2++;
1344882e3f0Stsutsui if (strchr(stage2, '/') != NULL) {
1354882e3f0Stsutsui warnx("The secondary bootstrap `%s' must be in / "
1364882e3f0Stsutsui "on filesystem `%s'", params->stage2, params->filesystem);
1374882e3f0Stsutsui return 0;
1384882e3f0Stsutsui }
1394882e3f0Stsutsui if (strchr(stage2, '.') == NULL) {
1404882e3f0Stsutsui /*
1414882e3f0Stsutsui * XXX should fix isofncmp()?
1424882e3f0Stsutsui */
1434882e3f0Stsutsui strlcat(name, ".", ISO_MAXNAMLEN);
1444882e3f0Stsutsui }
1454882e3f0Stsutsui
1464882e3f0Stsutsui rv = pread(params->fsfd, &ipd, sizeof(ipd),
1474882e3f0Stsutsui ISO_DEFAULT_BLOCK_SIZE * 16);
1484882e3f0Stsutsui if (rv == -1) {
1494882e3f0Stsutsui warn("Reading primary descriptor in `%s'", params->filesystem);
1504882e3f0Stsutsui return 0;
1514882e3f0Stsutsui } else if (rv != sizeof(ipd)) {
1524882e3f0Stsutsui warnx("Reading primary descriptor in `%s': short read",
1534882e3f0Stsutsui params->filesystem);
1544882e3f0Stsutsui return 0;
1554882e3f0Stsutsui }
1564882e3f0Stsutsui blocksize = isonum_723((u_char *)ipd.logical_block_size);
1574882e3f0Stsutsui
1584882e3f0Stsutsui idr = (void *)ipd.root_directory_record;
1594882e3f0Stsutsui loc = (off_t)isonum_733(idr->extent) * blocksize;
1604882e3f0Stsutsui rv = pread(params->fsfd, buf, blocksize, loc);
1614882e3f0Stsutsui if (rv == -1) {
1624882e3f0Stsutsui warn("Reading root directory record in `%s'",
1634882e3f0Stsutsui params->filesystem);
1644882e3f0Stsutsui return 0;
1654882e3f0Stsutsui } else if (rv != sizeof(ipd)) {
1664882e3f0Stsutsui warnx("Reading root directory record in `%s': short read",
1674882e3f0Stsutsui params->filesystem);
1684882e3f0Stsutsui return 0;
1694882e3f0Stsutsui }
1704882e3f0Stsutsui
1714882e3f0Stsutsui found = 0;
1724882e3f0Stsutsui for (i = 0; i < blocksize - sizeof(struct iso_directory_record);
1734882e3f0Stsutsui i += (u_char)idr->length[0]) {
1744882e3f0Stsutsui idr = (void *)&buf[i];
1754882e3f0Stsutsui
1764882e3f0Stsutsui #ifdef DEBUG
1774882e3f0Stsutsui printf("i = %d, idr->length[0] = %3d\n",
1784882e3f0Stsutsui i, (u_char)idr->length[0]);
1794882e3f0Stsutsui #endif
1804882e3f0Stsutsui /* check end of entries */
1814882e3f0Stsutsui if (idr->length[0] == 0) {
1824882e3f0Stsutsui #ifdef DEBUG
1834882e3f0Stsutsui printf("end of entries\n");
1844882e3f0Stsutsui #endif
1854882e3f0Stsutsui break;
1864882e3f0Stsutsui }
1874882e3f0Stsutsui
1884882e3f0Stsutsui if (idr->flags[0] & 2) {
1894882e3f0Stsutsui /* skip directory entries */
1904882e3f0Stsutsui #ifdef DEBUG
1914882e3f0Stsutsui printf("skip directory entry\n");
1924882e3f0Stsutsui #endif
1934882e3f0Stsutsui continue;
1944882e3f0Stsutsui }
1954882e3f0Stsutsui if (idr->name_len[0] == 1 &&
1964882e3f0Stsutsui (idr->name[0] == 0 || idr->name[0] == 1)) {
1974882e3f0Stsutsui /* skip "." and ".." */
1984882e3f0Stsutsui #ifdef DEBUG
1994882e3f0Stsutsui printf("skip dot dot\n");
2004882e3f0Stsutsui #endif
2014882e3f0Stsutsui continue;
2024882e3f0Stsutsui }
2034882e3f0Stsutsui #ifdef DEBUG
2044882e3f0Stsutsui {
2054882e3f0Stsutsui int j;
2064882e3f0Stsutsui
2074882e3f0Stsutsui printf("filename:");
2084882e3f0Stsutsui for (j = 0; j < isonum_711(idr->name_len); j++)
2094882e3f0Stsutsui printf("%c", idr->name[j]);
2104882e3f0Stsutsui printf("\n");
2114882e3f0Stsutsui }
2124882e3f0Stsutsui #endif
2134882e3f0Stsutsui if (isofncmp((u_char *)stage2, strlen(stage2),
2144882e3f0Stsutsui (u_char *)idr->name,
2154882e3f0Stsutsui isonum_711((u_char *)idr->name_len), 0) == 0) {
2164882e3f0Stsutsui found = 1;
2174882e3f0Stsutsui /* ISO filesystem always has contiguous file blocks */
2184882e3f0Stsutsui blocks[0].block = (int64_t)isonum_733(idr->extent);
2194882e3f0Stsutsui blocks[0].blocksize =
2204882e3f0Stsutsui roundup(isonum_733(idr->size), blocksize);
2214882e3f0Stsutsui *maxblk = 1;
2224882e3f0Stsutsui #ifdef DEBUG
2234882e3f0Stsutsui printf("block = %ld, blocksize = %ld\n",
2244882e3f0Stsutsui (long)blocks[0].block, blocks[0].blocksize);
2254882e3f0Stsutsui #endif
2264882e3f0Stsutsui break;
2274882e3f0Stsutsui }
2284882e3f0Stsutsui }
2294882e3f0Stsutsui
2304882e3f0Stsutsui if (found == 0) {
2314882e3f0Stsutsui warnx("Can't find secondary bootstrap `%s' in filesystem `%s'",
2324882e3f0Stsutsui params->stage2, params->filesystem);
2334882e3f0Stsutsui return 0;
2344882e3f0Stsutsui }
2354882e3f0Stsutsui
2364882e3f0Stsutsui return 1;
2374882e3f0Stsutsui }
238