xref: /illumos-gate/usr/src/cmd/cdrw/util.c (revision 533affcbc7fc4d0c8132976ea454aaa715fe2307)
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