Home | History | Annotate | Download | only in cdrw
      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, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <stdlib.h>
     30 #include <sys/types.h>
     31 #include <errno.h>
     32 #include <stdlib.h>
     33 #include <string.h>
     34 #include <unistd.h>
     35 #include <libintl.h>
     36 #include <time.h>
     37 #include <pwd.h>
     38 #include <auth_attr.h>
     39 #include <auth_list.h>
     40 #include <secdb.h>
     41 
     42 #include "transport.h"
     43 #include "util.h"
     44 #include "mmc.h"
     45 #include "msgs.h"
     46 #include "misc_scsi.h"
     47 #include "main.h"
     48 #include "trackio.h"
     49 #include "bstream.h"
     50 
     51 char strbuf[81];
     52 int priv_change_needed = 0;
     53 
     54 void *
     55 my_zalloc(size_t size)
     56 {
     57 	void *ret;
     58 
     59 	ret = malloc(size);
     60 	if (ret == NULL) {
     61 
     62 		/* Lets wait a sec. and try again */
     63 		if (errno == EAGAIN) {
     64 			(void) sleep(1);
     65 			ret = malloc(size);
     66 		}
     67 
     68 		if (ret == NULL) {
     69 			(void) err_msg("%s\n", gettext(strerror(errno)));
     70 			(void) err_msg(gettext(
     71 			    "Memory allocation failure, Exiting...\n"));
     72 			exit(1);
     73 		}
     74 	}
     75 	(void) memset(ret, 0, size);
     76 	return (ret);
     77 }
     78 
     79 /*
     80  * Prints a string after going back pos number of steps.
     81  * Mainly used to show %age complete.
     82  */
     83 int
     84 str_print(char *str, int pos)
     85 {
     86 	if ((pos > 0) && (pos < 80)) {
     87 		(void) memset(strbuf, 8, pos);
     88 		strbuf[pos] = 0;
     89 		(void) printf(strbuf);
     90 		(void) memset(strbuf, ' ', pos);
     91 		strbuf[pos] = 0;
     92 		(void) printf(strbuf);
     93 		(void) memset(strbuf, 8, pos);
     94 		strbuf[pos] = 0;
     95 		(void) printf(strbuf);
     96 	}
     97 
     98 	(void) printf("%s", str);
     99 	(void) fflush(stdout);
    100 	return (strlen(str));
    101 }
    102 
    103 /*
    104  * dump the trackio_error struct.
    105  */
    106 void
    107 print_trackio_error(struct trackio_error *te)
    108 {
    109 	char *msg, *msg1;
    110 
    111 	msg = gettext("System could not supply data at the required rate.\n");
    112 	msg1 = gettext("Try using a lower speed for write\n");
    113 
    114 	switch (te->err_type) {
    115 	case TRACKIO_ERR_SYSTEM:
    116 		err_msg(gettext("System error: %s\n"), strerror(te->te_errno));
    117 		return;
    118 	case TRACKIO_ERR_TRANSPORT:
    119 		err_msg(gettext("Transport mechanism error:\n"));
    120 		if (te->status == 2) {
    121 			if ((te->key == 3) && (te->asc == 0x0c) &&
    122 			    (te->ascq == 9)) {
    123 				err_msg(msg);
    124 				err_msg(msg1);
    125 				return;
    126 			}
    127 			if (te->key == 3) {
    128 				err_msg(gettext("Bad media.\n"));
    129 				return;
    130 			}
    131 			if (debug) {
    132 				err_msg("Sense key %x, asc/asq %x/%x\n",
    133 				    te->key, te->asc, te->ascq);
    134 			} else {
    135 				err_msg(gettext("I/O error\n"));
    136 			}
    137 			return;
    138 		}
    139 		if (te->te_errno != 0)
    140 			err_msg("%s\n", strerror(te->te_errno));
    141 		return;
    142 	case TRACKIO_ERR_USER_ABORT:
    143 		err_msg(gettext("User abort.\n"));
    144 		return;
    145 	default:
    146 		err_msg(gettext("Unknown error type.\n"));
    147 		if (debug) {
    148 			err_msg("Trackio err type %d\n", te->err_type);
    149 		}
    150 	}
    151 }
    152 
    153 char *
    154 get_err_str(void)
    155 {
    156 	if (str_errno != 0)
    157 		return (str_errno_to_string(str_errno));
    158 	return (strerror(errno));
    159 }
    160 
    161 int
    162 get_audio_type(char *ext)
    163 {
    164 	if ((strcasecmp(ext, "au") == 0) ||
    165 	    (strcasecmp(ext, "sun") == 0))
    166 		return (AUDIO_TYPE_SUN);
    167 	if ((strcasecmp(ext, "wav") == 0) ||
    168 	    (strcasecmp(ext, "riff") == 0))
    169 		return (AUDIO_TYPE_WAV);
    170 	if (strcasecmp(ext, "cda") == 0)
    171 		return (AUDIO_TYPE_CDA);
    172 	if (strcasecmp(ext, "aur") == 0)
    173 		return (AUDIO_TYPE_AUR);
    174 
    175 	return (-1);
    176 }
    177 
    178 /*
    179  * common routines for showing progress.
    180  */
    181 
    182 int progress_pos;
    183 static uint64_t last_total;
    184 time_t tm;
    185 
    186 void
    187 init_progress(void)
    188 {
    189 	progress_pos = 0;
    190 	last_total = 0;
    191 	tm = time(NULL);
    192 }
    193 
    194 int
    195 progress(int64_t arg, int64_t completed)
    196 {
    197 	char s[BUFSIZE];
    198 	uint64_t total = (uint64_t)arg;
    199 
    200 	if (completed == -1) {
    201 		/* Got ^C. Add 2 to progress pos to compensate for ^ and C */
    202 		progress_pos = str_print("(flushing ...)", progress_pos+2);
    203 		return (0);
    204 	}
    205 	if (total == 0) {
    206 		if (tm != time(NULL)) {
    207 			tm = time(NULL);
    208 			(void) snprintf(s, BUFSIZE,
    209 			    gettext("%d bytes written"), completed);
    210 
    211 			progress_pos = str_print(s, progress_pos);
    212 		}
    213 	} else {
    214 		total = (((uint64_t)completed) * 100)/total;
    215 		if (total == last_total)
    216 			return (0);
    217 		last_total = total;
    218 		if (total > 100) {
    219 			/* There is clearly a miscalculation somewhere */
    220 			if (debug)
    221 				(void) printf("\nWrote more than 100 %% !!\n");
    222 			return (0);
    223 		}
    224 		if (total == 100) {
    225 			/* l10n_NOTE : 'done' as in "Writing track 1...done"  */
    226 			(void) snprintf(s, BUFSIZE, gettext("done.\n"));
    227 		} else {
    228 			(void) snprintf(s, BUFSIZE, "%d %%", (uint_t)total);
    229 		}
    230 		progress_pos = str_print(s, progress_pos);
    231 	}
    232 	return (0);
    233 }
    234 
    235 void
    236 raise_priv(void)
    237 {
    238 	if (priv_change_needed && (cur_uid != 0)) {
    239 		if (seteuid(0) == 0)
    240 			cur_uid = 0;
    241 	}
    242 }
    243 
    244 void
    245 lower_priv(void)
    246 {
    247 	if (priv_change_needed && (cur_uid == 0)) {
    248 		if (seteuid(ruid) == 0)
    249 			cur_uid = ruid;
    250 	}
    251 }
    252 
    253 int
    254 check_auth(uid_t uid)
    255 {
    256 	struct passwd *pw;
    257 
    258 
    259 	pw = getpwuid(uid);
    260 
    261 	if (pw == NULL) {
    262 		/* fail if we cannot get password entry */
    263 		return (0);
    264 	}
    265 
    266 	/*
    267 	 * check in the RBAC authority files to see if
    268 	 * the user has permission to use CDRW
    269 	 */
    270 	if (chkauthattr(CDRW_AUTH, pw->pw_name) != 1) {
    271 		/* user is not in database, return failure */
    272 		return (0);
    273 	} else {
    274 		return (1);
    275 	}
    276 }
    277 
    278 /*
    279  * This will busy delay in ms milliseconds. Needed for cases
    280  * where 1 sec wait is too long. This is needed for some newer
    281  * drives which can empty the drive cache very quickly.
    282  */
    283 void
    284 ms_delay(uint_t ms)
    285 {
    286 
    287 	hrtime_t start, req;
    288 
    289 	start = gethrtime();
    290 	req = start + ((hrtime_t)ms * 1000000);
    291 
    292 	while (gethrtime() < req)
    293 		yield();
    294 }
    295