xref: /netbsd-src/usr.sbin/installboot/cd9660.c (revision 2e1ec38629f94cfdb19ca2dfee185edcf77cb51c)
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