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