xref: /onnv-gate/usr/src/cmd/cdrw/device.c (revision 10621:a6ab13bfdd64)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54078Srameshc  * Common Development and Distribution License (the "License").
64078Srameshc  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*10621SZachary.Kissel@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <fcntl.h>
280Sstevel@tonic-gate #include <errno.h>
290Sstevel@tonic-gate #include <sys/stat.h>
300Sstevel@tonic-gate #include <sys/dkio.h>
310Sstevel@tonic-gate #include <unistd.h>
320Sstevel@tonic-gate #include <dirent.h>
330Sstevel@tonic-gate #include <string.h>
340Sstevel@tonic-gate #include <stdlib.h>
350Sstevel@tonic-gate #include <libintl.h>
360Sstevel@tonic-gate #include <limits.h>
376222Szk194757 #include <dbus/dbus.h>
386222Szk194757 #include <hal/libhal.h>
390Sstevel@tonic-gate 
400Sstevel@tonic-gate #include "transport.h"
410Sstevel@tonic-gate #include "mmc.h"
420Sstevel@tonic-gate #include "device.h"
430Sstevel@tonic-gate #include "util.h"
440Sstevel@tonic-gate #include "msgs.h"
450Sstevel@tonic-gate #include "misc_scsi.h"
460Sstevel@tonic-gate #include "toshiba.h"
470Sstevel@tonic-gate #include "main.h"
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * Old sun drives have a vendor specific mode page for setting/getting speed.
510Sstevel@tonic-gate  * Also they use a different method for extracting audio.
520Sstevel@tonic-gate  * We have the device inquiry strings at this time. This is used to enable
530Sstevel@tonic-gate  * us to use older sun drives to extract audio.
540Sstevel@tonic-gate  */
550Sstevel@tonic-gate static int
is_old_sun_drive(cd_device * dev)560Sstevel@tonic-gate is_old_sun_drive(cd_device *dev)
570Sstevel@tonic-gate {
580Sstevel@tonic-gate 	/*
590Sstevel@tonic-gate 	 * If we have a SONY CDU 561, CDU 8012, or TOSHIBA model with XMa we
600Sstevel@tonic-gate 	 * need to handle these drives a bit differently.
610Sstevel@tonic-gate 	 */
620Sstevel@tonic-gate 	if (strncmp("SONY", (const char *)&dev->d_inq[8], 4) == 0) {
630Sstevel@tonic-gate 		if (strncmp("CDU 561", (const char *)&dev->d_inq[16], 7) == 0)
640Sstevel@tonic-gate 			return (1);
650Sstevel@tonic-gate 		if (strncmp("CDU-8012", (const char *)&dev->d_inq[16], 8) == 0)
660Sstevel@tonic-gate 			return (1);
670Sstevel@tonic-gate 	}
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 	if ((strncmp("TOSHIBA", (const char *)&dev->d_inq[8], 7) == 0) &&
700Sstevel@tonic-gate 	    (strncmp("XM", (const char *)&dev->d_inq[16], 2) == 0)) {
710Sstevel@tonic-gate 
720Sstevel@tonic-gate 		char product_id[17];
730Sstevel@tonic-gate 
740Sstevel@tonic-gate 		/* Changing speed is not allowed for 32X TOSHIBA drives */
750Sstevel@tonic-gate 		if (strncmp("SUN32XCD", (const char *)&dev->d_inq[24], 8) == 0)
760Sstevel@tonic-gate 			dev->d_cap |= DEV_CAP_SETTING_SPEED_NOT_ALLOWED;
770Sstevel@tonic-gate 		(void) strncpy(product_id, (const char *)&dev->d_inq[16], 16);
780Sstevel@tonic-gate 		product_id[16] = 0;
790Sstevel@tonic-gate 		if (strstr(product_id, "SUN") != NULL)
800Sstevel@tonic-gate 			return (1);
810Sstevel@tonic-gate 	}
820Sstevel@tonic-gate 	return (0);
830Sstevel@tonic-gate }
840Sstevel@tonic-gate 
850Sstevel@tonic-gate /*
860Sstevel@tonic-gate  * returns a cd_device handle for a node returned by lookup_device()
870Sstevel@tonic-gate  * also takes the user supplied name and stores it inside the node
880Sstevel@tonic-gate  */
890Sstevel@tonic-gate cd_device *
get_device(char * user_supplied,char * node)900Sstevel@tonic-gate get_device(char *user_supplied, char *node)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate 	cd_device *dev;
930Sstevel@tonic-gate 	int fd;
940Sstevel@tonic-gate 	uchar_t *cap;
950Sstevel@tonic-gate 	char devnode[PATH_MAX];
960Sstevel@tonic-gate 	int size;
970Sstevel@tonic-gate 	struct dk_minfo mediainfo;
980Sstevel@tonic-gate 	int use_cd_speed = 0;
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 	/*
1010Sstevel@tonic-gate 	 * we need to resolve any link paths to avoid fake files
1020Sstevel@tonic-gate 	 * such as /dev/rdsk/../../export/file.
1030Sstevel@tonic-gate 	 */
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	TRACE(traceall_msg("get_device(%s, %s)\n", user_supplied ?
1060Sstevel@tonic-gate 	    user_supplied : "<nil>", node ? node : "<nil>"));
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	size = resolvepath(node, devnode, PATH_MAX);
1090Sstevel@tonic-gate 	if ((size <= 0) || (size >= (PATH_MAX - 1)))
1100Sstevel@tonic-gate 		return (NULL);
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	/* resolvepath may not return a null terminated string */
1130Sstevel@tonic-gate 	devnode[size] = '\0';
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	/* the device node must be in /devices/ or /vol/dev/rdsk */
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	if ((strncmp(devnode, "/devices/", 9) != 0) &&
1190Sstevel@tonic-gate 	    (strncmp(devnode, "/vol/dev/rdsk", 13) != 0))
1200Sstevel@tonic-gate 		return (NULL);
1210Sstevel@tonic-gate 	/*
1220Sstevel@tonic-gate 	 * Since we are currently running with the user euid it is
1230Sstevel@tonic-gate 	 * safe to try to open the file without checking access.
1240Sstevel@tonic-gate 	 */
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	fd = open(devnode, O_RDONLY|O_NDELAY);
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	if (fd < 0) {
1290Sstevel@tonic-gate 		TRACE(traceall_msg("Cannot open %s: %s\n", node,
1300Sstevel@tonic-gate 		    strerror(errno)));
1310Sstevel@tonic-gate 		return (NULL);
1320Sstevel@tonic-gate 	}
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	dev = (cd_device *)my_zalloc(sizeof (cd_device));
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	dev->d_node = (char *)my_zalloc(strlen(devnode) + 1);
1370Sstevel@tonic-gate 	(void) strcpy(dev->d_node, devnode);
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	dev->d_fd = fd;
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	dev->d_inq = (uchar_t *)my_zalloc(INQUIRY_DATA_LENGTH);
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	if (!inquiry(fd, dev->d_inq)) {
1440Sstevel@tonic-gate 		TRACE(traceall_msg("Inquiry failed on device %s\n", node));
1450Sstevel@tonic-gate 		if (debug) {
1460Sstevel@tonic-gate 			(void) printf("USCSI ioctl failed %d\n",
1470Sstevel@tonic-gate 			    uscsi_error);
1480Sstevel@tonic-gate 		}
1490Sstevel@tonic-gate 		free(dev->d_inq);
1500Sstevel@tonic-gate 		free(dev->d_node);
1510Sstevel@tonic-gate 		(void) close(dev->d_fd);
1520Sstevel@tonic-gate 		free(dev);
1530Sstevel@tonic-gate 		return (NULL);
1540Sstevel@tonic-gate 	}
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	if (debug) {
1570Sstevel@tonic-gate 		cap = (uchar_t *)my_zalloc(18);
1580Sstevel@tonic-gate 		(void) printf("Checking device type\n");
1590Sstevel@tonic-gate 		if (get_mode_page(fd, 0x2A, 0, 8, cap)) {
1600Sstevel@tonic-gate 			if (cap[2] & 0x10)
1610Sstevel@tonic-gate 				(void) printf("DVD-R read support\n");
1620Sstevel@tonic-gate 			if (cap[3] & 0x10)
1630Sstevel@tonic-gate 				(void) printf("DVD-R write support\n");
1640Sstevel@tonic-gate 			if (cap[5] & 0x4)
1650Sstevel@tonic-gate 				(void) printf("R-W supported\n");
1660Sstevel@tonic-gate 			if (cap[2] & 0x20)
1670Sstevel@tonic-gate 				(void) printf("DVD-RAM read supported\n");
1680Sstevel@tonic-gate 			if (cap[3] & 0x20)
1690Sstevel@tonic-gate 				(void) printf("DVD-RAM write supported\n");
1700Sstevel@tonic-gate 		} else {
1710Sstevel@tonic-gate 			(void) printf("Could not read mode page 2A! \n");
1720Sstevel@tonic-gate 		}
1730Sstevel@tonic-gate 		free(cap);
1740Sstevel@tonic-gate 	}
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	/* Detect if it's a Lite-ON drive with a streaming CD problem */
1770Sstevel@tonic-gate 	if ((strncmp("LITE-ON", (const char *)&dev->d_inq[8], 7) == 0) &&
1780Sstevel@tonic-gate 	    (strncmp("LTR-48", (const char *)&dev->d_inq[16], 6) == 0)) {
1790Sstevel@tonic-gate 		use_cd_speed = 1;
1800Sstevel@tonic-gate 	}
1810Sstevel@tonic-gate 
182465Srameshc 	/*
183465Srameshc 	 * a workaround for the firmware problem in LITE-ON COMBO drives.
184465Srameshc 	 * streaming for these drives sets it only to max speed regardless
185465Srameshc 	 * of requested speed. cd_speed_ctrl allow speeds less than max
186465Srameshc 	 * to be set but not max thus the code below. (x48 is max speed
187465Srameshc 	 * for these drives).
188465Srameshc 	 */
189465Srameshc 	if ((strncmp("LITE-ON", (const char *)&dev->d_inq[8], 7) == 0) &&
190465Srameshc 	    (strncmp("COMBO SOHC-4836VS",
191465Srameshc 	    (const char *)&dev->d_inq[16], 17) == 0))
192465Srameshc 		if (requested_speed < 48)
193465Srameshc 			use_cd_speed = 1;
194465Srameshc 
1950Sstevel@tonic-gate 	cap = (uchar_t *)my_zalloc(8);
1960Sstevel@tonic-gate 	if (is_old_sun_drive(dev)) {
1970Sstevel@tonic-gate 		dev->d_read_audio = toshiba_read_audio;
1980Sstevel@tonic-gate 		dev->d_speed_ctrl = toshiba_speed_ctrl;
1990Sstevel@tonic-gate 	} else {
2000Sstevel@tonic-gate 		/*
2011318Sec158148 		 * If the CD Read Feature is supported, READ CD will work
2021318Sec158148 		 * and will return jitter free audio data. Otherwise, look
2031318Sec158148 		 * at Page Code 2A for this information.
2040Sstevel@tonic-gate 		 */
2051318Sec158148 		if (ftr_supported(fd, MMC_FTR_CD_READ) == 1) {
2060Sstevel@tonic-gate 			dev->d_read_audio = read_audio_through_read_cd;
2070Sstevel@tonic-gate 			dev->d_cap |= DEV_CAP_ACCURATE_CDDA;
2080Sstevel@tonic-gate 		} else if (get_mode_page(fd, 0x2A, 0, 8, cap)) {
2090Sstevel@tonic-gate 			if (cap[5] & 1) {
2100Sstevel@tonic-gate 				dev->d_read_audio = read_audio_through_read_cd;
2110Sstevel@tonic-gate 				if (cap[5] & 2)
2120Sstevel@tonic-gate 					dev->d_cap |= DEV_CAP_ACCURATE_CDDA;
2130Sstevel@tonic-gate 			}
2140Sstevel@tonic-gate 		}
2150Sstevel@tonic-gate 		/*
2161318Sec158148 		 * If the Real Time Streaming Feature is supported then
2174078Srameshc 		 * Real-time streaming commands can be used for speed control
2184078Srameshc 		 * (except when we want to use cd_speed_ctrl explicitly which
2194078Srameshc 		 * is specified by setting use_cd_speed to 1).
2201318Sec158148 		 * Otherwise try SET CD SPEED.
2210Sstevel@tonic-gate 		 */
2224078Srameshc 		if ((ftr_supported(fd, MMC_FTR_RT_STREAM) == 1) &&
2234078Srameshc 		    !use_cd_speed) {
2240Sstevel@tonic-gate 			dev->d_speed_ctrl = rt_streaming_ctrl;
2250Sstevel@tonic-gate 			if (debug)
2260Sstevel@tonic-gate 				(void) printf("using rt speed ctrl\n");
2270Sstevel@tonic-gate 		} else {
2280Sstevel@tonic-gate 			dev->d_speed_ctrl = cd_speed_ctrl;
2290Sstevel@tonic-gate 			if (debug)
2300Sstevel@tonic-gate 				(void) printf("using cd speed ctrl\n");
2310Sstevel@tonic-gate 		}
2320Sstevel@tonic-gate 	}
2330Sstevel@tonic-gate 	if (dev->d_read_audio != NULL)
2340Sstevel@tonic-gate 		dev->d_cap |= DEV_CAP_EXTRACT_CDDA;
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	dev->d_blksize = 0;
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	/*
2390Sstevel@tonic-gate 	 * Find the block size of the device so we can translate
2400Sstevel@tonic-gate 	 * the reads/writes to the device blocksize.
2410Sstevel@tonic-gate 	 */
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	if (ioctl(fd, DKIOCGMEDIAINFO, &mediainfo) < 0) {
2440Sstevel@tonic-gate 		/*
2450Sstevel@tonic-gate 		 * If DKIOCGMEDIAINFO fails we'll try to get
2460Sstevel@tonic-gate 		 * the blocksize from the device itself.
2470Sstevel@tonic-gate 		 */
2480Sstevel@tonic-gate 		if (debug)
2490Sstevel@tonic-gate 			(void) printf("DKIOCGMEDIAINFO failed\n");
2500Sstevel@tonic-gate 		if (read_capacity(fd, cap))
2510Sstevel@tonic-gate 			dev->d_blksize = read_scsi32(cap + 4);
2520Sstevel@tonic-gate 	} else {
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 		dev->d_blksize = mediainfo.dki_lbsize;
2550Sstevel@tonic-gate 	}
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	if (debug) {
2580Sstevel@tonic-gate 		uint_t bsize;
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 		(void) printf("blocksize = %d\n", dev->d_blksize);
2610Sstevel@tonic-gate 		(void) printf("read_format_capacity = %d \n",
2620Sstevel@tonic-gate 		    read_format_capacity(fd, &bsize));
2630Sstevel@tonic-gate 	}
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	/*
2660Sstevel@tonic-gate 	 * Some devices will return invalid blocksizes. ie. Toshiba
2670Sstevel@tonic-gate 	 * drives will return 2352 when an audio CD is inserted.
2680Sstevel@tonic-gate 	 * Older Sun drives will use 512 byte block sizes. All newer
2690Sstevel@tonic-gate 	 * drives should have 2k blocksizes.
2700Sstevel@tonic-gate 	 */
2710Sstevel@tonic-gate 	if (((dev->d_blksize != 512) && (dev->d_blksize != 2048))) {
2720Sstevel@tonic-gate 			if (is_old_sun_drive(dev)) {
2730Sstevel@tonic-gate 				dev->d_blksize = 512;
2740Sstevel@tonic-gate 			} else {
2750Sstevel@tonic-gate 				dev->d_blksize = 2048;
2760Sstevel@tonic-gate 			}
2770Sstevel@tonic-gate 		if (debug)
2780Sstevel@tonic-gate 			(void) printf(" switching to %d\n", dev->d_blksize);
2790Sstevel@tonic-gate 	}
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 	free(cap);
2820Sstevel@tonic-gate 	if (user_supplied) {
2830Sstevel@tonic-gate 		dev->d_name = (char *)my_zalloc(strlen(user_supplied) + 1);
2840Sstevel@tonic-gate 		(void) strcpy(dev->d_name, user_supplied);
2850Sstevel@tonic-gate 	}
2860Sstevel@tonic-gate 	TRACE(traceall_msg("Got device %s\n", node));
2870Sstevel@tonic-gate 	return (dev);
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate void
fini_device(cd_device * dev)2910Sstevel@tonic-gate fini_device(cd_device *dev)
2920Sstevel@tonic-gate {
2930Sstevel@tonic-gate 	free(dev->d_inq);
2940Sstevel@tonic-gate 	free(dev->d_node);
2950Sstevel@tonic-gate 	(void) close(dev->d_fd);
2960Sstevel@tonic-gate 	if (dev->d_name)
2970Sstevel@tonic-gate 		free(dev->d_name);
2980Sstevel@tonic-gate 	free(dev);
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate 
3016222Szk194757 /*
3026222Szk194757  * Given a /dev path resolve that path to a symbolic
3036222Szk194757  * name such as cdrom0 if hald is running. If hald is
3046222Szk194757  * not running, or does not have a symbolic name for the
3056222Szk194757  * the specified /dev path return NULL.
3066222Szk194757  */
3076222Szk194757 static char *
hald_symname(char * path)3086222Szk194757 hald_symname(char *path)
3096222Szk194757 {
3106222Szk194757 	LibHalContext *ctx = NULL;
3116222Szk194757 	DBusError error;
3126222Szk194757 
3136222Szk194757 	char **udi, *p = NULL;
3146222Szk194757 	int ndevs = 0, i;
3156222Szk194757 
3166222Szk194757 	/* Make sure hald is running */
3176222Szk194757 	if (vol_running == 0)
3186222Szk194757 		return (p);
3196222Szk194757 
3206222Szk194757 	dbus_error_init(&error);
3216222Szk194757 
3226222Szk194757 	if ((ctx = attach_to_hald()) == NULL)
3236222Szk194757 		return (p);
3246222Szk194757 
3256222Szk194757 	if ((udi = libhal_manager_find_device_string_match(ctx,
3266222Szk194757 	    HAL_RDSK_PROP, path, &ndevs, &error)) == NULL)
3276222Szk194757 		goto done;
3286222Szk194757 
3296222Szk194757 	/* Look for the node that contains the valid (non-null) symdev */
3306222Szk194757 	for (i = 0; i < ndevs; i++) {
3316222Szk194757 		if ((p = libhal_device_get_property_string(ctx, udi[i],
3326222Szk194757 		    HAL_SYMDEV_PROP, NULL)) != NULL)
3336222Szk194757 			break;
3346222Szk194757 		else
3356222Szk194757 			libhal_free_string(p);
3366222Szk194757 	}
3376222Szk194757 
3386222Szk194757 done:
3396222Szk194757 	if (udi != NULL)
3406222Szk194757 		libhal_free_string_array(udi);
3416222Szk194757 	if (dbus_error_is_set(&error))
3426222Szk194757 		dbus_error_free(&error);
3436222Szk194757 	detach_from_hald(ctx, HAL_INITIALIZED);
3446222Szk194757 	return (p);
3456222Szk194757 }
3466222Szk194757 
3476222Szk194757 /*
3486222Szk194757  * Given a name resolve that name to a raw device in the case
3496222Szk194757  * that it is a symbolic name or just return what is given if
3506222Szk194757  * we are given a /dev path or hald is not running.
3516222Szk194757  */
3526222Szk194757 static char *
hald_findname(char * symname)3536222Szk194757 hald_findname(char *symname)
3546222Szk194757 {
3556222Szk194757 	LibHalContext *ctx = NULL;
3566222Szk194757 	DBusError error;
3576222Szk194757 
3586222Szk194757 	char **udi, *path = NULL;
3596222Szk194757 	int ndevs = 0, i;
3606222Szk194757 
361*10621SZachary.Kissel@Sun.COM 	/*
362*10621SZachary.Kissel@Sun.COM 	 * We already have a raw path lets return it in a copied buffer
363*10621SZachary.Kissel@Sun.COM 	 * as our caller assumes that they need to free memory.
364*10621SZachary.Kissel@Sun.COM 	 */
365*10621SZachary.Kissel@Sun.COM 	if (symname[0] == '/') {
366*10621SZachary.Kissel@Sun.COM 		path = my_zalloc(strlen(symname) + 1);
367*10621SZachary.Kissel@Sun.COM 		(void) strlcpy(path, symname, (strlen(symname) + 1));
368*10621SZachary.Kissel@Sun.COM 		return (path);
369*10621SZachary.Kissel@Sun.COM 	}
3706222Szk194757 
3716222Szk194757 	/* Get the raw device from the hal record */
3726222Szk194757 	if (vol_running != 0) {
3736222Szk194757 		dbus_error_init(&error);
3746222Szk194757 
3756222Szk194757 		if ((ctx = attach_to_hald()) == NULL)
3766222Szk194757 			return (path);
3776222Szk194757 
3786222Szk194757 		if ((udi = libhal_manager_find_device_string_match(ctx,
3796222Szk194757 		    HAL_SYMDEV_PROP, symname, &ndevs,
3806222Szk194757 		    &error)) == NULL)
3816222Szk194757 			goto done;
3826222Szk194757 
3836222Szk194757 		/*
3846222Szk194757 		 * Loop over the returned UDIs to access the raw
3856222Szk194757 		 * device path.
3866222Szk194757 		 */
3876222Szk194757 		for (i = 0; i < ndevs; i++) {
3886222Szk194757 			if ((path = libhal_device_get_property_string(ctx,
3896222Szk194757 			    udi[i], HAL_RDSK_PROP, NULL)) != NULL)
3906222Szk194757 				break;
3916222Szk194757 			else
3926222Szk194757 				libhal_free_string(path);
3936222Szk194757 		}
3946222Szk194757 
3956222Szk194757 done:
3966222Szk194757 		if (udi != NULL)
3976222Szk194757 			libhal_free_string_array(udi);
3986222Szk194757 		if (dbus_error_is_set(&error))
3996222Szk194757 			dbus_error_free(&error);
4006222Szk194757 		detach_from_hald(ctx, HAL_INITIALIZED);
4016222Szk194757 		return (path);
4026222Szk194757 	} else {
4036222Szk194757 		return (NULL);
4046222Szk194757 	}
4056222Szk194757 }
4066222Szk194757 
4070Sstevel@tonic-gate static int
vol_name_to_dev_node(char * vname,char * found)4080Sstevel@tonic-gate vol_name_to_dev_node(char *vname, char *found)
4090Sstevel@tonic-gate {
4100Sstevel@tonic-gate 	struct stat statbuf;
4110Sstevel@tonic-gate 	char *p1;
4120Sstevel@tonic-gate 	int i;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	if (vname == NULL)
4150Sstevel@tonic-gate 		return (0);
4166222Szk194757 
4176222Szk194757 	p1 = hald_findname(vname);
4186222Szk194757 
4190Sstevel@tonic-gate 	if (p1 == NULL)
4200Sstevel@tonic-gate 		return (0);
4210Sstevel@tonic-gate 	if (stat(p1, &statbuf) < 0) {
4226222Szk194757 		libhal_free_string(p1);
4230Sstevel@tonic-gate 		return (0);
4240Sstevel@tonic-gate 	}
425871Scasper 	if (S_ISDIR(statbuf.st_mode)) {
4260Sstevel@tonic-gate 		for (i = 0; i < 16; i++) {
4270Sstevel@tonic-gate 			(void) snprintf(found, PATH_MAX, "%s/s%d", p1, i);
4280Sstevel@tonic-gate 			if (access(found, F_OK) >= 0)
4290Sstevel@tonic-gate 				break;
4300Sstevel@tonic-gate 		}
4310Sstevel@tonic-gate 		if (i == 16) {
4326222Szk194757 			libhal_free_string(p1);
4330Sstevel@tonic-gate 			return (0);
4340Sstevel@tonic-gate 		}
4350Sstevel@tonic-gate 	} else {
4360Sstevel@tonic-gate 		(void) strlcpy(found, p1, PATH_MAX);
4370Sstevel@tonic-gate 	}
4386222Szk194757 	libhal_free_string(p1);
4390Sstevel@tonic-gate 	return (1);
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate /*
4430Sstevel@tonic-gate  * Builds an open()able device path from a user supplied node which can be
4440Sstevel@tonic-gate  * of the * form of /dev/[r]dsk/cxtxdx[sx] or cxtxdx[sx] or volmgt-name like
4450Sstevel@tonic-gate  * cdrom[n]
4460Sstevel@tonic-gate  * returns the path found in 'found' and returns 1. Otherwise returns 0.
4470Sstevel@tonic-gate  */
4480Sstevel@tonic-gate int
lookup_device(char * supplied,char * found)4490Sstevel@tonic-gate lookup_device(char *supplied, char *found)
4500Sstevel@tonic-gate {
4510Sstevel@tonic-gate 	struct stat statbuf;
4520Sstevel@tonic-gate 	int fd;
4530Sstevel@tonic-gate 	char tmpstr[PATH_MAX];
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	/* If everything is fine and proper, no need to analyze */
456871Scasper 	if ((stat(supplied, &statbuf) == 0) && S_ISCHR(statbuf.st_mode) &&
4570Sstevel@tonic-gate 	    ((fd = open(supplied, O_RDONLY|O_NDELAY)) >= 0)) {
4580Sstevel@tonic-gate 		(void) close(fd);
4590Sstevel@tonic-gate 		(void) strlcpy(found, supplied, PATH_MAX);
4600Sstevel@tonic-gate 		return (1);
4610Sstevel@tonic-gate 	}
4626222Szk194757 
4636222Szk194757 	/*
4646222Szk194757 	 * Hal only allows access to a device when the user is
4656222Szk194757 	 * on the console, therefore if hal is running and we can't
4666222Szk194757 	 * open the /dev/rdsk or /dev/removable-media/rdsk device
4676222Szk194757 	 * file we will return 0 marking this device as not avaiable.
4686222Szk194757 	 */
4696222Szk194757 	if (fd < 0 && ((strncmp(supplied, "/dev/rdsk/", 10) == 0) ||
4706222Szk194757 	    (strncmp(supplied, "/dev/removable-media/rdsk/", 26) == 0)))
4716222Szk194757 		return (0);
4726222Szk194757 
4736222Szk194757 	if ((strncmp(supplied, "/dev/dsk/", 9) == 0) ||
4746222Szk194757 	    (strncmp(supplied, "/dev/removable-media/dsk/", 25) == 0)) {
4750Sstevel@tonic-gate 		(void) snprintf(tmpstr, PATH_MAX, "/dev/rdsk/%s",
4760Sstevel@tonic-gate 		    (char *)strrchr(supplied, '/'));
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 		if ((fd = open(tmpstr, O_RDONLY|O_NDELAY)) >= 0) {
4790Sstevel@tonic-gate 			(void) close(fd);
4800Sstevel@tonic-gate 			(void) strlcpy(found, supplied, PATH_MAX);
4810Sstevel@tonic-gate 			return (1);
4820Sstevel@tonic-gate 		}
4836222Szk194757 
4846222Szk194757 		/* This device can't be opened mark it as unavailable. */
4856222Szk194757 		return (0);
4860Sstevel@tonic-gate 	}
4870Sstevel@tonic-gate 	if ((strncmp(supplied, "cdrom", 5) != 0) &&
4880Sstevel@tonic-gate 	    (strlen(supplied) < 32)) {
4890Sstevel@tonic-gate 		(void) snprintf(tmpstr, sizeof (tmpstr), "/dev/rdsk/%s",
4900Sstevel@tonic-gate 		    supplied);
4910Sstevel@tonic-gate 		if (access(tmpstr, F_OK) < 0) {
4920Sstevel@tonic-gate 			(void) strcat(tmpstr, "s2");
4930Sstevel@tonic-gate 		}
4940Sstevel@tonic-gate 		if ((fd = open(tmpstr, O_RDONLY|O_NDELAY)) >= 0) {
4950Sstevel@tonic-gate 			(void) close(fd);
4960Sstevel@tonic-gate 			(void) strlcpy(found, tmpstr, PATH_MAX);
4970Sstevel@tonic-gate 			return (1);
4980Sstevel@tonic-gate 		}
4996222Szk194757 
5006222Szk194757 		/* This device can't be opened mark it as unavailable. */
5016222Szk194757 		return (0);
5020Sstevel@tonic-gate 	}
5030Sstevel@tonic-gate 	return (vol_name_to_dev_node(supplied, found));
5040Sstevel@tonic-gate }
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate /*
5070Sstevel@tonic-gate  * Opens the device node name passed and returns 1 (true) if the
5080Sstevel@tonic-gate  * device is a CD.
5090Sstevel@tonic-gate  */
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate static int
is_cd(char * node)5120Sstevel@tonic-gate is_cd(char *node)
5130Sstevel@tonic-gate {
5140Sstevel@tonic-gate 	int fd;
5150Sstevel@tonic-gate 	struct dk_cinfo cinfo;
5160Sstevel@tonic-gate 	int ret = 1;
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	fd = open(node, O_RDONLY|O_NDELAY);
5190Sstevel@tonic-gate 	if (fd < 0) {
5200Sstevel@tonic-gate 		ret = 0;
5210Sstevel@tonic-gate 	} else if (ioctl(fd, DKIOCINFO, &cinfo) < 0) {
5220Sstevel@tonic-gate 		ret = 0;
5230Sstevel@tonic-gate 	} else if (cinfo.dki_ctype != DKC_CDROM) {
5240Sstevel@tonic-gate 		ret = 0;
5250Sstevel@tonic-gate 	}
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	if (fd >= 0) {
5280Sstevel@tonic-gate 		(void) close(fd);
5290Sstevel@tonic-gate 	}
5300Sstevel@tonic-gate 	return (ret);
5310Sstevel@tonic-gate }
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate static void
print_header(void)5340Sstevel@tonic-gate print_header(void)
5350Sstevel@tonic-gate {
5360Sstevel@tonic-gate 	/* l10n_NOTE : Column spacing should be kept same */
5370Sstevel@tonic-gate 	(void) printf(gettext("    Node	           Connected Device"));
5380Sstevel@tonic-gate 	/* l10n_NOTE : Column spacing should be kept same */
5390Sstevel@tonic-gate 	(void) printf(gettext("	           Device type\n"));
5400Sstevel@tonic-gate 	(void) printf(
5410Sstevel@tonic-gate 	    "----------------------+--------------------------------");
5420Sstevel@tonic-gate 	(void) printf("+-----------------\n");
5430Sstevel@tonic-gate }
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate /*
5460Sstevel@tonic-gate  * returns the number of writers or CD/DVD-roms found and the path of
5470Sstevel@tonic-gate  * the first device found depending on the mode argument.
5480Sstevel@tonic-gate  * possible mode values are:
5490Sstevel@tonic-gate  * SCAN_ALL_CDS 	Scan all CD/DVD devices. Return first CD-RW found.
5500Sstevel@tonic-gate  * SCAN_WRITERS		Scan all CD-RW devices. Return first one found.
5510Sstevel@tonic-gate  * SCAN_LISTDEVS	List all devices found.
5520Sstevel@tonic-gate  */
5530Sstevel@tonic-gate int
scan_for_cd_device(int mode,cd_device ** found)5540Sstevel@tonic-gate scan_for_cd_device(int mode, cd_device **found)
5550Sstevel@tonic-gate {
5560Sstevel@tonic-gate 	DIR *dir;
5570Sstevel@tonic-gate 	struct dirent *dirent;
5580Sstevel@tonic-gate 	char sdev[PATH_MAX], dev[PATH_MAX];
5590Sstevel@tonic-gate 	cd_device *t_dev;
5600Sstevel@tonic-gate 	int writers_found = 0;
5610Sstevel@tonic-gate 	int header_printed = 0;
5620Sstevel@tonic-gate 	int is_writer;
5630Sstevel@tonic-gate 	int total_devices_found;
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 	TRACE(traceall_msg("scan_for_cd_devices (mode=%d) called\n", mode));
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	if (mode) {
5680Sstevel@tonic-gate 		(void) printf(gettext("Looking for CD devices...\n"));
5690Sstevel@tonic-gate 	}
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 	dir = opendir("/dev/rdsk");
5720Sstevel@tonic-gate 	if (dir == NULL)
5730Sstevel@tonic-gate 		return (0);
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	writers_found = 0;
5760Sstevel@tonic-gate 	total_devices_found = 0;
5770Sstevel@tonic-gate 	while ((dirent = readdir(dir)) != NULL) {
5780Sstevel@tonic-gate 		if (dirent->d_name[0] == '.')
5790Sstevel@tonic-gate 			continue;
5800Sstevel@tonic-gate 		(void) snprintf(sdev, PATH_MAX, "/dev/rdsk/%s",
5810Sstevel@tonic-gate 		    dirent->d_name);
5820Sstevel@tonic-gate 		if (strcmp("s2", (char *)strrchr(sdev, 's')) != 0)
5830Sstevel@tonic-gate 			continue;
5840Sstevel@tonic-gate 		if (!lookup_device(sdev, dev))
5850Sstevel@tonic-gate 			continue;
5860Sstevel@tonic-gate 		if (!is_cd(dev))
5870Sstevel@tonic-gate 			continue;
5880Sstevel@tonic-gate 		if ((t_dev = get_device(NULL, dev)) == NULL) {
5890Sstevel@tonic-gate 			continue;
5900Sstevel@tonic-gate 		}
5910Sstevel@tonic-gate 		total_devices_found++;
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 		is_writer = !(check_device(t_dev, CHECK_DEVICE_NOT_WRITABLE));
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 		if (is_writer) {
5960Sstevel@tonic-gate 			writers_found++;
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 			if ((writers_found == 1) && (mode != SCAN_LISTDEVS)) {
5990Sstevel@tonic-gate 				*found = t_dev;
6000Sstevel@tonic-gate 			}
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 		} else if ((mode == SCAN_ALL_CDS) && (writers_found == 0) &&
6030Sstevel@tonic-gate 		    (total_devices_found == 1) && found) {
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 			/* We found a CD-ROM or DVD-ROM */
6060Sstevel@tonic-gate 			*found = t_dev;
6070Sstevel@tonic-gate 		}
6080Sstevel@tonic-gate 
6096222Szk194757 		if (mode == SCAN_LISTDEVS) {
6100Sstevel@tonic-gate 			char *sn;
6110Sstevel@tonic-gate 
6126222Szk194757 			sn = hald_symname(sdev);
6130Sstevel@tonic-gate 			if (!header_printed) {
6140Sstevel@tonic-gate 				print_header();
6150Sstevel@tonic-gate 				header_printed = 1;
6160Sstevel@tonic-gate 			}
6170Sstevel@tonic-gate 			/* show vendor, model, firmware rev and device type */
6180Sstevel@tonic-gate 			(void) printf(" %-21.21s| %.8s %.16s %.4s | %s%s\n",
6190Sstevel@tonic-gate 			    sn ? sn : sdev, &t_dev->d_inq[8],
6200Sstevel@tonic-gate 			    &t_dev->d_inq[16], &t_dev->d_inq[32],
6210Sstevel@tonic-gate 			    gettext("CD Reader"),
6220Sstevel@tonic-gate 			    is_writer ? gettext("/Writer") : "");
6230Sstevel@tonic-gate 			if (sn)
6240Sstevel@tonic-gate 				free(sn);
6250Sstevel@tonic-gate 		}
6260Sstevel@tonic-gate 		if ((found != NULL) && ((*found) != t_dev))
6270Sstevel@tonic-gate 			fini_device(t_dev);
6280Sstevel@tonic-gate 	}
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 	(void) closedir(dir);
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	if ((mode & SCAN_WRITERS) || writers_found)
6330Sstevel@tonic-gate 		return (writers_found);
6340Sstevel@tonic-gate 	else
6350Sstevel@tonic-gate 		return (total_devices_found);
6360Sstevel@tonic-gate }
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate /*
6390Sstevel@tonic-gate  * Check device for various conditions/capabilities
6400Sstevel@tonic-gate  * If EXIT_IF_CHECK_FAILED set in cond then it will also exit after
6410Sstevel@tonic-gate  * printing a message.
6420Sstevel@tonic-gate  */
6430Sstevel@tonic-gate int
check_device(cd_device * dev,int cond)6440Sstevel@tonic-gate check_device(cd_device *dev, int cond)
6450Sstevel@tonic-gate {
6460Sstevel@tonic-gate 	uchar_t *disc_info, disc_status = 0, erasable = 0;
6470Sstevel@tonic-gate 	uchar_t page_code[4];
6480Sstevel@tonic-gate 	char *errmsg = NULL;
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 	if ((errmsg == NULL) && (cond & CHECK_TYPE_NOT_CDROM) &&
6510Sstevel@tonic-gate 	    ((dev->d_inq[0] & 0x1f) != 5)) {
6520Sstevel@tonic-gate 		errmsg =
6530Sstevel@tonic-gate 		    gettext("Specified device does not appear to be a CDROM");
6540Sstevel@tonic-gate 	}
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	if ((errmsg == NULL) && (cond & CHECK_DEVICE_NOT_READY) &&
6570Sstevel@tonic-gate 	    !test_unit_ready(dev->d_fd)) {
6580Sstevel@tonic-gate 		errmsg = gettext("Device not ready");
6590Sstevel@tonic-gate 	}
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 	/* Look at the capabilities page for this information */
6620Sstevel@tonic-gate 	if ((errmsg == NULL) && (cond & CHECK_DEVICE_NOT_WRITABLE)) {
6630Sstevel@tonic-gate 		if (!get_mode_page(dev->d_fd, 0x2a, 0, 4, page_code) ||
6640Sstevel@tonic-gate 		    ((page_code[3] & 1) == 0)) {
6650Sstevel@tonic-gate 			errmsg = gettext("Target device is not a CD writer");
6660Sstevel@tonic-gate 		}
6670Sstevel@tonic-gate 	}
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 	if ((errmsg == NULL) && (cond & CHECK_NO_MEDIA)) {
6700Sstevel@tonic-gate 		if (!test_unit_ready(dev->d_fd) && (uscsi_status == 2) &&
6710Sstevel@tonic-gate 		    ((RQBUFLEN - rqresid) >= 14) &&
6720Sstevel@tonic-gate 		    ((SENSE_KEY(rqbuf) & 0x0f) == 2) && (ASC(rqbuf) == 0x3A) &&
6730Sstevel@tonic-gate 		    ((ASCQ(rqbuf) == 0) || (ASCQ(rqbuf) == 1) ||
6740Sstevel@tonic-gate 		    (ASCQ(rqbuf) == 2))) {
6750Sstevel@tonic-gate 			/* medium not present */
6760Sstevel@tonic-gate 			errmsg = gettext("No media in device");
6770Sstevel@tonic-gate 		}
6780Sstevel@tonic-gate 	}
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	/* Issue READ DISC INFORMATION mmc command */
6830Sstevel@tonic-gate 	if ((errmsg == NULL) && ((cond & CHECK_MEDIA_IS_NOT_BLANK) ||
6840Sstevel@tonic-gate 	    (cond & CHECK_MEDIA_IS_NOT_WRITABLE) ||
6850Sstevel@tonic-gate 	    (cond & CHECK_MEDIA_IS_NOT_ERASABLE))) {
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 		disc_info = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE);
6880Sstevel@tonic-gate 		if (!read_disc_info(dev->d_fd, disc_info)) {
6890Sstevel@tonic-gate 			errmsg = gettext("Cannot obtain disc information");
6900Sstevel@tonic-gate 		} else {
6910Sstevel@tonic-gate 			disc_status = disc_info[2] & 0x03;
6920Sstevel@tonic-gate 			erasable = disc_info[2] & 0x10;
6930Sstevel@tonic-gate 		}
6940Sstevel@tonic-gate 		free(disc_info);
6950Sstevel@tonic-gate 		if (errmsg == NULL) {
6960Sstevel@tonic-gate 			if (!erasable && (cond & CHECK_MEDIA_IS_NOT_ERASABLE))
6970Sstevel@tonic-gate 				errmsg = gettext(
6980Sstevel@tonic-gate 				    "Media in the device is not erasable");
6990Sstevel@tonic-gate 			else if ((disc_status != 0) &&
7000Sstevel@tonic-gate 			    (cond & CHECK_MEDIA_IS_NOT_BLANK))
7010Sstevel@tonic-gate 				errmsg = gettext(
7020Sstevel@tonic-gate 				    "Media in the device is not blank");
7030Sstevel@tonic-gate 			else if ((disc_status == 2) &&
7040Sstevel@tonic-gate 			    (cond & CHECK_MEDIA_IS_NOT_WRITABLE) &&
7050Sstevel@tonic-gate 			    ((device_type != DVD_PLUS_W) &&
7060Sstevel@tonic-gate 			    (device_type != DVD_PLUS)))
7070Sstevel@tonic-gate 				errmsg = gettext(
7080Sstevel@tonic-gate 				    "Media in the device is not writable");
7090Sstevel@tonic-gate 		}
7100Sstevel@tonic-gate 	}
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate 	if (errmsg) {
7130Sstevel@tonic-gate 		if (cond & EXIT_IF_CHECK_FAILED) {
7140Sstevel@tonic-gate 			err_msg("%s.\n", errmsg);
7150Sstevel@tonic-gate 			exit(1);
7160Sstevel@tonic-gate 		}
7170Sstevel@tonic-gate 		return (1);
7180Sstevel@tonic-gate 	}
7190Sstevel@tonic-gate 	return (0);
7200Sstevel@tonic-gate }
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate /*
7230Sstevel@tonic-gate  * Generic routine for writing whatever the next track is and taking
7240Sstevel@tonic-gate  * care of the progress bar. Mode tells the track type (audio or data).
7250Sstevel@tonic-gate  * Data from track is taken from the byte stream h
7260Sstevel@tonic-gate  */
7270Sstevel@tonic-gate void
write_next_track(int mode,bstreamhandle h)7280Sstevel@tonic-gate write_next_track(int mode, bstreamhandle h)
7290Sstevel@tonic-gate {
7300Sstevel@tonic-gate 	struct track_info *ti;
7310Sstevel@tonic-gate 	struct trackio_error *te;
7320Sstevel@tonic-gate 	off_t size;
7330Sstevel@tonic-gate 
734178Sarutz 	ti = (struct track_info *)my_zalloc(sizeof (*ti));
7350Sstevel@tonic-gate 	if ((build_track_info(target, -1, ti) == 0) ||
7360Sstevel@tonic-gate 	    ((ti->ti_flags & TI_NWA_VALID) == 0)) {
7370Sstevel@tonic-gate 		if ((device_type == DVD_PLUS) || (device_type ==
7380Sstevel@tonic-gate 		    DVD_PLUS_W)) {
7390Sstevel@tonic-gate 			ti->ti_flags |= TI_NWA_VALID;
7400Sstevel@tonic-gate 		} else {
7410Sstevel@tonic-gate 			err_msg(gettext(
7420Sstevel@tonic-gate 			    "Cannot get writable address for the media.\n"));
7430Sstevel@tonic-gate 			exit(1);
7440Sstevel@tonic-gate 		}
7450Sstevel@tonic-gate 	}
7460Sstevel@tonic-gate 	if (ti->ti_nwa != ti->ti_start_address) {
7470Sstevel@tonic-gate 		err_msg(gettext(
7480Sstevel@tonic-gate 		    "Media state is not suitable for this write mode.\n"));
7490Sstevel@tonic-gate 		exit(1);
7500Sstevel@tonic-gate 	}
7510Sstevel@tonic-gate 	if (mode == TRACK_MODE_DATA) {
7520Sstevel@tonic-gate 		if (!(ti->ti_track_mode & 4)) {
7530Sstevel@tonic-gate 			/* Write track depends upon this bit */
7540Sstevel@tonic-gate 			ti->ti_track_mode |= TRACK_MODE_DATA;
7550Sstevel@tonic-gate 		}
7560Sstevel@tonic-gate 	}
7570Sstevel@tonic-gate 	size = 0;
7580Sstevel@tonic-gate 	h->bstr_size(h, &size);
7590Sstevel@tonic-gate 	h->bstr_rewind(h);
7600Sstevel@tonic-gate 	te = (struct trackio_error *)my_zalloc(sizeof (*te));
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	print_n_flush(gettext("Writing track %d..."), (int)ti->ti_track_no);
7630Sstevel@tonic-gate 	init_progress();
764370Snakanon 	if (!write_track(target, ti, h, progress, size, te)) {
7650Sstevel@tonic-gate 		if (te->err_type == TRACKIO_ERR_USER_ABORT) {
7660Sstevel@tonic-gate 			(void) str_print(gettext("Aborted.\n"), progress_pos);
7670Sstevel@tonic-gate 		} else {
7680Sstevel@tonic-gate 			if (device_type != DVD_PLUS_W) {
7690Sstevel@tonic-gate 			/* l10n_NOTE : 'failed' as in Writing Track...failed  */
7700Sstevel@tonic-gate 				(void) str_print(gettext("failed.\n"),
7710Sstevel@tonic-gate 				    progress_pos);
7720Sstevel@tonic-gate 			}
7730Sstevel@tonic-gate 		}
7740Sstevel@tonic-gate 	}
7750Sstevel@tonic-gate 	/* l10n_NOTE : 'done' as in "Writing track 1...done"  */
7760Sstevel@tonic-gate 	(void) str_print(gettext("done.\n"), progress_pos);
7770Sstevel@tonic-gate 	free(ti);
7780Sstevel@tonic-gate 	free(te);
7790Sstevel@tonic-gate }
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate void
list(void)7820Sstevel@tonic-gate list(void)
7830Sstevel@tonic-gate {
7840Sstevel@tonic-gate 	if (scan_for_cd_device(SCAN_LISTDEVS, NULL) == 0) {
7850Sstevel@tonic-gate 		if (vol_running) {
7860Sstevel@tonic-gate 			err_msg(gettext(
7876222Szk194757 			    "No CD writers found, no media in the drive "
7886222Szk194757 			    "or not on the console.\n"));
7890Sstevel@tonic-gate 		} else {
7900Sstevel@tonic-gate 			if (cur_uid != 0) {
7910Sstevel@tonic-gate 				err_msg(gettext(
7920Sstevel@tonic-gate 				    "Volume manager is not running.\n"));
7930Sstevel@tonic-gate 				err_msg(gettext(
7940Sstevel@tonic-gate "Please start volume manager or run cdrw as root to access all devices.\n"));
7950Sstevel@tonic-gate 			} else {
7960Sstevel@tonic-gate 				err_msg(gettext("No CD writers found.\n"));
7970Sstevel@tonic-gate 			}
7980Sstevel@tonic-gate 		}
7990Sstevel@tonic-gate 	}
8000Sstevel@tonic-gate 	exit(0);
8010Sstevel@tonic-gate }
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate void
get_media_type(int fd)8040Sstevel@tonic-gate get_media_type(int fd)
8050Sstevel@tonic-gate {
8061318Sec158148 	uchar_t *cap = (uchar_t *)my_zalloc(MMC_FTR_HDR_LEN);
8070Sstevel@tonic-gate 
8081318Sec158148 	if (get_configuration(fd, MMC_FTR_PRFL_LIST,
8091318Sec158148 	    MMC_FTR_HDR_LEN, cap)) {
8101318Sec158148 		if (debug)
8111318Sec158148 			(void) print_profile_list(fd);
8121318Sec158148 		switch (read_scsi16(&cap[6])) {
8130Sstevel@tonic-gate 			case 0x8: /* CD-ROM */
8140Sstevel@tonic-gate 				if (debug)
8150Sstevel@tonic-gate 					(void) printf("CD-ROM found\n");
8160Sstevel@tonic-gate 				/*
8170Sstevel@tonic-gate 				 * To avoid regression issues, treat as
8180Sstevel@tonic-gate 				 * A cdrw, we will check the writable
8190Sstevel@tonic-gate 				 * mode page to see if the media is
8200Sstevel@tonic-gate 				 * actually writable.
8210Sstevel@tonic-gate 				 */
8220Sstevel@tonic-gate 				device_type = CD_RW;
8230Sstevel@tonic-gate 				break;
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 			case 0x9: /* CD-R */
8260Sstevel@tonic-gate 				if (debug)
8270Sstevel@tonic-gate 					(void) printf("CD-R found\n");
8280Sstevel@tonic-gate 				device_type = CD_RW;
8290Sstevel@tonic-gate 				break;
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 			case 0x10: /* DVD-ROM */
8320Sstevel@tonic-gate 				/*
8330Sstevel@tonic-gate 				 * Have seen drives return DVD+RW media
8340Sstevel@tonic-gate 				 * DVD-ROM, so try treating it as a DVD+RW
8350Sstevel@tonic-gate 				 * profile. checking for writable media
8360Sstevel@tonic-gate 				 * is done through mode page 5.
8370Sstevel@tonic-gate 				 */
8380Sstevel@tonic-gate 				if (debug)
8390Sstevel@tonic-gate 					(void) printf("DVD-ROM found\n");
8400Sstevel@tonic-gate 				device_type = DVD_PLUS_W;
8410Sstevel@tonic-gate 				break;
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 			case 0xA: /* CD-RW */
8440Sstevel@tonic-gate 				if (debug)
8450Sstevel@tonic-gate 					(void) printf("CD-RW found\n");
8460Sstevel@tonic-gate 				device_type = CD_RW;
8470Sstevel@tonic-gate 				break;
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 			case 0x11: /* DVD-R */
8500Sstevel@tonic-gate 				if (debug)
8510Sstevel@tonic-gate 					(void) printf("DVD-R found\n");
8520Sstevel@tonic-gate 				device_type = DVD_MINUS;
8530Sstevel@tonic-gate 				break;
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 			case 0x12: /* DVD-RAM */
8560Sstevel@tonic-gate 				if (debug)
8570Sstevel@tonic-gate 					(void) printf("DVD-RAM found\n");
8580Sstevel@tonic-gate 				/* treat as CD-RW, may be a legacy drive */
8590Sstevel@tonic-gate 				device_type = CD_RW;
8600Sstevel@tonic-gate 				break;
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 			case 0x13: /* DVD-RW restricted overwrite */
8636222Szk194757 			case 0x14: /* DVD-RW sequential */
8640Sstevel@tonic-gate 				if (debug)
8650Sstevel@tonic-gate 					(void) printf("DVD-RW found\n");
8660Sstevel@tonic-gate 				device_type = DVD_MINUS;
8670Sstevel@tonic-gate 				break;
8680Sstevel@tonic-gate 
8696540Szk194757 			case 0x15: /* DVD-R Dual Layer Sequential Recording */
8706540Szk194757 			case 0x16: /* DVD-R Dual Layer Jump Recording */
8716540Szk194757 				if (debug)
8726540Szk194757 					(void) printf("DVD-R DL found\n");
8736540Szk194757 				device_type = DVD_MINUS;
8746540Szk194757 				break;
8756540Szk194757 
8766540Szk194757 			case 0x17: /* DVD-RW Dual Layer */
8776540Szk194757 				if (debug)
8786540Szk194757 					(void) printf("DVD-RW DL found\n");
8796540Szk194757 				device_type = DVD_MINUS;
8806540Szk194757 				break;
8816540Szk194757 
8820Sstevel@tonic-gate 			case 0x1A: /* DVD+RW */
8830Sstevel@tonic-gate 				if (debug)
8840Sstevel@tonic-gate 					(void) printf("DVD+RW found\n");
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 				device_type = DVD_PLUS_W;
8870Sstevel@tonic-gate 				break;
8886540Szk194757 
8890Sstevel@tonic-gate 			case 0x1B: /* DVD+R */
8900Sstevel@tonic-gate 				if (debug)
8910Sstevel@tonic-gate 					(void) printf("DVD+R found\n");
8920Sstevel@tonic-gate 				device_type = DVD_PLUS;
8930Sstevel@tonic-gate 				break;
8940Sstevel@tonic-gate 
8956540Szk194757 			case 0x2A: /* DVD+RW Dual Layer */
8966540Szk194757 				if (debug)
8976540Szk194757 					(void) printf("DVD+RW DL found\n");
8986540Szk194757 				device_type = DVD_PLUS_W;
8996540Szk194757 				break;
9006540Szk194757 
9016540Szk194757 			case 0x2B: /* DVD+R Dual Layer */
9026540Szk194757 				if (debug)
9036540Szk194757 					(void) printf("DVD+R DL found\n");
9046540Szk194757 				device_type = DVD_PLUS;
9056540Szk194757 				break;
9066540Szk194757 
9070Sstevel@tonic-gate 			default:
9080Sstevel@tonic-gate 				if (debug)
9090Sstevel@tonic-gate 					(void) printf(
9106222Szk194757 					    "unknown drive found\n type = 0x%x",
9116222Szk194757 					    cap[7]);
9120Sstevel@tonic-gate 				/*
9130Sstevel@tonic-gate 				 * Treat as CD_RW to avoid regression, may
9140Sstevel@tonic-gate 				 * be a legacy drive.
9150Sstevel@tonic-gate 				 */
9160Sstevel@tonic-gate 				device_type = CD_RW;
9170Sstevel@tonic-gate 		}
9180Sstevel@tonic-gate 	}
9191318Sec158148 	free(cap);
9200Sstevel@tonic-gate }
921936Sarutz 
922936Sarutz /* Translate a transfer rate (eg, KB/s) into a Speed (eg, "2X") */
923936Sarutz uint_t
cdrw_bandwidth_to_x(uint_t rate)924936Sarutz cdrw_bandwidth_to_x(uint_t rate)
925936Sarutz {
926936Sarutz 	switch (device_type) {
927936Sarutz 	case DVD_PLUS_W:
928936Sarutz 	case DVD_MINUS:
929936Sarutz 	case DVD_PLUS:
930936Sarutz 		return (DVD_RATE_TO_X(rate));
931936Sarutz 
932936Sarutz 	default:
933936Sarutz 	case CD_RW:
934936Sarutz 		return (CD_RATE_TO_X(rate));
935936Sarutz 	}
936936Sarutz }
937936Sarutz 
938936Sarutz /* Translate a Speed (eg, "2X") into a transfer rate (eg, KB/s) */
939936Sarutz uint_t
cdrw_x_to_bandwidth(uint_t x)940936Sarutz cdrw_x_to_bandwidth(uint_t x)
941936Sarutz {
942936Sarutz 	switch (device_type) {
943936Sarutz 	case DVD_PLUS_W:
944936Sarutz 	case DVD_MINUS:
945936Sarutz 	case DVD_PLUS:
946936Sarutz 		return (DVD_X_TO_RATE(x));
947936Sarutz 
948936Sarutz 	default:
949936Sarutz 	case CD_RW:
950936Sarutz 		return (CD_X_TO_RATE(x));
951936Sarutz 	}
952936Sarutz }
953