Home | History | Annotate | Line # | Download | only in newfs_udf
newfs_udf.c revision 1.23
      1 /* $NetBSD: newfs_udf.c,v 1.23 2022/04/06 13:29:15 reinoud Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2006, 2008, 2013, 2021, 2022 Reinoud Zandijk
      5  * All rights reserved.
      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  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  *
     27  */
     28 
     29 /*
     30  * TODO
     31  * - implement metadata formatting for BD-R
     32  * - implement support for a read-only companion partition?
     33  */
     34 
     35 #define _EXPOSE_MMC
     36 #if 0
     37 # define DEBUG
     38 #endif
     39 
     40 #include <stdio.h>
     41 #include <stdlib.h>
     42 #include <dirent.h>
     43 #include <inttypes.h>
     44 #include <stdint.h>
     45 #include <string.h>
     46 #include <errno.h>
     47 #include <fcntl.h>
     48 #include <unistd.h>
     49 #include <util.h>
     50 #include <time.h>
     51 #include <assert.h>
     52 #include <err.h>
     53 
     54 #include <sys/ioctl.h>
     55 #include <sys/stat.h>
     56 #include <sys/types.h>
     57 #include <sys/cdio.h>
     58 #include <sys/disklabel.h>
     59 #include <sys/dkio.h>
     60 #include <sys/param.h>
     61 
     62 #include <fs/udf/udf_mount.h>
     63 
     64 #include "mountprog.h"
     65 #include "udf_core.h"
     66 #include "newfs_udf.h"
     67 
     68 /* Identifying myself */
     69 #define IMPL_NAME		"*NetBSD newfs_udf 10.0"
     70 #define APP_VERSION_MAIN	0
     71 #define APP_VERSION_SUB		5
     72 
     73 /* prototypes */
     74 int newfs_udf(int argc, char **argv);
     75 static void usage(void) __attribute__((__noreturn__));
     76 
     77 /* global variables describing disc and format requests */
     78 char	*format_str;			/* format: string representation */
     79 
     80 
     81 /* --------------------------------------------------------------------- */
     82 
     83 static int
     84 udf_prepare_format_track512(void)
     85 {
     86 	struct mmc_trackinfo ti;
     87 	struct mmc_op        op;
     88 	int error;
     89 
     90 	if (!(context.format_flags & FORMAT_TRACK512))
     91 		return 0;
     92 
     93 	/* get last track (again) */
     94 	ti.tracknr = mmc_discinfo.last_track_last_session;
     95 	error = udf_update_trackinfo(&ti);
     96 	if (error)
     97 		return error;
     98 
     99 	/* Split up the space at 512 for iso cd9660 hooking */
    100 	memset(&op, 0, sizeof(op));
    101 	op.operation   = MMC_OP_RESERVETRACK_NWA;	/* UPTO nwa */
    102 	op.mmc_profile = mmc_discinfo.mmc_profile;
    103 	op.extent      = 512;				/* size */
    104 	error = ioctl(dev_fd, MMCOP, &op);
    105 
    106 	return error;
    107 }
    108 
    109 /* --------------------------------------------------------------------- */
    110 
    111 static int
    112 udf_do_newfs(void)
    113 {
    114 	int error;
    115 
    116 	error = udf_do_newfs_prefix();
    117 	if (error)
    118 		return error;
    119 	error = udf_do_rootdir();
    120 	if (error)
    121 		return error;
    122 	error = udf_do_newfs_postfix();
    123 
    124 	return error;
    125 }
    126 
    127 /* --------------------------------------------------------------------- */
    128 
    129 static void
    130 usage(void)
    131 {
    132 	(void)fprintf(stderr, "Usage: %s [-cFM] [-L loglabel] "
    133 	    "[-P discid] [-S sectorsize] [-s size] [-p perc] "
    134 	    "[-t gmtoff] [-v min_udf] [-V max_udf] special\n", getprogname());
    135 	exit(EXIT_FAILURE);
    136 }
    137 
    138 
    139 int
    140 main(int argc, char **argv)
    141 {
    142 	struct tm *tm;
    143 	time_t now;
    144 	off_t setsize;
    145 	char  scrap[255], *colon;
    146 	int ch, req_enable, req_disable;
    147 	int error;
    148 
    149 	setprogname(argv[0]);
    150 
    151 	/* initialise */
    152 	format_str    = strdup("");
    153 	req_enable    = req_disable = 0;
    154 	setsize       = 0;
    155 
    156 	emul_mmc_profile  =  -1;	/* invalid->no emulation	*/
    157 	emul_packetsize   =   1;	/* reasonable default		*/
    158 	emul_sectorsize   = 512;	/* minimum allowed sector size	*/
    159 	emul_size	  =   0;	/* empty			*/
    160 
    161 	srandom((unsigned long) time(NULL));
    162 	udf_init_create_context();
    163 	context.app_name         = "*NetBSD UDF";
    164 	context.app_version_main = APP_VERSION_MAIN;
    165 	context.app_version_sub  = APP_VERSION_SUB;
    166 	context.impl_name        = IMPL_NAME;
    167 
    168 	/* minimum and maximum UDF versions we advise */
    169 	context.min_udf = 0x201;
    170 	context.max_udf = 0x250;
    171 
    172 	/* use user's time zone as default */
    173 	(void)time(&now);
    174 	tm = localtime(&now);
    175 	context.gmtoff = tm->tm_gmtoff;
    176 
    177 	/* process options */
    178 	while ((ch = getopt(argc, argv, "cFL:Mp:P:s:S:B:t:v:V:")) != -1) {
    179 		switch (ch) {
    180 		case 'c' :
    181 			context.check_surface = 1;
    182 			break;
    183 		case 'F' :
    184 			context.create_new_session = 1;
    185 			break;
    186 		case 'L' :
    187 			if (context.logvol_name) free(context.logvol_name);
    188 			context.logvol_name = strdup(optarg);
    189 			break;
    190 		case 'M' :
    191 			req_disable |= FORMAT_META;
    192 			break;
    193 		case 'p' :
    194 			context.meta_perc = a_num(optarg, "meta_perc");
    195 			/* limit to `sensible` values */
    196 			context.meta_perc = MIN(context.meta_perc, 99);
    197 			context.meta_perc = MAX(context.meta_perc, 1);
    198 			break;
    199 		case 'v' :
    200 			context.min_udf = a_udf_version(optarg, "min_udf");
    201 			if (context.min_udf > context.max_udf)
    202 				context.max_udf = context.min_udf;
    203 			break;
    204 		case 'V' :
    205 			context.max_udf = a_udf_version(optarg, "max_udf");
    206 			if (context.min_udf > context.max_udf)
    207 				context.min_udf = context.max_udf;
    208 			break;
    209 		case 'P' :
    210 			/* check if there is a ':' in the name */
    211 			if ((colon = strstr(optarg, ":"))) {
    212 				if (context.volset_name)
    213 					free(context.volset_name);
    214 				*colon = 0;
    215 				context.volset_name = strdup(optarg);
    216 				optarg = colon+1;
    217 			}
    218 			if (context.primary_name)
    219 				free(context.primary_name);
    220 			if ((strstr(optarg, ":")))
    221 				errx(1, "primary name can't have ':' in its name");
    222 			context.primary_name = strdup(optarg);
    223 			break;
    224 		case 's' :
    225 			/* support for files, set file size */
    226 			/* XXX support for formatting recordables on vnd/file? */
    227 			if (dehumanize_number(optarg, &setsize) < 0)
    228 				errx(1, "can't parse size argument");
    229 			setsize = MAX(0, setsize);
    230 			break;
    231 		case 'S' :
    232 			emul_sectorsize = a_num(optarg, "secsize");
    233 			emul_sectorsize = MAX(512, emul_sectorsize);
    234 			break;
    235 		case 'B' :
    236 			emul_packetsize = a_num(optarg,
    237 				"blockingnr, packetsize");
    238 			emul_packetsize = MAX(emul_packetsize, 1);
    239 			emul_packetsize = MIN(emul_packetsize, 32);
    240 			break;
    241 		case 't' :
    242 			/* time zone override */
    243 			context.gmtoff = a_num(optarg, "gmtoff");
    244 			break;
    245 		default  :
    246 			usage();
    247 			/* NOTREACHED */
    248 		}
    249 	}
    250 
    251 	if (optind + 1 != argc)
    252 		usage();
    253 
    254 	/* get device and directory specifier */
    255 	dev_name = argv[optind];
    256 
    257 	emul_size = setsize;
    258 	error = udf_opendisc(dev_name, O_RDWR | O_CREAT | O_TRUNC);
    259 	if (error) {
    260 		udf_closedisc();
    261 		errx(1, "can't open device");
    262 	}
    263 
    264 	/* get 'disc' information */
    265 	error = udf_update_discinfo();
    266 	if (error) {
    267 		udf_closedisc();
    268 		errx(1, "can't retrieve discinfo");
    269 	}
    270 
    271 	/* derive disc identifiers when not specified and check given */
    272 	error = udf_proces_names();
    273 	if (error) {
    274 		/* error message has been printed */
    275 		udf_closedisc();
    276 		errx(1, "bad names given");
    277 	}
    278 
    279 	/* derive newfs disc format from disc profile */
    280 	error = udf_derive_format(req_enable, req_disable);
    281 	if (error)  {
    282 		/* error message has been printed */
    283 		udf_closedisc();
    284 		errx(1, "can't derive format from media/settings");
    285 	}
    286 
    287 	udf_dump_discinfo(&mmc_discinfo);
    288 	printf("Formatting disc compatible with UDF version %x to %x\n\n",
    289 		context.min_udf, context.max_udf);
    290 	(void)snprintb(scrap, sizeof(scrap), FORMAT_FLAGBITS,
    291 	    (uint64_t) context.format_flags);
    292 	printf("UDF properties       %s\n", scrap);
    293 	printf("Volume set          `%s'\n", context.volset_name);
    294 	printf("Primary volume      `%s`\n", context.primary_name);
    295 	printf("Logical volume      `%s`\n", context.logvol_name);
    296 	if (context.format_flags & FORMAT_META)
    297 		printf("Metadata percentage  %d %%\n", context.meta_perc);
    298 	printf("\n");
    299 
    300 	/* prepare disc if necessary (recordables mainly) */
    301 	error = udf_prepare_disc();
    302 	if (error) {
    303 		udf_closedisc();
    304 		errx(1, "preparing disc failed");
    305 	}
    306 	error = udf_prepare_format_track512();
    307 	if (error) {
    308 		udf_closedisc();
    309 		errx(1, "reservation for track512 failed");
    310 	}
    311 
    312 	/* perform the newfs itself */
    313 	udf_allow_writing();
    314 	error = udf_do_newfs();
    315 	udf_closedisc();
    316 
    317 	if (error)
    318 		return EXIT_FAILURE;
    319 
    320 	return EXIT_SUCCESS;
    321 }
    322 
    323 /* --------------------------------------------------------------------- */
    324 
    325