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