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
print_usage(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
check_invalid_option(options * specified,char * opstr)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 *
attach_to_hald(void)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
detach_from_hald(LibHalContext * ctx,hal_state_t state)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
hald_running(void)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
setup_target(int flag)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
main(int argc,char ** argv)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