1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <sys/types.h> 29 #include <limits.h> 30 #include <unistd.h> 31 #include <libintl.h> 32 #include <locale.h> 33 #include <dbus/dbus.h> 34 #include <hal/libhal.h> 35 36 #include "msgs.h" 37 #include "device.h" 38 #include "util.h" 39 #include "main.h" 40 #include "options.h" 41 #include "mmc.h" 42 #include "misc_scsi.h" 43 44 /* 45 * global flags 46 */ 47 int debug = 0; 48 int keep_disc_open = 0; 49 int requested_speed = 0; 50 int simulation = 0; 51 int verbose = 0; 52 char *image_file = NULL; 53 char *blanking_type = NULL; 54 int audio_type = AUDIO_TYPE_NONE; 55 int extract_track_no = 0; 56 char *extract_file = NULL; 57 char *alt_tmp_dir = NULL; 58 char *copy_src = NULL; 59 int vol_running = 0; 60 int cflag = 0; 61 int tflag = 0; 62 uid_t ruid, cur_uid; 63 64 /* 65 * global variables 66 */ 67 cd_device *target = NULL; /* Default target device */ 68 static char *tgtdev = NULL; 69 int device_type = CD_RW; /* Default to CD/RW */ 70 int write_mode = TAO_MODE; /* Default to track at once */ 71 72 static void 73 print_usage(void) 74 { 75 err_msg(gettext("USAGE:\n")); 76 err_msg(gettext("\tcdrw -i [ -vSCO ] [ -d device ] [ -p speed ]")); 77 err_msg(gettext(" [ image-file ]\n")); 78 err_msg(gettext("\tcdrw -a [ -vSCO ] [ -d device ] [ -p speed ]")); 79 err_msg(gettext(" [ -T audio-type ] audio-file1 audio-file2 ...\n")); 80 err_msg(gettext("\tcdrw -x [ -v ] [ -d device ] [ -T audio-type ]")); 81 err_msg(gettext(" track-number audio-file\n")); 82 err_msg(gettext("\tcdrw -c [ -SC ] [ -d device ] [ -p speed ]")); 83 err_msg(gettext(" [ -m tmp-dir ] [ -s src-device ]\n")); 84 err_msg( 85 gettext("\tcdrw -b [ -v ] [ -d device ] all | session | fast\n")); 86 err_msg(gettext("\tcdrw -M [ -v ] [ -d device ]\n")); 87 err_msg(gettext("\tcdrw -L [ -v ] [ -d device ]\n")); 88 err_msg(gettext("\tcdrw -l [ -v ]\n")); 89 err_msg(gettext("\tcdrw -h\n")); 90 91 exit(2); 92 } 93 94 static void 95 check_invalid_option(options *specified, char *opstr) 96 { 97 options c_op; 98 int ret; 99 100 set_options_mask(&c_op, opstr); 101 if ((ret = compare_options_mask(&c_op, specified)) != 0) { 102 err_msg( 103 gettext("Option %c is not defined for this operation.\n"), 104 (char)ret); 105 print_usage(); 106 } 107 } 108 109 LibHalContext * 110 attach_to_hald(void) 111 { 112 LibHalContext *ctx = NULL; 113 DBusConnection *con = NULL; 114 DBusError error; 115 hal_state_t state; 116 117 /* Initialize the dbus error states */ 118 dbus_error_init(&error); 119 120 if ((con = dbus_bus_get(DBUS_BUS_SYSTEM, &error)) == NULL) { 121 return (NULL); 122 } 123 state = DBUS_CONNECTION; 124 125 /* Allocate a new hal context to work with the dbus */ 126 if ((ctx = libhal_ctx_new()) == NULL) 127 return (NULL); 128 state = HAL_CONTEXT; 129 130 /* Pair up the context with the connection */ 131 if (!libhal_ctx_set_dbus_connection(ctx, con)) 132 goto fail; 133 state = HAL_PAIRED; 134 135 /* If libhal_ctx_init fails hald is not present */ 136 if (!libhal_ctx_init(ctx, &error)) { 137 goto fail; 138 } 139 state = HAL_INITIALIZED; 140 141 return (ctx); 142 fail: 143 if (dbus_error_is_set(&error)) 144 dbus_error_free(&error); 145 detach_from_hald(ctx, state); 146 return (NULL); 147 148 } 149 150 void 151 detach_from_hald(LibHalContext *ctx, hal_state_t state) 152 { 153 DBusError error; 154 DBusConnection *con = libhal_ctx_get_dbus_connection(ctx); 155 156 dbus_error_init(&error); 157 158 switch (state) { 159 case HAL_INITIALIZED: 160 if (libhal_ctx_shutdown(ctx, &error) == FALSE) 161 if (dbus_error_is_set(&error)) 162 dbus_error_free(&error); 163 /*FALLTHROUGH*/ 164 case HAL_PAIRED: 165 (void) libhal_ctx_free(ctx); 166 dbus_connection_unref(con); 167 break; 168 case HAL_CONTEXT: 169 (void) libhal_ctx_free(ctx); 170 break; 171 case DBUS_CONNECTION: 172 default: 173 break; 174 } 175 } 176 177 /* 178 * This function returns one if hald is running and 179 * zero if hald is not running 180 */ 181 int 182 hald_running(void) 183 { 184 LibHalContext *ctx; 185 186 if ((ctx = attach_to_hald()) == NULL) 187 return (0); 188 189 detach_from_hald(ctx, HAL_INITIALIZED); 190 return (1); 191 } 192 193 int 194 setup_target(int flag) 195 { 196 char *devpath; 197 198 if (tgtdev != NULL) { 199 devpath = (char *)my_zalloc(PATH_MAX); 200 if (lookup_device(tgtdev, devpath)) { 201 target = get_device(tgtdev, devpath); 202 } 203 free(devpath); 204 if (target == NULL) { 205 return (0); 206 } 207 return (1); 208 } 209 return (scan_for_cd_device(flag, &target)); 210 } 211 212 int 213 main(int argc, char **argv) 214 { 215 int c; 216 int operations; 217 options specified_ops; 218 int aflag, iflag, Mflag, Lflag, lflag, bflag, xflag; 219 int ret; 220 221 (void) setlocale(LC_ALL, ""); 222 223 #if !defined(TEXT_DOMAIN) 224 #define TEXT_DOMAIN "SYS_TEST" 225 #endif 226 227 228 (void) textdomain(TEXT_DOMAIN); 229 230 ruid = getuid(); 231 cur_uid = geteuid(); 232 233 if (check_auth(ruid) != 1) { 234 err_msg(gettext( 235 "Authorization failed, Cannot access disks.\n")); 236 exit(1); 237 } 238 239 if ((cur_uid == 0) && (ruid != 0)) { 240 priv_change_needed = 1; 241 lower_priv(); 242 } 243 244 vol_running = hald_running(); 245 246 tgtdev = NULL; 247 operations = 0; 248 set_options_mask(&specified_ops, ""); 249 iflag = Mflag = Lflag = lflag = bflag = aflag = xflag = cflag = 0; 250 251 while ((c = getopt(argc, argv, "abcCd:hiLlm:MOp:s:ST:vVx")) != EOF) { 252 add_option(&specified_ops, c); 253 switch (c) { 254 case 'a': 255 aflag = 1; 256 operations++; 257 break; 258 case 'b': 259 bflag = 1; 260 operations++; 261 break; 262 case 'c': 263 cflag = 1; 264 operations++; 265 break; 266 case 'C': 267 /* 268 * cdrw now attempts to use the stated medium capacity 269 * by default, so this option no longer has any effect. 270 * It remains in the interface for backwards 271 * compatibility only. 272 */ 273 break; 274 case 'd': 275 tgtdev = optarg; 276 break; 277 case 'h': 278 print_usage(); /* will not return */ 279 break; 280 case 'i': 281 iflag = 1; 282 operations++; 283 break; 284 case 'L': 285 Lflag = 1; 286 operations++; 287 break; 288 case 'l': 289 lflag = 1; 290 operations++; 291 break; 292 case 'm': 293 alt_tmp_dir = optarg; 294 break; 295 case 'M': 296 Mflag = 1; 297 operations++; 298 break; 299 case 'O': 300 keep_disc_open = 1; 301 break; 302 case 'p': 303 requested_speed = atoi(optarg); 304 break; 305 case 's': 306 copy_src = optarg; 307 break; 308 case 'S': 309 simulation++; 310 break; 311 case 'T': 312 audio_type = get_audio_type(optarg); 313 if (audio_type == -1) { 314 err_msg(gettext("Unknown audio type %s\n"), 315 optarg); 316 exit(1); 317 } 318 break; 319 case 'v': 320 verbose++; 321 break; 322 case 'V': 323 /* 324 * more verbose. this will print out debug comments 325 */ 326 327 debug++; 328 break; 329 case 'x': 330 xflag++; 331 operations++; 332 break; 333 default: 334 print_usage(); 335 } 336 } 337 if (operations == 0) { 338 err_msg(gettext("No operation specified.\n")); 339 exit(1); 340 } 341 if (operations != 1) { 342 err_msg(gettext("More than one operation specified.\n")); 343 exit(1); 344 } 345 346 if (lflag) { 347 check_invalid_option(&specified_ops, "lhvV"); 348 list(); 349 } 350 351 /* 352 * we'll allow the user to specify the source device (-s) when 353 * extracting audio. 354 */ 355 356 if (xflag && copy_src) 357 tgtdev = copy_src; 358 359 /* 360 * This will scan for all CD devices when xflag or Mflag 361 * (extract audio, list toc) commands are used, providing 362 * no CD-RW devices are found. Since these commands can 363 * be used without a CD writer. 364 */ 365 366 if (xflag || Mflag) { 367 ret = setup_target(SCAN_ALL_CDS); 368 } else { 369 ret = setup_target(SCAN_WRITERS); 370 } 371 372 if (ret == 0) { 373 374 if (tgtdev != NULL) { 375 err_msg(gettext( 376 "Cannot find device %s.\n"), tgtdev); 377 378 } 379 380 if (vol_running) { 381 err_msg(gettext( 382 "No CD writers found or no media in the drive.\n")); 383 } else { 384 if (cur_uid != 0) { 385 err_msg(gettext( 386 "Volume manager is not running.\n")); 387 err_msg(gettext( 388 "Please start volume manager or run cdrw as root to access all devices.\n")); 389 } else { 390 err_msg(gettext( 391 "No CD writers found.\n")); 392 } 393 } 394 exit(1); 395 396 } else if (ret != 1) { 397 err_msg(gettext("More than one CD device found.\n")); 398 err_msg(gettext("Specify one using -d option.\n")); 399 err_msg(gettext( 400 "Or use -l option to list all the CD devices found\n")); 401 exit(1); 402 } 403 (void) check_device(target, CHECK_TYPE_NOT_CDROM|EXIT_IF_CHECK_FAILED); 404 405 if (check_device(target, CHECK_NO_MEDIA) == 0) { 406 int retry; 407 for (retry = 0; retry < 5; retry++) { 408 if (check_device(target, CHECK_DEVICE_NOT_READY) == 0) 409 break; 410 (void) sleep(3); 411 } 412 } 413 414 if (aflag) { 415 check_invalid_option(&specified_ops, "ahvSCOdpTV"); 416 if (optind == argc) { 417 err_msg(gettext("No audio files specified.\n")); 418 exit(1); 419 } 420 write_audio(argv, optind, argc); 421 } 422 if (Mflag) { 423 check_invalid_option(&specified_ops, "MhvdV"); 424 info(); 425 } 426 if (iflag) { 427 check_invalid_option(&specified_ops, "ihvSCOdpV"); 428 if (optind == (argc - 1)) { 429 image_file = argv[optind]; 430 write_image(); 431 } 432 if (optind == argc) 433 write_image(); 434 err_msg(gettext("Command line parsing error.\n")); 435 err_msg(gettext("Only one image-file can be specified.\n")); 436 exit(1); 437 } 438 if (bflag) { 439 check_invalid_option(&specified_ops, "bhvdV"); 440 if (optind != (argc - 1)) { 441 err_msg(gettext("Command line parsing error.\n")); 442 print_usage(); 443 } 444 blanking_type = argv[argc - 1]; 445 blank(); 446 } 447 if (xflag) { 448 check_invalid_option(&specified_ops, "xhpvdsTV"); 449 if (optind != (argc - 2)) { 450 err_msg(gettext("Command line parsing error.\n")); 451 print_usage(); 452 } 453 extract_track_no = atoi(argv[argc - 2]); 454 extract_file = argv[argc - 1]; 455 extract_audio(); 456 } 457 if (cflag) { 458 check_invalid_option(&specified_ops, "chvSCdpmsV"); 459 copy_cd(); 460 } 461 462 /* 463 * Open a closed disk, we do this by erasing the track tail 464 * and then re-finalizing with an open leadout. 465 */ 466 if (Lflag) { 467 check_invalid_option(&specified_ops, "LvdV"); 468 (void) check_device(target, CHECK_NO_MEDIA | 469 CHECK_DEVICE_NOT_READY | EXIT_IF_CHECK_FAILED); 470 471 /* no need to erase blank media */ 472 if (!check_device(target, CHECK_MEDIA_IS_NOT_BLANK)) 473 exit(0); 474 475 blanking_type = "leadout"; 476 blank(); 477 478 write_init(TRACK_MODE_DATA); 479 (void) close_track(target->d_fd, 0, 1, 1); 480 (void) finalize(target); 481 (void) printf(gettext("done.\n")); 482 exit(0); 483 } 484 return (0); 485 } 486