1/* $NetBSD: newfs_udf.c,v 1.24 2022/04/09 09:58:11 riastradh 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 */ 74int newfs_udf(int argc, char **argv); 75static void usage(void) __attribute__((__noreturn__)); 76 77/* global variables describing disc and format requests */ 78char *format_str; /* format: string representation */ 79 80 81/* --------------------------------------------------------------------- */ 82 83static int 84udf_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 111static int 112udf_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 129static void 130usage(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 139int 140main(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