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 2004 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(void *arg, int64_t completed) 196 { 197 char s[BUFSIZE]; 198 uint64_t total = (uintptr_t)arg & 0xffffffff; 199 if (completed == -1) { 200 /* Got ^C. Add 2 to progress pos to compensate for ^ and C */ 201 progress_pos = str_print("(flushing ...)", progress_pos+2); 202 return (0); 203 } 204 if (total == 0) { 205 if (tm != time(NULL)) { 206 tm = time(NULL); 207 (void) snprintf(s, BUFSIZE, 208 gettext("%d bytes written"), completed); 209 210 progress_pos = str_print(s, progress_pos); 211 } 212 } else { 213 total = (((uint64_t)completed) * 100)/total; 214 if (total == last_total) 215 return (0); 216 last_total = total; 217 if (total > 100) { 218 /* There is clearly a miscalculation somewhere */ 219 if (debug) 220 (void) printf("\nWrote more than 100 %% !!\n"); 221 return (0); 222 } 223 if (total == 100) { 224 /* l10n_NOTE : 'done' as in "Writing track 1...done" */ 225 (void) snprintf(s, BUFSIZE, gettext("done.\n")); 226 } else { 227 (void) snprintf(s, BUFSIZE, "%d %%", (uint_t)total); 228 } 229 progress_pos = str_print(s, progress_pos); 230 } 231 return (0); 232 } 233 234 void 235 raise_priv(void) 236 { 237 if (priv_change_needed && (cur_uid != 0)) { 238 if (seteuid(0) == 0) 239 cur_uid = 0; 240 } 241 } 242 243 void 244 lower_priv(void) 245 { 246 if (priv_change_needed && (cur_uid == 0)) { 247 if (seteuid(ruid) == 0) 248 cur_uid = ruid; 249 } 250 } 251 252 int 253 check_auth(uid_t uid) 254 { 255 struct passwd *pw; 256 257 258 pw = getpwuid(uid); 259 260 if (pw == NULL) { 261 /* fail if we cannot get password entry */ 262 return (0); 263 } 264 265 /* 266 * check in the RBAC authority files to see if 267 * the user has permission to use CDRW 268 */ 269 if (chkauthattr(CDRW_AUTH, pw->pw_name) != 1) { 270 /* user is not in database, return failure */ 271 return (0); 272 } else { 273 return (1); 274 } 275 } 276 277 /* 278 * This will busy delay in ms milliseconds. Needed for cases 279 * where 1 sec wait is too long. This is needed for some newer 280 * drives which can empty the drive cache very quickly. 281 */ 282 void 283 ms_delay(uint_t ms) 284 { 285 286 hrtime_t start, req; 287 288 start = gethrtime(); 289 req = start + ((hrtime_t)ms * 1000000); 290 291 while (gethrtime() < req) 292 yield(); 293 } 294