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