"Fossies" - the Fresh Open Source Software Archive 
Member "xorriso-1.5.4/libburn/sg-solaris.c" (30 Jan 2021, 27969 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "sg-solaris.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
1.5.2_vs_1.5.4.
1 /* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
2
3 /*
4 Copyright (c) 2010 - 2016 Thomas Schmitt <scdbackup@gmx.net>
5 Provided under GPL version 2 or later.
6 */
7
8
9 /*
10
11 This is the main operating system dependent SCSI part of libburn. It implements
12 the transport level aspects of SCSI control and command i/o.
13
14 Present implementation: Solaris uscsi, e.g. for SunOS 5.11
15
16
17 PORTING:
18
19 Porting libburn typically will consist of adding a new operating system case
20 to the following switcher files:
21 os.h Operating system specific libburn definitions and declarations.
22 sg.c Operating system dependent transport level modules.
23 and of deriving the following system specific files from existing examples:
24 os-*.h Included by os.h. You will need some general system knowledge
25 about signals and knowledge about the storage object needs of your
26 transport level module sg-*.c.
27
28 sg-*.c This source module. You will need special system knowledge about
29 how to detect all potentially available drives, how to open them,
30 eventually how to exclusively reserve them, how to perform
31 SCSI transactions, how to inquire the (pseudo-)SCSI driver.
32 You will not need to care about CD burning, MMC or other high-level
33 SCSI aspects.
34
35 Said sg-*.c operations are defined by a public function interface, which has
36 to be implemented in a way that provides libburn with the desired services:
37
38 sg_id_string() returns an id string of the SCSI transport adapter.
39 It may be called before initialization but then may
40 return only a preliminary id.
41
42 sg_initialize() performs global initialization of the SCSI transport
43 adapter and eventually needed operating system
44 facilities. Checks for compatibility of supporting
45 software components.
46
47 sg_shutdown() performs global finalizations and releases globally
48 acquired resources.
49
50 sg_give_next_adr() iterates over the set of potentially useful drive
51 address strings.
52
53 scsi_enumerate_drives() brings all available, not-whitelist-banned, and
54 accessible drives into libburn's list of drives.
55
56 sg_dispose_drive() finalizes adapter specifics of struct burn_drive
57 on destruction. Releases resources which were acquired
58 underneath scsi_enumerate_drives().
59
60 sg_drive_is_open() tells whether libburn has the given drive in use.
61
62 sg_grab() opens the drive for SCSI commands and ensures
63 undisturbed access.
64
65 sg_release() closes a drive opened by sg_grab()
66
67 sg_issue_command() sends a SCSI command to the drive, receives reply,
68 and evaluates whether the command succeeded or shall
69 be retried or finally failed.
70
71 sg_obtain_scsi_adr() tries to obtain SCSI address parameters.
72
73
74 burn_os_is_2k_seekrw() tells whether the given path leads to a file object
75 that can be used in 2 kB granularity by lseek(2),
76 read(2), and possibly write(2) if not read-only..
77 E.g. a USB stick or a hard disk.
78
79 burn_os_stdio_capacity() estimates the emulated media space of stdio-drives.
80
81 burn_os_open_track_src() opens a disk file in a way that offers best
82 throughput with file reading and/or SCSI write command
83 transmission.
84
85 burn_os_alloc_buffer() allocates a memory area that is suitable for file
86 descriptors issued by burn_os_open_track_src().
87 The buffer size may be rounded up for alignment
88 reasons.
89
90 burn_os_free_buffer() delete a buffer obtained by burn_os_alloc_buffer().
91
92 Porting hints are marked by the text "PORTING:".
93 Send feedback to libburn-hackers@pykix.org .
94
95 */
96
97 #ifdef HAVE_CONFIG_H
98 #include "../config.h"
99 #endif
100
101
102 /** PORTING : ------- OS dependent headers and definitions ------ */
103
104 #include <unistd.h>
105 #include <stropts.h>
106 #include <stdio.h>
107 #include <sys/types.h>
108 #include <errno.h>
109 #include <fcntl.h>
110 #include <sys/stat.h>
111 #include <string.h>
112 #include <stdlib.h>
113 #include <dirent.h>
114
115 #ifdef Libburn_os_has_statvfS
116 #include <sys/statvfs.h>
117 #endif /* Libburn_os_has_stavtfS */
118
119 #include <volmgt.h>
120 #include <sys/dkio.h>
121 #include <sys/vtoc.h>
122
123 #include <sys/scsi/impl/uscsi.h>
124
125
126 /* The waiting time before eventually retrying a failed SCSI command.
127 Before each retry wait Libburn_sg_linux_retry_incR longer than with
128 the previous one.
129 */
130 #define Libburn_sg_solaris_retry_usleeP 100000
131 #define Libburn_sg_solaris_retry_incR 100000
132
133
134 /** PORTING : ------ libburn portable headers and definitions ----- */
135
136 #include "transport.h"
137 #include "drive.h"
138 #include "sg.h"
139 #include "spc.h"
140 #include "sbc.h"
141 #include "debug.h"
142 #include "toc.h"
143 #include "util.h"
144 #include "init.h"
145
146 #include "libdax_msgs.h"
147 extern struct libdax_msgs *libdax_messenger;
148
149
150 /* is in portable part of libburn */
151 int burn_drive_is_banned(char *device_address);
152 int burn_drive_resolve_link(char *path, char adr[],
153 int *recursion_count, int flag); /* drive.c */
154
155 /* Whether to log SCSI commands:
156 bit0= log in /tmp/libburn_sg_command_log
157 bit1= log to stderr
158 bit2= flush every line
159 */
160 extern int burn_sg_log_scsi;
161
162
163 /* ------------------------------------------------------------------------ */
164 /* PORTING: Private definitions. Port only if needed by public functions. */
165 /* (Public functions are listed below) */
166 /* ------------------------------------------------------------------------ */
167
168
169 /* Storage object is in libburn/init.c
170 whether to strive for exclusive access to the drive
171 */
172 extern int burn_sg_open_o_excl;
173
174
175 /* ------------------------------------------------------------------------ */
176 /* PORTING: Private functions. Port only if needed by public functions */
177 /* (Public functions are listed below) */
178 /* ------------------------------------------------------------------------ */
179
180
181 static int sg_close_drive(struct burn_drive * d)
182 {
183 if (d->fd != -1) {
184 close(d->fd);
185 d->fd = -1;
186 return 1;
187 }
188 return 0;
189 }
190
191
192 static int decode_btl_number(char **cpt, int stopper, int *no)
193 {
194 *no = 0;
195 for ((*cpt)++; **cpt != stopper; (*cpt)++) {
196 if (**cpt < '0' || **cpt > '9')
197 return 0;
198 *no = *no * 10 + **cpt - '0';
199 }
200 return 1;
201 }
202
203
204 /* Read bus, target, lun from name "cXtYdZs2" or "cXtYdZ/...".
205 Return 0 if name is not of the desired form.
206 */
207 static int decode_btl_solaris(char *name, int *busno, int *tgtno, int *lunno,
208 int flag)
209 {
210 char *cpt, *cpt_mem;
211 int ret;
212
213 *busno = *tgtno = *lunno = -1;
214 cpt = name;
215 if (*cpt != 'c')
216 return 0;
217 ret = decode_btl_number(&cpt, 't', busno);
218 if (ret <= 0)
219 return ret;
220 ret = decode_btl_number(&cpt, 'd', tgtno);
221 if (ret <= 0)
222 return ret;
223 cpt_mem = cpt;
224 ret = decode_btl_number(&cpt, 's', lunno);
225 if (ret <= 0) {
226 cpt = cpt_mem;
227 ret = decode_btl_number(&cpt, '/', lunno);
228 if (ret <= 0)
229 return ret;
230 return(1);
231 }
232 cpt++;
233 if (*cpt != '2' || *(cpt + 1) != 0)
234 return 0;
235 return 1;
236 }
237
238
239 static int start_enum_cXtYdZs2(burn_drive_enumerator_t *idx, int flag)
240 {
241 DIR *dir;
242
243 idx->dir = NULL;
244 dir = opendir("/dev/rdsk");
245 if (dir == NULL) {
246 libdax_msgs_submit(libdax_messenger, -1,
247 0x0002000c, LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
248 "Cannot start device file enumeration. opendir(\"/dev/rdsk\") failed.",
249 errno, 0);
250 return 0;
251 }
252 idx->dir = dir;
253 return 1;
254 }
255
256
257 static int sg_solaris_convert_devname(char *path, char **dev_to_open, int flag)
258 {
259 char *sym_name = NULL, *media_name = NULL, *curr_name, *msg = NULL;
260 int ret;
261
262 BURN_ALLOC_MEM(msg, char, 4096);
263
264 BURN_FREE_MEM(*dev_to_open);
265 *dev_to_open = NULL;
266 curr_name = path;
267
268 if (! volmgt_running())
269 goto set_name;
270 sym_name = volmgt_symname(path);
271 sprintf(msg, "Volume Management symbolic name: '%s' -> %s",
272 path, sym_name == NULL ? "NULL" : sym_name);
273 libdax_msgs_submit(libdax_messenger, -1,
274 0x00000002,
275 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
276 msg, 0, 0);
277 if (sym_name != NULL)
278 media_name = media_findname(sym_name);
279 else
280 media_name = media_findname(path);
281 if (media_name != NULL)
282 curr_name = media_name;
283 sprintf(msg, "Media name: %s -> %s",
284 sym_name == NULL ? path : sym_name,
285 media_name == NULL ? "NULL" : media_name);
286 libdax_msgs_submit(libdax_messenger, -1,
287 0x00000002,
288 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
289 msg, 0, 0);
290 set_name:
291 BURN_ALLOC_MEM(*dev_to_open, char, strlen(curr_name) + 1);
292 strcpy(*dev_to_open, curr_name);
293 ret = 1;
294 ex:
295 if (media_name != NULL)
296 free(media_name);
297 if (sym_name != NULL)
298 free(sym_name);
299 BURN_FREE_MEM(msg);
300 return(ret);
301 }
302
303
304 static int next_enum_cXtYdZs2(burn_drive_enumerator_t *idx,
305 char adr[], int adr_size, int flag)
306 {
307 int busno, tgtno, lunno, ret, fd = -1, volpath_size = 160, os_errno;
308 char *volpath = NULL, *msg = NULL, *dev_to_open = NULL;
309 struct dirent *entry;
310 struct dk_cinfo cinfo;
311 DIR *dir;
312
313 BURN_ALLOC_MEM(volpath, char, volpath_size);
314 BURN_ALLOC_MEM(msg, char, 4096);
315
316 dir = idx->dir;
317 while (1) {
318 errno = 0;
319 entry = readdir(dir);
320 if (entry == NULL) {
321 if (errno) {
322 libdax_msgs_submit(libdax_messenger,
323 -1, 0x0002000d,
324 LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
325 "Cannot enumerate next device. readdir() from \"/dev/rdsk\" failed.",
326 errno, 0);
327 {ret = -1; goto ex;}
328 }
329 break;
330 }
331 if (strlen(entry->d_name) > (size_t) (volpath_size - 11))
332 continue;
333 ret = decode_btl_solaris(entry->d_name,
334 &busno, &tgtno, &lunno, 0);
335 if (ret <= 0)
336 continue; /* not cXtYdZs2 */
337
338 sprintf(volpath, "/dev/rdsk/%s", entry->d_name);
339 if (burn_drive_is_banned(volpath))
340 continue;
341 ret = sg_solaris_convert_devname(volpath, &dev_to_open, 0);
342 if (ret <= 0)
343 continue;
344 fd = open(dev_to_open, O_RDONLY | O_NDELAY);
345 if (fd < 0) {
346 os_errno = errno;
347 sprintf(msg, "Could not open '%s' , errno = %d",
348 dev_to_open, os_errno);
349 libdax_msgs_submit(libdax_messenger, -1,
350 0x00000002,
351 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
352 msg, os_errno, 0);
353 continue;
354 }
355 /* See man dkio */
356 ret = ioctl(fd, DKIOCINFO, &cinfo);
357 close(fd);
358 if (ret < 0) {
359 os_errno = errno;
360 sprintf(msg,
361 "ioctl(DKIOCINFO) failed on drive '%s', errno = %d",
362 volpath, os_errno);
363 libdax_msgs_submit(libdax_messenger, -1,
364 0x00000002,
365 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
366 msg, os_errno, 0);
367 continue;
368 }
369 if (cinfo.dki_ctype != DKC_CDROM) {
370 sprintf(msg,
371 "ioctl(DKIOCINFO) classifies drive '%s' as dki_ctype %ld, not as DKC_CDROM = %ld",
372 volpath, (long int) cinfo.dki_ctype,
373 (long int) DKC_CDROM);
374 libdax_msgs_submit(libdax_messenger, -1,
375 0x00000002,
376 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
377 msg, 0, 0);
378 continue;
379 }
380 if (adr_size <= (int) strlen(volpath)) {
381 sprintf(msg,
382 "Device path '%s' too long. (Max. %d)",
383 volpath, adr_size - 1);
384 libdax_msgs_submit(libdax_messenger, -1,
385 0x00000002,
386 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
387 msg, 0, 0);
388 {ret = -1; goto ex;}
389 }
390 strcpy(adr, volpath);
391 sprintf(msg, "Accepted as valid drive '%s'", volpath);
392 libdax_msgs_submit(libdax_messenger, -1,
393 0x00000002,
394 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
395 msg, 0, 0);
396 {ret = 1; goto ex;}
397 }
398 ret = 0;
399 ex:;
400 BURN_FREE_MEM(dev_to_open);
401 BURN_FREE_MEM(msg);
402 BURN_FREE_MEM(volpath);
403 return ret;
404 }
405
406
407 static int end_enum_cXtYdZs2(burn_drive_enumerator_t *idx, int flag)
408 {
409 DIR *dir;
410
411 dir = idx->dir;
412 if(dir != NULL)
413 closedir(dir);
414 idx->dir = NULL;
415 return 1;
416 }
417
418
419 /* ----------------------------------------------------------------------- */
420 /* PORTING: Private functions which contain publicly needed functionality. */
421 /* Their portable part must be performed. So it is probably best */
422 /* to replace the non-portable part and to call these functions */
423 /* in your port, too. */
424 /* ----------------------------------------------------------------------- */
425
426
427 /** Wraps a detected drive into libburn structures and hands it over to
428 libburn drive list.
429 */
430 static void enumerate_common(char *fname,
431 int bus_no, int host_no,
432 int channel_no, int target_no, int lun_no)
433 {
434 int ret;
435 struct burn_drive out;
436
437 /* General libburn drive setup */
438 burn_setup_drive(&out, fname);
439
440 /* This transport adapter uses SCSI-family commands and models
441 (seems the adapter would know better than its boss, if ever) */
442 ret = burn_scsi_setup_drive(&out, bus_no, host_no, channel_no,
443 target_no, lun_no, 0);
444 if (ret <= 0)
445 return;
446
447 /* PORTING: ------------------- non portable part --------------- */
448
449 /* Transport adapter is Solaris uscsi */
450 /* Adapter specific handles and data */
451 out.fd = -1;
452
453 /* PORTING: ---------------- end of non portable part ------------ */
454
455 /* Adapter specific functions with standardized names */
456 out.grab = sg_grab;
457 out.release = sg_release;
458 out.drive_is_open = sg_drive_is_open;
459 out.issue_command = sg_issue_command;
460 /* Finally register drive and inquire drive information */
461 burn_drive_finish_enum(&out);
462 }
463
464
465 /* ------------------------------------------------------------------------ */
466 /* PORTING: Public functions. These MUST be ported. */
467 /* ------------------------------------------------------------------------ */
468
469
470 /** Returns the id string of the SCSI transport adapter and eventually
471 needed operating system facilities.
472 This call is usable even if sg_initialize() was not called yet. In that
473 case a preliminary constant message might be issued if detailed info is
474 not available yet.
475 @param msg returns id string
476 @param flag unused yet, submit 0
477 @return 1 = success, <=0 = failure
478 */
479 int sg_id_string(char msg[1024], int flag)
480 {
481 sprintf(msg, "internal Solaris uscsi adapter sg-solaris");
482 return 1;
483 }
484
485
486 /** Performs global initialization of the SCSI transport adapter and eventually
487 needed operating system facilities. Checks for compatibility of supporting
488 software components.
489 @param msg returns ids and/or error messages of eventual helpers
490 @param flag unused yet, submit 0
491 @return 1 = success, <=0 = failure
492 */
493 int sg_initialize(char msg[1024], int flag)
494 {
495 return sg_id_string(msg, 0);
496 }
497
498
499 /** Performs global finalization of the SCSI transport adapter and eventually
500 needed operating system facilities. Releases globally acquired resources.
501 @param flag unused yet, submit 0
502 @return 1 = success, <=0 = failure
503 */
504 int sg_shutdown(int flag)
505 {
506 return 1;
507 }
508
509
510 /** Finalizes BURN_OS_TRANSPORT_DRIVE_ELEMENTS, the components of
511 struct burn_drive which are defined in os-*.h.
512 The eventual initialization of those components was made underneath
513 scsi_enumerate_drives().
514 This will be called when a burn_drive gets disposed.
515 @param d the drive to be finalized
516 @param flag unused yet, submit 0
517 @return 1 = success, <=0 = failure
518 */
519 int sg_dispose_drive(struct burn_drive *d, int flag)
520 {
521 return 1;
522 }
523
524
525 /** Returns the next index number and the next enumerated drive address.
526 The enumeration has to cover all available and accessible drives. It is
527 allowed to return addresses of drives which are not available but under
528 some (even exotic) circumstances could be available. It is on the other
529 hand allowed, only to hand out addresses which can really be used right
530 in the moment of this call. (This implementation chooses the latter.)
531 @param idx An opaque handle. Make no own theories about it.
532 @param adr Takes the reply
533 @param adr_size Gives maximum size of reply including final 0
534 @param initialize 1 = start new,
535 0 = continue, use no other values for now
536 -1 = finish
537 @return 1 = reply is a valid address , 0 = no further address available
538 -1 = severe error (e.g. adr_size too small)
539 */
540 int sg_give_next_adr(burn_drive_enumerator_t *idx,
541 char adr[], int adr_size, int initialize)
542 {
543 int ret;
544
545 if (initialize == 1) {
546 ret = start_enum_cXtYdZs2(idx, 0);
547 if (ret <= 0)
548 return ret;
549 } else if (initialize == -1) {
550 ret = end_enum_cXtYdZs2(idx, 0);
551 return 0;
552 }
553 ret = next_enum_cXtYdZs2(idx, adr, adr_size, 0);
554 return ret;
555 }
556
557
558 /** Brings all available, not-whitelist-banned, and accessible drives into
559 libburn's list of drives.
560 */
561 int scsi_enumerate_drives(void)
562 {
563 burn_drive_enumerator_t idx;
564 int initialize = 1, ret, i_bus_no = -1, buf_size = 4096;
565 int i_host_no = -1, i_channel_no = -1, i_target_no = -1, i_lun_no = -1;
566 char *buf = NULL;
567
568 BURN_ALLOC_MEM(buf, char, buf_size);
569
570 while(1) {
571 ret = sg_give_next_adr(&idx, buf, buf_size, initialize);
572 initialize = 0;
573 if (ret <= 0)
574 break;
575 if (burn_drive_is_banned(buf))
576 continue;
577 sg_obtain_scsi_adr(buf, &i_bus_no, &i_host_no,
578 &i_channel_no, &i_target_no, &i_lun_no);
579 enumerate_common(buf,
580 i_bus_no, i_host_no, i_channel_no,
581 i_target_no, i_lun_no);
582 }
583 sg_give_next_adr(&idx, buf, buf_size, -1);
584 ret = 1;
585 ex:;
586 BURN_FREE_MEM(buf);
587 return ret;
588 }
589
590
591 /** Tells whether libburn has the given drive in use or exclusively reserved.
592 If it is "open" then libburn will eventually call sg_release() on it when
593 it is time to give up usage and reservation.
594 */
595 /** Published as burn_drive.drive_is_open() */
596 int sg_drive_is_open(struct burn_drive * d)
597 {
598 return (d->fd != -1);
599 }
600
601
602 /** Opens the drive for SCSI commands and - if burn activities are prone
603 to external interference on your system - obtains an exclusive access lock
604 on the drive. (Note: this is not physical tray locking.)
605 A drive that has been opened with sg_grab() will eventually be handed
606 over to sg_release() for closing and unreserving.
607 */
608 int sg_grab(struct burn_drive *d)
609 {
610 char *msg = NULL, *dev_to_open = NULL;
611 int os_errno, ret;
612 struct dk_cinfo cinfo;
613
614 BURN_ALLOC_MEM(msg, char, 4096);
615
616 if (d->fd != -1) {
617 d->released = 0;
618 {ret = 1; goto ex;}
619 }
620 ret = sg_solaris_convert_devname(d->devname, &dev_to_open, 0);
621 if (ret <= 0)
622 goto ex;
623 d->fd = open(dev_to_open, O_RDONLY | O_NDELAY);
624 if (d->fd == -1) {
625 os_errno = errno;
626 sprintf(msg, "Could not grab drive '%s'",
627 d->devname);
628 if (strcmp(d->devname, dev_to_open))
629 sprintf(msg + strlen(msg), " via '%s'", dev_to_open);
630 libdax_msgs_submit(libdax_messenger, d->global_index,
631 0x00020003,
632 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
633 msg, os_errno, 0);
634 {ret = 0; goto ex;}
635 }
636 ret = ioctl(d->fd, DKIOCINFO, &cinfo);
637 if (ret < 0) {
638 os_errno = errno;
639 sprintf(msg, "ioctl(DKIOCINFO) failed on drive '%s'",
640 d->devname);
641 libdax_msgs_submit(libdax_messenger, d->global_index,
642 0x00000002,
643 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
644 msg, os_errno, 0);
645 goto revoke;
646 }
647 if (cinfo.dki_ctype != DKC_CDROM) {
648 sprintf(msg,
649 "ioctl(DKIOCINFO) classifies drive '%s' as dki_ctype %ld, not as DKC_CDROM = %ld",
650 d->devname, (long int) cinfo.dki_ctype,
651 (long int) DKC_CDROM);
652 libdax_msgs_submit(libdax_messenger, d->global_index,
653 0x00000002,
654 LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
655 msg, 0, 0);
656 goto revoke;
657 }
658
659 /* >>> obtain eventual locks */;
660
661 d->released = 0;
662 {ret = 1; goto ex;}
663 revoke:;
664 sprintf(msg, "Could not grab drive '%s'. Not a CDROM device.",
665 d->devname);
666 libdax_msgs_submit(libdax_messenger, d->global_index,
667 0x00020003,
668 LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
669 msg, 0, 0);
670 ret = 0;
671 ex:;
672 BURN_FREE_MEM(dev_to_open);
673 BURN_FREE_MEM(msg);
674 return ret;
675 }
676
677
678 /** PORTING: Is mainly about the call to sg_close_drive() and whether it
679 implements the demanded functionality.
680 */
681 /** Gives up the drive for SCSI commands and releases eventual access locks.
682 (Note: this is not physical tray locking.)
683 */
684 int sg_release(struct burn_drive *d)
685 {
686 if (d->fd < 0)
687 return 0;
688 sg_close_drive(d);
689 return 0;
690 }
691
692
693 /** Sends a SCSI command to the drive, receives reply and evaluates whether
694 the command succeeded or shall be retried or finally failed.
695 Returned SCSI errors shall not lead to a return value indicating failure.
696 The callers get notified by c->error. An SCSI failure which leads not to
697 a retry shall be notified via scsi_notify_error().
698 The Libburn_log_sg_commandS facility might be of help when problems with
699 a drive have to be examined. It shall stay disabled for normal use.
700 @return: 1 success , <=0 failure
701 */
702 int sg_issue_command(struct burn_drive *d, struct command *c)
703 {
704 int i, timeout_ms, ret, key, asc, ascq, done = 0, sense_len;
705 time_t start_time;
706 struct uscsi_cmd cgc;
707 char msg[80];
708 static FILE *fp = NULL;
709
710 c->error = 0;
711 memset(c->sense, 0, sizeof(c->sense));
712
713 if (d->fd == -1)
714 return 0;
715
716 if (burn_sg_log_scsi & 1) {
717 if (fp == NULL) {
718 fp= fopen("/tmp/libburn_sg_command_log", "a");
719 fprintf(fp,
720 "\n-----------------------------------------\n");
721 }
722 }
723 if (burn_sg_log_scsi & 3)
724 scsi_log_cmd(c,fp,0);
725
726 if (c->timeout > 0)
727 timeout_ms = c->timeout;
728 else
729 timeout_ms = 200000;
730 memset (&cgc, 0, sizeof (struct uscsi_cmd));
731 /* No error messages, no retries,
732 do not execute with other commands, request sense data
733 */
734 cgc.uscsi_flags = USCSI_SILENT | USCSI_DIAGNOSE | USCSI_ISOLATE
735 | USCSI_RQENABLE;
736 cgc.uscsi_timeout = timeout_ms / 1000;
737 cgc.uscsi_cdb = (caddr_t) c->opcode;
738 cgc.uscsi_bufaddr = (caddr_t) c->page->data;
739 if (c->dir == TO_DRIVE) {
740 cgc.uscsi_flags |= USCSI_WRITE;
741 cgc.uscsi_buflen = c->page->bytes;
742 } else if (c->dir == FROM_DRIVE) {
743 cgc.uscsi_flags |= USCSI_READ;
744 if (c->dxfer_len >= 0)
745 cgc.uscsi_buflen = c->dxfer_len;
746 else
747 cgc.uscsi_buflen = BUFFER_SIZE;
748 /* touch page so we can use valgrind */
749 memset(c->page->data, 0, BUFFER_SIZE);
750 } else {
751 cgc.uscsi_buflen = 0;
752 }
753 cgc.uscsi_cdblen = c->oplen;
754 cgc.uscsi_rqlen = sizeof(c->sense);
755 cgc.uscsi_rqbuf = (caddr_t) c->sense;
756
757 /* ts B90523 : Record effective transfer length request for debugging*/
758 c->dxfer_len = cgc.uscsi_buflen;
759
760 /* retry-loop */
761 start_time = time(NULL);
762 for(i = 0; !done; i++) {
763
764 memset(c->sense, 0, sizeof(c->sense));
765 c->start_time = burn_get_time(0);
766
767 ret = ioctl(d->fd, USCSICMD, &cgc);
768
769 c->end_time = burn_get_time(0);
770
771 /* For cgc.uscsi_status see SAM-3 5.3.1, Table 22
772 0 = GOOD , 2 = CHECK CONDITION : Sense Data are delivered
773 8 = BUSY
774 */
775 if (ret != 0 && cgc.uscsi_status != 2) {
776 sprintf(msg,
777 "Failed to transfer command to drive. (uscsi_status = 0x%X)",
778 (unsigned int) cgc.uscsi_status),
779 libdax_msgs_submit(libdax_messenger,
780 d->global_index, 0x0002010c,
781 LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
782 msg, errno, 0);
783 sg_close_drive(d);
784 d->released = 1;
785 d->busy = BURN_DRIVE_IDLE;
786 c->error = 1;
787 return -1;
788 }
789
790
791 /* >>> Should replace "18" by realistic sense length.
792 What's about following older remark ?
793 */
794 /* >>> valid sense: cgc.uscsi_rqlen - cgc.uscsi_rqresid */;
795
796 spc_decode_sense(c->sense, 0, &key, &asc, &ascq);
797 if (key || asc || ascq)
798 sense_len = 18;
799 else
800 sense_len = 0;
801 done = scsi_eval_cmd_outcome(d, c, fp, c->sense, sense_len,
802 start_time, timeout_ms, i, 0);
803 if (d->cancel)
804 done = 1;
805 if (!done)
806 spc_register_retry(c);
807
808 } /* end of retry-loop */
809
810 return 1;
811 }
812
813
814 /** Tries to obtain SCSI address parameters.
815 @return 1 is success , 0 is failure
816 */
817 int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
818 int *target_no, int *lun_no)
819 {
820 int ret;
821
822 /* Try to guess from path */
823 if (strncmp("/dev/rdsk/", path, 10) == 0) {
824 ret = decode_btl_solaris(path + 10,
825 bus_no, target_no, lun_no, 0);
826 if (ret > 0) {
827 *host_no = *bus_no;
828 *channel_no = 0;
829 return 1;
830 }
831 }
832 *bus_no = *host_no = *channel_no = *target_no = *lun_no = -1;
833
834 /* >>> Could need a ioctl which gives SCSI numbers */;
835
836 return (0);
837 }
838
839
840 /** Tells whether a text is a persistent address as listed by the enumeration
841 functions.
842 */
843
844 #ifndef NIX
845
846 int sg_is_enumerable_adr(char* path)
847 {
848 int ret;
849 int bus_no, target_no, lun_no;
850 struct stat stbuf;
851
852 if (strncmp("/dev/rdsk/", path, 10) != 0)
853 return 0;
854 ret = decode_btl_solaris(path + 10, &bus_no, &target_no, &lun_no, 0);
855 if (ret <= 0)
856 return 0;
857 if (stat(path, &stbuf) == -1)
858 return 0;
859 return 1;
860 }
861
862 #else /* ! NIX */
863
864 int sg_is_enumerable_adr(char* adr)
865 {
866 burn_drive_enumerator_t idx;
867 int initialize = 1, ret;
868 char buf[64];
869
870 while(1) {
871 ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
872 initialize = 0;
873 if (ret <= 0)
874 break;
875 if (strcmp(adr, buf) == 0) {
876 sg_give_next_adr(&idx, buf, sizeof(buf), -1);
877 return 1;
878 }
879 }
880 sg_give_next_adr(&idx, buf, sizeof(buf), -1);
881 return (0);
882 }
883 #endif /* NIX */
884
885
886
887
888 /* Return 1 if the given path leads to a regular file or a device that can be
889 fseeked, read, and possibly written with 2 kB granularity.
890 */
891 int burn_os_is_2k_seekrw(char *path, int flag)
892 {
893 struct stat stbuf;
894
895 if (stat(path, &stbuf) == -1)
896 return 0;
897 if (S_ISREG(stbuf.st_mode))
898 return 1;
899 if (S_ISBLK(stbuf.st_mode))
900 return 1;
901 return 0;
902 }
903
904
905 /** Estimate the potential payload capacity of a file address.
906 @param path The address of the file to be examined. If it does not
907 exist yet, then the directory will be inquired.
908 @param bytes The pointed value gets modified, but only if an estimation is
909 possible.
910 @return -2 = cannot perform necessary operations on file object
911 -1 = neither path nor dirname of path exist
912 0 = could not estimate size capacity of file object
913 1 = estimation has been made, bytes was set
914 */
915 int burn_os_stdio_capacity(char *path, off_t write_start, off_t *bytes)
916 {
917 struct stat stbuf;
918 int ret;
919
920 #ifdef Libburn_os_has_statvfS
921 struct statvfs vfsbuf;
922 #endif
923
924 char *testpath = NULL, *cpt;
925 off_t add_size = 0;
926
927 BURN_ALLOC_MEM(testpath, char, 4096);
928
929 testpath[0] = 0;
930 if (stat(path, &stbuf) == -1) {
931 strcpy(testpath, path);
932 cpt = strrchr(testpath, '/');
933 if(cpt == NULL)
934 strcpy(testpath, ".");
935 else if(cpt == testpath)
936 testpath[1] = 0;
937 else
938 *cpt = 0;
939 if (stat(testpath, &stbuf) == -1)
940 {ret = -1; goto ex;}
941
942 } else if(S_ISBLK(stbuf.st_mode)) {
943 int open_mode = O_RDONLY, fd;
944
945 fd = open(path, open_mode);
946 if (fd == -1)
947 {ret = -2; goto ex;}
948 *bytes = lseek(fd, 0, SEEK_END);
949 close(fd);
950 if (*bytes == -1) {
951 *bytes = 0;
952 {ret = 0; goto ex;}
953 }
954
955 } else if(S_ISREG(stbuf.st_mode)) {
956 add_size = burn_sparse_file_addsize(write_start, &stbuf);
957 strcpy(testpath, path);
958 } else
959 {ret = 0; goto ex;}
960
961 if (testpath[0]) {
962
963 #ifdef Libburn_os_has_statvfS
964
965 if (statvfs(testpath, &vfsbuf) == -1)
966 {ret = -2; goto ex;}
967 *bytes = add_size + ((off_t) vfsbuf.f_frsize) *
968 (off_t) vfsbuf.f_bavail;
969
970 #else /* Libburn_os_has_statvfS */
971
972 {ret = 0; goto ex;}
973
974 #endif /* ! Libburn_os_has_stavtfS */
975
976 }
977 ret = 1;
978 ex:;
979 BURN_FREE_MEM(testpath);
980 return ret;
981 }
982
983
984 /* ts A91122 : an interface to open(O_DIRECT) or similar OS tricks. */
985
986 #ifdef Libburn_read_o_direcT
987
988 /* No special O_DIRECT-like precautions are implemented here */
989
990 #endif /* Libburn_read_o_direcT */
991
992
993 int burn_os_open_track_src(char *path, int open_flags, int flag)
994 {
995 int fd;
996
997 fd = open(path, open_flags);
998 return fd;
999 }
1000
1001
1002 void *burn_os_alloc_buffer(size_t amount, int flag)
1003 {
1004 void *buf = NULL;
1005
1006 buf = calloc(1, amount);
1007 return buf;
1008 }
1009
1010
1011 int burn_os_free_buffer(void *buffer, size_t amount, int flag)
1012 {
1013 if (buffer == NULL)
1014 return 0;
1015 free(buffer);
1016 return 1;
1017 }
1018