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