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