You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

911 lines
25 KiB

  1. /* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
  2. /*
  3. Copyright (c) 2010 - 2016 Thomas Schmitt <scdbackup@gmx.net>
  4. Provided under GPL version 2 or later.
  5. Derived 2014 from libburn/sg-solaris.c with information learned from
  6. dvd+rw-tools, http://fxr.watson.org/fxr/source/sys/scsiio.h?v=NETBSD,
  7. http://netbsd.gw.com/cgi-bin/man-cgi?scsi+4+NetBSD-current,
  8. and experiments made by Freddy Fisker.
  9. Adapted 2016 to OpenBSD by help of SASANO Takayoshi <uaa@mx5.nisiq.net>.
  10. */
  11. /*
  12. This is the main operating system dependent SCSI part of libburn. It implements
  13. the transport level aspects of SCSI control and command i/o.
  14. Present implementation: NetBSD 6, ioctl SCIOCCOMMAND
  15. OpenBSD 5.9, ioctl SCIOCCOMMAND
  16. PORTING:
  17. Porting libburn typically will consist of adding a new operating system case
  18. to the following switcher files:
  19. os.h Operating system specific libburn definitions and declarations.
  20. sg.c Operating system dependent transport level modules.
  21. and of deriving the following system specific files from existing examples:
  22. os-*.h Included by os.h. You will need some general system knowledge
  23. about signals and knowledge about the storage object needs of your
  24. transport level module sg-*.c.
  25. sg-*.c This source module. You will need special system knowledge about
  26. how to detect all potentially available drives, how to open them,
  27. eventually how to exclusively reserve them, how to perform
  28. SCSI transactions, how to inquire the (pseudo-)SCSI driver.
  29. You will not need to care about CD burning, MMC or other high-level
  30. SCSI aspects.
  31. Said sg-*.c operations are defined by a public function interface, which has
  32. to be implemented in a way that provides libburn with the desired services:
  33. sg_id_string() returns an id string of the SCSI transport adapter.
  34. It may be called before initialization but then may
  35. return only a preliminary id.
  36. sg_initialize() performs global initialization of the SCSI transport
  37. adapter and eventually needed operating system
  38. facilities. Checks for compatibility of supporting
  39. software components.
  40. sg_shutdown() performs global finalizations and releases golbally
  41. acquired resources.
  42. sg_give_next_adr() iterates over the set of potentially useful drive
  43. address strings.
  44. scsi_enumerate_drives() brings all available, not-whitelist-banned, and
  45. accessible drives into libburn's list of drives.
  46. sg_dispose_drive() finalizes adapter specifics of struct burn_drive
  47. on destruction. Releases resources which were acquired
  48. underneath scsi_enumerate_drives().
  49. sg_drive_is_open() tells wether libburn has the given drive in use.
  50. sg_grab() opens the drive for SCSI commands and ensures
  51. undisturbed access.
  52. sg_release() closes a drive opened by sg_grab()
  53. sg_issue_command() sends a SCSI command to the drive, receives reply,
  54. and evaluates wether the command succeeded or shall
  55. be retried or finally failed.
  56. sg_obtain_scsi_adr() tries to obtain SCSI address parameters.
  57. burn_os_is_2k_seekrw() tells whether the given path leads to a file object
  58. that can be used in 2 kB granularity by lseek(2),
  59. read(2), and possibly write(2) if not read-only..
  60. E.g. a USB stick or a hard disk.
  61. burn_os_stdio_capacity() estimates the emulated media space of stdio-drives.
  62. burn_os_open_track_src() opens a disk file in a way that offers best
  63. throughput with file reading and/or SCSI write command
  64. transmission.
  65. burn_os_alloc_buffer() allocates a memory area that is suitable for file
  66. descriptors issued by burn_os_open_track_src().
  67. The buffer size may be rounded up for alignment
  68. reasons.
  69. burn_os_free_buffer() delete a buffer obtained by burn_os_alloc_buffer().
  70. Porting hints are marked by the text "PORTING:".
  71. Send feedback to libburn-hackers@pykix.org .
  72. */
  73. #ifdef HAVE_CONFIG_H
  74. #include "../config.h"
  75. #endif
  76. /** PORTING : ------- OS dependent headers and definitions ------ */
  77. #include <unistd.h>
  78. #include <stdio.h>
  79. #include <sys/types.h>
  80. #include <errno.h>
  81. #include <fcntl.h>
  82. #include <sys/stat.h>
  83. #include <string.h>
  84. #include <stdlib.h>
  85. #ifdef Libburn_os_has_statvfS
  86. #include <sys/statvfs.h>
  87. #endif /* Libburn_os_has_stavtfS */
  88. #include <sys/ioctl.h>
  89. #include <sys/scsiio.h>
  90. /** PORTING : ------ libburn portable headers and definitions ----- */
  91. #include "transport.h"
  92. #include "drive.h"
  93. #include "sg.h"
  94. #include "spc.h"
  95. #include "sbc.h"
  96. #include "debug.h"
  97. #include "toc.h"
  98. #include "util.h"
  99. #include "init.h"
  100. #include "libdax_msgs.h"
  101. extern struct libdax_msgs *libdax_messenger;
  102. /* is in portable part of libburn */
  103. int burn_drive_is_banned(char *device_address);
  104. int burn_drive_resolve_link(char *path, char adr[],
  105. int *recursion_count, int flag); /* drive.c */
  106. /* Whether to log SCSI commands:
  107. bit0= log in /tmp/libburn_sg_command_log
  108. bit1= log to stderr
  109. bit2= flush every line
  110. */
  111. extern int burn_sg_log_scsi;
  112. /* ------------------------------------------------------------------------ */
  113. /* PORTING: Private definitions. Port only if needed by public functions. */
  114. /* (Public functions are listed below) */
  115. /* ------------------------------------------------------------------------ */
  116. /* Storage object is in libburn/init.c
  117. whether to strive for exclusive access to the drive
  118. */
  119. extern int burn_sg_open_o_excl;
  120. /* ------------------------------------------------------------------------ */
  121. /* PORTING: Private functions. Port only if needed by public functions */
  122. /* (Public functions are listed below) */
  123. /* ------------------------------------------------------------------------ */
  124. static int sg_close_drive(struct burn_drive * d)
  125. {
  126. if (d->fd != -1) {
  127. close(d->fd);
  128. d->fd = -1;
  129. return 1;
  130. }
  131. return 0;
  132. }
  133. /* ----------------------------------------------------------------------- */
  134. /* PORTING: Private functions which contain publicly needed functionality. */
  135. /* Their portable part must be performed. So it is probably best */
  136. /* to replace the non-portable part and to call these functions */
  137. /* in your port, too. */
  138. /* ----------------------------------------------------------------------- */
  139. /** Wraps a detected drive into libburn structures and hands it over to
  140. libburn drive list.
  141. */
  142. static void enumerate_common(char *fname,
  143. int bus_no, int host_no,
  144. int channel_no, int target_no, int lun_no)
  145. {
  146. int ret;
  147. struct burn_drive out;
  148. /* General libburn drive setup */
  149. burn_setup_drive(&out, fname);
  150. /* This transport adapter uses SCSI-family commands and models
  151. (seems the adapter would know better than its boss, if ever) */
  152. ret = burn_scsi_setup_drive(&out, bus_no, host_no, channel_no,
  153. target_no, lun_no, 0);
  154. if (ret <= 0)
  155. return;
  156. /* PORTING: ------------------- non portable part --------------- */
  157. /* Transport adapter is NetBSD/OpenBSD ioctl SCIOCCOMMAND */
  158. /* Adapter specific handles and data */
  159. out.fd = -1;
  160. /* PORTING: ---------------- end of non portable part ------------ */
  161. /* Adapter specific functions with standardized names */
  162. out.grab = sg_grab;
  163. out.release = sg_release;
  164. out.drive_is_open = sg_drive_is_open;
  165. out.issue_command = sg_issue_command;
  166. /* Finally register drive and inquire drive information */
  167. burn_drive_finish_enum(&out);
  168. }
  169. static int start_enum_rcdNx(burn_drive_enumerator_t *idx, int flag)
  170. {
  171. idx->cdno = -1;
  172. return 1;
  173. }
  174. /* Trying /dev/rcd[0..63][dc] */
  175. #define Libburn_netbsd_max_cdnuM 63
  176. static int next_enum_rcdNx(burn_drive_enumerator_t *idx,
  177. char adr[], int adr_size, int flag)
  178. {
  179. static char suffix[2] = {'d', 'c'};
  180. struct stat stbuf;
  181. int i, stat_ret;
  182. char path[16];
  183. while (idx->cdno < Libburn_netbsd_max_cdnuM) {
  184. idx->cdno++;
  185. for (i = 0; i < 2; i++) {
  186. sprintf(path, "/dev/rcd%d%c", idx->cdno, suffix[i]);
  187. stat_ret = stat(path, &stbuf);
  188. if (stat_ret == -1)
  189. continue;
  190. if (!S_ISCHR(stbuf.st_mode))
  191. continue;
  192. if ((int) strlen(path) >= adr_size)
  193. continue;
  194. strcpy(adr, path);
  195. return 1;
  196. }
  197. }
  198. return 0;
  199. }
  200. /* Searching the first byte address that cannot be lseeked and read
  201. */
  202. static int guess_size_by_seek_set(int fd, off_t *bytes, int flag)
  203. {
  204. static off_t abs_limit = ((off_t) 1024) * 1024 * 1024 * 1024 * 1024;
  205. off_t i, step = ((off_t) 1024) * 1024 * 1024 * 1024, ret;
  206. char buf[1];
  207. *bytes = 0;
  208. for (i = step; i < abs_limit; i += step) {
  209. ret = lseek(fd, i, SEEK_SET);
  210. if (ret == -1) {
  211. i -= step;
  212. step = step >> 1;
  213. if (step > 0)
  214. continue;
  215. return 1;
  216. }
  217. ret = read(fd, buf, 1);
  218. if (ret == -1) {
  219. i -= step;
  220. step = step >> 1;
  221. if (step > 0)
  222. continue;
  223. return 1;
  224. }
  225. *bytes = i + 1;
  226. }
  227. return 0;
  228. }
  229. /* ------------------------------------------------------------------------ */
  230. /* PORTING: Public functions. These MUST be ported. */
  231. /* ------------------------------------------------------------------------ */
  232. /** Returns the id string of the SCSI transport adapter and eventually
  233. needed operating system facilities.
  234. This call is usable even if sg_initialize() was not called yet. In that
  235. case a preliminary constant message might be issued if detailed info is
  236. not available yet.
  237. @param msg returns id string
  238. @param flag unused yet, submit 0
  239. @return 1 = success, <=0 = failure
  240. */
  241. int sg_id_string(char msg[1024], int flag)
  242. {
  243. #ifdef __OpenBSD__
  244. sprintf(msg, "internal OpenBSD SCIOCCOMMAND adapter sg-netbsd");
  245. #else
  246. sprintf(msg, "internal NetBSD SCIOCCOMMAND adapter sg-netbsd");
  247. #endif
  248. return 1;
  249. }
  250. /** Performs global initialization of the SCSI transport adapter and eventually
  251. needed operating system facilities. Checks for compatibility of supporting
  252. software components.
  253. @param msg returns ids and/or error messages of eventual helpers
  254. @param flag unused yet, submit 0
  255. @return 1 = success, <=0 = failure
  256. */
  257. int sg_initialize(char msg[1024], int flag)
  258. {
  259. return sg_id_string(msg, 0);
  260. }
  261. /** Performs global finalization of the SCSI transport adapter and eventually
  262. needed operating system facilities. Releases globally acquired resources.
  263. @param flag unused yet, submit 0
  264. @return 1 = success, <=0 = failure
  265. */
  266. int sg_shutdown(int flag)
  267. {
  268. return 1;
  269. }
  270. /** Finalizes BURN_OS_TRANSPORT_DRIVE_ELEMENTS, the components of
  271. struct burn_drive which are defined in os-*.h.
  272. The eventual initialization of those components was made underneath
  273. scsi_enumerate_drives().
  274. This will be called when a burn_drive gets disposed.
  275. @param d the drive to be finalized
  276. @param flag unused yet, submit 0
  277. @return 1 = success, <=0 = failure
  278. */
  279. int sg_dispose_drive(struct burn_drive *d, int flag)
  280. {
  281. return 1;
  282. }
  283. /** Returns the next index number and the next enumerated drive address.
  284. The enumeration has to cover all available and accessible drives. It is
  285. allowed to return addresses of drives which are not available but under
  286. some (even exotic) circumstances could be available. It is on the other
  287. hand allowed, only to hand out addresses which can really be used right
  288. in the moment of this call. (This implementation chooses the former.)
  289. @param idx An opaque handle. Make no own theories about it.
  290. @param adr Takes the reply
  291. @param adr_size Gives maximum size of reply including final 0
  292. @param initialize 1 = start new,
  293. 0 = continue, use no other values for now
  294. -1 = finish
  295. @return 1 = reply is a valid address , 0 = no further address available
  296. -1 = severe error (e.g. adr_size too small)
  297. */
  298. int sg_give_next_adr(burn_drive_enumerator_t *idx,
  299. char adr[], int adr_size, int initialize)
  300. {
  301. int ret;
  302. if (initialize == 1) {
  303. ret = start_enum_rcdNx(idx, 0);
  304. if (ret <= 0)
  305. return ret;
  306. } else if (initialize == -1) {
  307. return 0;
  308. }
  309. ret = next_enum_rcdNx(idx, adr, adr_size, 0);
  310. return ret;
  311. }
  312. /** Brings all available, not-whitelist-banned, and accessible drives into
  313. libburn's list of drives.
  314. */
  315. int scsi_enumerate_drives(void)
  316. {
  317. burn_drive_enumerator_t idx;
  318. int initialize = 1, ret, i_bus_no = -1, buf_size = 4096;
  319. int i_host_no = -1, i_channel_no = -1, i_target_no = -1, i_lun_no = -1;
  320. char *buf = NULL;
  321. BURN_ALLOC_MEM(buf, char, buf_size);
  322. while(1) {
  323. ret = sg_give_next_adr(&idx, buf, buf_size, initialize);
  324. initialize = 0;
  325. if (ret <= 0)
  326. break;
  327. if (burn_drive_is_banned(buf))
  328. continue;
  329. sg_obtain_scsi_adr(buf, &i_bus_no, &i_host_no,
  330. &i_channel_no, &i_target_no, &i_lun_no);
  331. enumerate_common(buf,
  332. i_bus_no, i_host_no, i_channel_no,
  333. i_target_no, i_lun_no);
  334. }
  335. sg_give_next_adr(&idx, buf, buf_size, -1);
  336. ret = 1;
  337. ex:;
  338. BURN_FREE_MEM(buf);
  339. return ret;
  340. }
  341. /** Tells whether libburn has the given drive in use or exclusively reserved.
  342. If it is "open" then libburn will eventually call sg_release() on it when
  343. it is time to give up usage and reservation.
  344. */
  345. /** Published as burn_drive.drive_is_open() */
  346. int sg_drive_is_open(struct burn_drive * d)
  347. {
  348. return (d->fd != -1);
  349. }
  350. /** Opens the drive for SCSI commands and - if burn activities are prone
  351. to external interference on your system - obtains an exclusive access lock
  352. on the drive. (Note: this is not physical tray locking.)
  353. A drive that has been opened with sg_grab() will eventually be handed
  354. over to sg_release() for closing and unreserving.
  355. */
  356. int sg_grab(struct burn_drive *d)
  357. {
  358. char *msg = NULL;
  359. int os_errno, ret;
  360. BURN_ALLOC_MEM(msg, char, 4096);
  361. if (d->fd != -1) {
  362. d->released = 0;
  363. {ret = 1; goto ex;}
  364. }
  365. d->fd = open(d->devname, O_RDWR | O_NDELAY);
  366. if (d->fd == -1) {
  367. os_errno = errno;
  368. sprintf(msg, "Could not grab drive '%s'", d->devname);
  369. /* (errno == ENXIO is a device file with no drive attached) */
  370. libdax_msgs_submit(libdax_messenger, d->global_index,
  371. 0x00020003,
  372. errno == ENXIO ? LIBDAX_MSGS_SEV_DEBUG :
  373. LIBDAX_MSGS_SEV_SORRY,
  374. LIBDAX_MSGS_PRIO_HIGH,
  375. msg, os_errno, 0);
  376. {ret = 0; goto ex;}
  377. }
  378. d->released = 0;
  379. /* Make sure by INQUIRY that this is really a MMC drive */
  380. ret = spc_confirm_cd_drive(d, 0);
  381. if (ret <= 0)
  382. goto revoke;
  383. /* # define Libburn_sg_netbsd_scsi_debuG */
  384. #ifdef Libburn_sg_netbsd_scsi_debuG
  385. {
  386. static int sc_db = SC_DB_CMDS | SC_DB_FLOW;
  387. ret = ioctl(d->fd, SCIOCDEBUG, &sc_db);
  388. if (ret == -1)
  389. fprintf(stderr,
  390. "libburn_DEBUG: ioctl(%d, SCIOCDEBUG, &(0x%X)) returns %d, errno = %d\n",
  391. d->fd, (unsigned int) sc_db, ret, errno);
  392. }
  393. #endif
  394. {ret = 1; goto ex;}
  395. revoke:;
  396. sprintf(msg, "Could not grab drive '%s'.", d->devname);
  397. libdax_msgs_submit(libdax_messenger, d->global_index,
  398. 0x00020003,
  399. LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
  400. msg, 0, 0);
  401. if (d->fd >= 0) {
  402. close(d->fd);
  403. d->fd = -1;
  404. d->released = 1;
  405. }
  406. ret = 0;
  407. ex:;
  408. BURN_FREE_MEM(msg);
  409. return ret;
  410. }
  411. /** PORTING: Is mainly about the call to sg_close_drive() and whether it
  412. implements the demanded functionality.
  413. */
  414. /** Gives up the drive for SCSI commands and releases eventual access locks.
  415. (Note: this is not physical tray locking.)
  416. */
  417. int sg_release(struct burn_drive *d)
  418. {
  419. if (d->fd < 0)
  420. return 0;
  421. sg_close_drive(d);
  422. return 0;
  423. }
  424. /** Sends a SCSI command to the drive, receives reply and evaluates wether
  425. the command succeeded or shall be retried or finally failed.
  426. Returned SCSI errors shall not lead to a return value indicating failure.
  427. The callers get notified by c->error. An SCSI failure which leads not to
  428. a retry shall be notified via scsi_notify_error().
  429. The Libburn_log_sg_commandS facility might be of help when problems with
  430. a drive have to be examined. It shall stay disabled for normal use.
  431. @return: 1 success , <=0 failure
  432. */
  433. int sg_issue_command(struct burn_drive *d, struct command *c)
  434. {
  435. int i, timeout_ms, ret, key, asc, ascq, done = 0, sense_len, max_sl;
  436. time_t start_time;
  437. scsireq_t req;
  438. char msg[160];
  439. static FILE *fp = NULL;
  440. c->error = 0;
  441. if (d->fd == -1)
  442. return 0;
  443. if (burn_sg_log_scsi & 1) {
  444. if (fp == NULL) {
  445. fp= fopen("/tmp/libburn_sg_command_log", "a");
  446. fprintf(fp,
  447. "\n-----------------------------------------\n");
  448. }
  449. }
  450. if (burn_sg_log_scsi & 3)
  451. scsi_log_cmd(c,fp,0);
  452. if (c->timeout > 0)
  453. timeout_ms = c->timeout;
  454. else
  455. timeout_ms = 200000;
  456. memset (&req, 0, sizeof(req));
  457. memcpy(req.cmd, c->opcode, c->oplen);
  458. req.cmdlen = c->oplen;
  459. req.databuf = (caddr_t) c->page->data;
  460. req.flags = SCCMD_ESCAPE; /* probably to make req.cmdlen significant */
  461. req.timeout = timeout_ms;
  462. max_sl = sizeof(c->sense) > SENSEBUFLEN ?
  463. SENSEBUFLEN : sizeof(c->sense);
  464. req.senselen = max_sl;
  465. if (c->dir == TO_DRIVE) {
  466. req.datalen = c->page->bytes;
  467. req.flags |= SCCMD_WRITE;
  468. } else if (c->dir == FROM_DRIVE) {
  469. req.flags |= SCCMD_READ;
  470. if (c->dxfer_len >= 0)
  471. req.datalen = c->dxfer_len;
  472. else
  473. req.datalen = BUFFER_SIZE;
  474. /* touch page so we can use valgrind */
  475. memset(c->page->data, 0, BUFFER_SIZE);
  476. } else {
  477. req.flags |= SCCMD_READ;
  478. req.datalen = 0;
  479. }
  480. /* retry-loop */
  481. start_time = time(NULL);
  482. for(i = 0; !done; i++) {
  483. memset(c->sense, 0, sizeof(c->sense));
  484. c->start_time = burn_get_time(0);
  485. ret = ioctl(d->fd, SCIOCCOMMAND, &req);
  486. /* <<< Fault mock-up
  487. if (c->opcode[0] == 0x28) {
  488. ret = -1;
  489. errno = 9;
  490. }
  491. */
  492. c->end_time = burn_get_time(0);
  493. /* #define Libburn_debug_sg_netbsD */
  494. #ifdef Libburn_debug_sg_netbsD
  495. fprintf(stderr, "libburn_DEBUG: ret= %d, retsts = 0x%X, senselen_used = %d, status = 0x%X, error= 0x%X\n", ret, (unsigned int) req.retsts, (int) req.senselen_used, (unsigned int) req.status, req.error);
  496. fprintf(stderr, "libburn_DEBUG: datalen_used = %u\n",
  497. (unsigned int) req.datalen_used);
  498. #endif
  499. if (ret != 0 ||
  500. (req.retsts != SCCMD_SENSE && req.retsts != SCCMD_OK)) {
  501. sprintf(msg, "Failed to transfer command to drive. (ioctl(%d, SCIOCCOMMAND) = %d, scsireq_t.retsts = 0x%X, errno= %d)",
  502. d->fd, ret, (unsigned int) req.retsts, errno);
  503. if (burn_sg_log_scsi & 3)
  504. scsi_log_message(d, fp, msg, 0);
  505. libdax_msgs_submit(libdax_messenger,
  506. d->global_index, 0x0002010c,
  507. LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
  508. msg, errno, 0);
  509. sg_close_drive(d);
  510. d->released = 1;
  511. d->busy = BURN_DRIVE_IDLE;
  512. c->error = 1;
  513. return -1;
  514. }
  515. sense_len = 0;
  516. if (req.retsts == SCCMD_SENSE) {
  517. memcpy(c->sense, req.sense, max_sl);
  518. sense_len = req.senselen > max_sl ?
  519. max_sl : req.senselen;
  520. }
  521. spc_decode_sense(c->sense, sense_len, &key, &asc, &ascq);
  522. if (key || asc || ascq)
  523. sense_len = req.senselen;
  524. else
  525. sense_len = 0;
  526. /* <<< Fault mock-up
  527. if (c->opcode[0] == 0x5a) {
  528. req.datalen_used = 0;
  529. memset(c->page->data, 0, BUFFER_SIZE);
  530. }
  531. */
  532. if (c->dir == FROM_DRIVE && sense_len == 0 &&
  533. req.datalen > 0 && req.datalen_used < req.datalen) {
  534. sprintf(msg, "Short reply from SCSI command %2.2X: expected: %d, got: %d, req.retsts: 0x%X",
  535. (unsigned int) c->opcode[0],
  536. (int) req.datalen, (int) req.datalen_used,
  537. (unsigned int) req.retsts);
  538. if (burn_sg_log_scsi & 3)
  539. scsi_log_message(d, fp, msg, 0);
  540. libdax_msgs_submit(libdax_messenger,
  541. d->global_index, 0x00000002,
  542. LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
  543. msg, 0, 0);
  544. if (req.datalen_used == 0)
  545. c->error = 1;
  546. c->dxfer_len = req.datalen_used;
  547. }
  548. done = scsi_eval_cmd_outcome(d, c, fp, c->sense, sense_len,
  549. start_time, timeout_ms, i, 0);
  550. if (d->cancel)
  551. done = 1;
  552. } /* end of retry-loop */
  553. return 1;
  554. }
  555. /** Tries to obtain SCSI address parameters.
  556. @return 1 is success , 0 is failure
  557. */
  558. int sg_obtain_scsi_adr(char *path, int *bus_no, int *host_no, int *channel_no,
  559. int *target_no, int *lun_no)
  560. {
  561. int ret, fd = -1;
  562. struct scsi_addr addr;
  563. fd = open(path, O_RDWR | O_NDELAY);
  564. if (fd == -1)
  565. return 0;
  566. *bus_no = *host_no = *channel_no = *target_no = *lun_no = 0;
  567. memset(&addr, 0, sizeof(addr));
  568. ret = ioctl(fd, SCIOCIDENTIFY, &addr);
  569. if (ret != 0)
  570. {ret = 0; goto ex;}
  571. if (addr.type != TYPE_SCSI)
  572. {ret = 0; goto ex;}
  573. #ifdef __OpenBSD__
  574. *bus_no = *host_no = addr.scbus;
  575. *target_no = addr.target;
  576. *lun_no = addr.lun;
  577. #else /* __OpenBSD__ */
  578. *bus_no = *host_no = addr.addr.scsi.scbus;
  579. *target_no = addr.addr.scsi.target;
  580. *lun_no = addr.addr.scsi.lun;
  581. #endif /* ! __OpenBSD__ */
  582. ret = 1;
  583. ex:;
  584. if (fd != -1)
  585. close(fd);
  586. return (0);
  587. }
  588. /** Tells wether a text is a persistent address as listed by the enumeration
  589. functions.
  590. */
  591. int sg_is_enumerable_adr(char* adr)
  592. {
  593. burn_drive_enumerator_t idx;
  594. int initialize = 1, ret;
  595. char buf[64];
  596. while(1) {
  597. ret = sg_give_next_adr(&idx, buf, sizeof(buf), initialize);
  598. initialize = 0;
  599. if (ret <= 0)
  600. break;
  601. if (strcmp(adr, buf) == 0) {
  602. sg_give_next_adr(&idx, buf, sizeof(buf), -1);
  603. return 1;
  604. }
  605. }
  606. sg_give_next_adr(&idx, buf, sizeof(buf), -1);
  607. return (0);
  608. }
  609. /* Return 1 if the given path leads to a regular file or a device that can be
  610. fseeked, read, and possibly written with 2 kB granularity.
  611. */
  612. int burn_os_is_2k_seekrw(char *path, int flag)
  613. {
  614. struct stat stbuf;
  615. int l, i, dev, tl;
  616. char try[16];
  617. /* >>> ??? Is this a comprehensive list of lseek()-capable devices ? */
  618. /* http://www.netbsd.org/docs/guide/en/chap-rmmedia.html */
  619. static char dev_names[][4] = {
  620. "fd", "rfd", "sd" , "cd", "rcd", "wd", ""};
  621. if (path[0] == 0)
  622. return 0;
  623. if (stat(path, &stbuf) == -1)
  624. return 0;
  625. if (S_ISREG(stbuf.st_mode))
  626. return 1;
  627. if (S_ISBLK(stbuf.st_mode))
  628. return 1;
  629. /* Look for known device names which promise the desired capabilities */
  630. if (strncmp(path, "/dev/", 5) != 0)
  631. return 0;
  632. l = strlen(path);
  633. for (dev = 0; dev_names[dev][0] != 0; dev++) {
  634. sprintf(try, "/dev/%s", dev_names[dev]);
  635. tl = strlen(try);
  636. if (strncmp(path, try, tl) != 0)
  637. continue;
  638. l -= tl;
  639. for (i = 0; i < Libburn_netbsd_max_cdnuM; i++) {
  640. sprintf(try + tl, "%d", i);
  641. if (strncmp(path, try, strlen(try)) == 0)
  642. break;
  643. }
  644. if (i >= Libburn_netbsd_max_cdnuM)
  645. continue;
  646. tl += strlen(try + tl);
  647. if (l == tl)
  648. return 1;
  649. if (l > tl + 1)
  650. continue;
  651. if (path[l - 1] >= 'a' && path[l - 1] <= 'z')
  652. return 1;
  653. }
  654. return 0;
  655. }
  656. /** Estimate the potential payload capacity of a file address.
  657. @param path The address of the file to be examined. If it does not
  658. exist yet, then the directory will be inquired.
  659. @param bytes The pointed value gets modified, but only if an estimation is
  660. possible.
  661. @return -2 = cannot perform necessary operations on file object
  662. -1 = neither path nor dirname of path exist
  663. 0 = could not estimate size capacity of file object
  664. 1 = estimation has been made, bytes was set
  665. */
  666. int burn_os_stdio_capacity(char *path, off_t write_start, off_t *bytes)
  667. {
  668. struct stat stbuf;
  669. int ret;
  670. #ifdef Libburn_os_has_statvfS
  671. struct statvfs vfsbuf;
  672. #endif
  673. char *testpath = NULL, *cpt;
  674. off_t add_size = 0;
  675. BURN_ALLOC_MEM(testpath, char, 4096);
  676. testpath[0] = 0;
  677. if (stat(path, &stbuf) == -1) {
  678. strcpy(testpath, path);
  679. cpt = strrchr(testpath, '/');
  680. if(cpt == NULL)
  681. strcpy(testpath, ".");
  682. else if(cpt == testpath)
  683. testpath[1] = 0;
  684. else
  685. *cpt = 0;
  686. if (stat(testpath, &stbuf) == -1)
  687. {ret = -1; goto ex;}
  688. } else if(S_ISBLK(stbuf.st_mode)) {
  689. int open_mode = O_RDONLY, fd;
  690. fd = open(path, open_mode);
  691. if (fd == -1)
  692. {ret = -2; goto ex;}
  693. *bytes = lseek(fd, 0, SEEK_END);
  694. if (*bytes <= 0)
  695. guess_size_by_seek_set(fd, bytes, 0);
  696. close(fd);
  697. if (*bytes == -1) {
  698. *bytes = 0;
  699. {ret = 0; goto ex;}
  700. }
  701. } else if(S_ISREG(stbuf.st_mode)) {
  702. add_size = burn_sparse_file_addsize(write_start, &stbuf);
  703. strcpy(testpath, path);
  704. } else
  705. {ret = 0; goto ex;}
  706. if (testpath[0]) {
  707. #ifdef Libburn_os_has_statvfS
  708. if (statvfs(testpath, &vfsbuf) == -1)
  709. {ret = -2; goto ex;}
  710. *bytes = add_size + ((off_t) vfsbuf.f_frsize) *
  711. (off_t) vfsbuf.f_bavail;
  712. #else /* Libburn_os_has_statvfS */
  713. {ret = 0; goto ex;}
  714. #endif /* ! Libburn_os_has_stavtfS */
  715. }
  716. ret = 1;
  717. ex:;
  718. BURN_FREE_MEM(testpath);
  719. return ret;
  720. }
  721. /* ts A91122 : an interface to open(O_DIRECT) or similar OS tricks. */
  722. #ifdef Libburn_read_o_direcT
  723. /* No special O_DIRECT-like precautions are implemented here */
  724. #endif /* Libburn_read_o_direcT */
  725. int burn_os_open_track_src(char *path, int open_flags, int flag)
  726. {
  727. int fd;
  728. fd = open(path, open_flags);
  729. return fd;
  730. }
  731. void *burn_os_alloc_buffer(size_t amount, int flag)
  732. {
  733. void *buf = NULL;
  734. buf = calloc(1, amount);
  735. return buf;
  736. }
  737. int burn_os_free_buffer(void *buffer, size_t amount, int flag)
  738. {
  739. if (buffer == NULL)
  740. return 0;
  741. free(buffer);
  742. return 1;
  743. }