Blame src/util.c

Packit dd8086
/*
Packit dd8086
  Copyright (C) 2003-2010, 2012-2014, 2017 Rocky Bernstein <rocky@gnu.org>
Packit dd8086
Packit dd8086
  This program is free software: you can redistribute it and/or modify
Packit dd8086
  it under the terms of the GNU General Public License as published by
Packit dd8086
  the Free Software Foundation, either version 3 of the License, or
Packit dd8086
  (at your option) any later version.
Packit dd8086
Packit dd8086
  This program is distributed in the hope that it will be useful,
Packit dd8086
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit dd8086
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit dd8086
  GNU General Public License for more details.
Packit dd8086
Packit dd8086
  You should have received a copy of the GNU General Public License
Packit dd8086
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit dd8086
*/
Packit dd8086
Packit dd8086
/* Miscellaneous things common to standalone programs. */
Packit dd8086
Packit dd8086
#include "util.h"
Packit dd8086
#include <cdio/mmc.h>
Packit dd8086
#include <cdio/bytesex.h>
Packit dd8086
Packit dd8086
#ifdef HAVE_SYS_STAT_H
Packit dd8086
# include <sys/stat.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
/* MSYS 1.0.10 with MinGW 3.4.2 (and perhaps others) don't have
Packit dd8086
   S_ISSOCK() or S_ISLNK() macros, so we'll roll our own. */
Packit dd8086
#if !defined(HAVE_S_ISSOCK) && !defined(S_ISSOCK)
Packit dd8086
#define S_ISSOCK(st_mode) ((((st_mode)) & 0170000) == (0140000))
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#if !defined(HAVE_S_ISLNK) && !defined(S_ISLNK)
Packit dd8086
#define S_ISLNK(st_mode) ((((st_mode)) & 0170000) == (0010000))
Packit dd8086
#endif
Packit dd8086
Packit dd8086
cdio_log_handler_t gl_default_cdio_log_handler = NULL;
Packit dd8086
char *source_name = NULL;
Packit dd8086
char *program_name;
Packit dd8086
Packit dd8086
void
Packit dd8086
myexit(CdIo_t *cdio, int rc)
Packit dd8086
{
Packit dd8086
  if (NULL != cdio) cdio_destroy(cdio);
Packit dd8086
  if (NULL != program_name) free(program_name);
Packit dd8086
  if (NULL != source_name)  free(source_name);
Packit dd8086
  exit(rc);
Packit dd8086
}
Packit dd8086
Packit dd8086
void
Packit dd8086
print_version (char *prog_name, const char *version,
Packit dd8086
	       int no_header, bool version_only)
Packit dd8086
{
Packit dd8086
Packit dd8086
  if (no_header == 0) {
Packit dd8086
    report( stdout,
Packit dd8086
	    "%s version %s\n"
Packit dd8086
	    "Copyright (c) 2003-2005, 2007-2008, 2011-2015, 2017 "
Packit dd8086
	    "R. Bernstein\n",
Packit dd8086
	    prog_name, version);
Packit dd8086
    report( stdout,
Packit dd8086
            _("This is free software; see the source for copying conditions.\n\
Packit dd8086
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n\
Packit dd8086
PARTICULAR PURPOSE.\n\
Packit dd8086
"));
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (version_only) {
Packit dd8086
    char *default_device;
Packit dd8086
    const driver_id_t *driver_id_p;
Packit dd8086
    for (driver_id_p=cdio_drivers; *driver_id_p!=DRIVER_UNKNOWN; driver_id_p++) {
Packit dd8086
      if (cdio_have_driver(*driver_id_p)) {
Packit dd8086
	report( stdout, "Have driver: %s\n", cdio_driver_describe(*driver_id_p));
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
    default_device=cdio_get_default_device(NULL);
Packit dd8086
    if (default_device)
Packit dd8086
      report( stdout, "Default CD-ROM device: %s\n", default_device);
Packit dd8086
    else
Packit dd8086
      report( stdout, "No CD-ROM device found.\n");
Packit dd8086
    free(prog_name);
Packit dd8086
    exit(EXIT_INFO);
Packit dd8086
  }
Packit dd8086
Packit dd8086
}
Packit dd8086
Packit dd8086
/*! Device input routine. If successful we return an open CdIo_t
Packit dd8086
    pointer. On error the program exits.
Packit dd8086
 */
Packit dd8086
CdIo_t *
Packit dd8086
open_input(const char *psz_source, source_image_t source_image,
Packit dd8086
	   const char *psz_access_mode)
Packit dd8086
{
Packit dd8086
  CdIo_t *p_cdio = NULL;
Packit dd8086
  switch (source_image) {
Packit dd8086
  case INPUT_UNKNOWN:
Packit dd8086
  case INPUT_AUTO:
Packit dd8086
    p_cdio = cdio_open_am (psz_source, DRIVER_UNKNOWN, psz_access_mode);
Packit dd8086
    if (!p_cdio) {
Packit dd8086
      if (psz_source) {
Packit dd8086
	err_exit("Error in automatically selecting driver for input %s.\n",
Packit dd8086
		 psz_source);
Packit dd8086
      } else {
Packit dd8086
	err_exit("%s", "Error in automatically selecting driver.\n");
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
    break;
Packit dd8086
  case INPUT_DEVICE:
Packit dd8086
    p_cdio = cdio_open_am (psz_source, DRIVER_DEVICE, psz_access_mode);
Packit dd8086
    if (!p_cdio) {
Packit dd8086
      if (psz_source) {
Packit dd8086
	err_exit("Cannot use CD-ROM device %s. Is a CD loaded?\n",
Packit dd8086
		 psz_source);
Packit dd8086
      } else {
Packit dd8086
	err_exit("%s", "Cannot find a CD-ROM with a CD loaded.\n");
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
    break;
Packit dd8086
  case INPUT_BIN:
Packit dd8086
    p_cdio = cdio_open_am (psz_source, DRIVER_BINCUE, psz_access_mode);
Packit dd8086
    if (!p_cdio) {
Packit dd8086
      if (psz_source) {
Packit dd8086
	err_exit("%s: Error in opening CDRWin BIN/CUE image for BIN"
Packit dd8086
		 " input %s\n", psz_source);
Packit dd8086
      } else {
Packit dd8086
	err_exit("%s", "Cannot find CDRWin BIN/CUE image.\n");
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
    break;
Packit dd8086
  case INPUT_CUE:
Packit dd8086
    p_cdio = cdio_open_cue(psz_source);
Packit dd8086
    if (p_cdio==NULL) {
Packit dd8086
      if (psz_source) {
Packit dd8086
	err_exit("%s: Error in opening CDRWin BIN/CUE image for CUE"
Packit dd8086
		 " input %s\n", psz_source);
Packit dd8086
      } else {
Packit dd8086
	err_exit("%s", "Cannot find CDRWin BIN/CUE image.\n");
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
    break;
Packit dd8086
  case INPUT_NRG:
Packit dd8086
    p_cdio = cdio_open_am (psz_source, DRIVER_NRG, psz_access_mode);
Packit dd8086
    if (p_cdio==NULL) {
Packit dd8086
      if (psz_source) {
Packit dd8086
	err_exit("Error in opening Nero NRG image for input %s\n",
Packit dd8086
		 psz_source);
Packit dd8086
      } else {
Packit dd8086
	err_exit("%s", "Cannot find Nero NRG image.\n");
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
    break;
Packit dd8086
Packit dd8086
  case INPUT_CDRDAO:
Packit dd8086
    p_cdio = cdio_open_am (psz_source, DRIVER_CDRDAO, psz_access_mode);
Packit dd8086
    if (p_cdio==NULL) {
Packit dd8086
      if (psz_source) {
Packit dd8086
	err_exit("Error in opening cdrdao TOC with input %s.\n", psz_source);
Packit dd8086
      } else {
Packit dd8086
	err_exit("%s", "Cannot find cdrdao TOC image.\n");
Packit dd8086
      }
Packit dd8086
    }
Packit dd8086
    break;
Packit dd8086
  }
Packit dd8086
  return p_cdio;
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
#define DEV_PREFIX "/dev/"
Packit dd8086
char *
Packit dd8086
fillout_device_name(const char *device_name)
Packit dd8086
{
Packit dd8086
#if defined(HAVE_WIN32_CDROM) || defined(HAVE_OS2_CDROM)
Packit dd8086
  return strdup(device_name);
Packit dd8086
#else
Packit dd8086
  unsigned int prefix_len = strlen(DEV_PREFIX);
Packit dd8086
  if (!device_name) return NULL;
Packit dd8086
  if (0 == strncmp(device_name, DEV_PREFIX, prefix_len))
Packit dd8086
    return strdup(device_name);
Packit dd8086
  else {
Packit dd8086
    char *full_device_name = (char*) calloc(1, strlen(device_name)+prefix_len);
Packit dd8086
    report( stdout, full_device_name, DEV_PREFIX "%s", device_name);
Packit dd8086
    return full_device_name;
Packit dd8086
  }
Packit dd8086
#endif
Packit dd8086
}
Packit dd8086
Packit dd8086
/*! Prints out SCSI-MMC drive features  */
Packit dd8086
void
Packit dd8086
print_mmc_drive_features(CdIo_t *p_cdio)
Packit dd8086
{
Packit dd8086
Packit dd8086
  int i_status;                  /* Result of SCSI MMC command */
Packit dd8086
  uint8_t buf[65530] = { 0, };     /* Place to hold returned data */
Packit dd8086
  mmc_cdb_t cdb = {{0, }};       /* Command Descriptor Block */
Packit dd8086
Packit dd8086
  CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_GET_CONFIGURATION);
Packit dd8086
  CDIO_MMC_SET_READ_LENGTH8(cdb.field, sizeof(buf));
Packit dd8086
  cdb.field[1] = CDIO_MMC_GET_CONF_ALL_FEATURES;
Packit dd8086
  cdb.field[3] = 0x0;
Packit dd8086
Packit dd8086
  i_status = mmc_run_cmd(p_cdio, 0, &cdb, SCSI_MMC_DATA_READ, sizeof(buf),
Packit dd8086
			 &buf;;
Packit dd8086
  if (i_status == 0) {
Packit dd8086
    uint8_t *p;
Packit dd8086
    uint32_t i_data;
Packit dd8086
    uint8_t *p_max = buf + sizeof(buf);
Packit dd8086
Packit dd8086
    i_data  = (unsigned int) CDIO_MMC_GET_LEN32(buf);
Packit dd8086
Packit dd8086
    /* set to first sense feature code, and then walk through the masks */
Packit dd8086
    p = buf + 8;
Packit dd8086
    while( (p < &(buf[i_data])) && (p < p_max) ) {
Packit dd8086
      uint16_t i_feature;
Packit dd8086
      uint8_t i_feature_additional = p[3];
Packit dd8086
Packit dd8086
      i_feature = CDIO_MMC_GET_LEN16(p);
Packit dd8086
      {
Packit dd8086
	const char *feature_str = mmc_feature2str(i_feature);
Packit dd8086
	report( stdout, "%s Feature\n", feature_str);
Packit dd8086
	switch( i_feature )
Packit dd8086
	  {
Packit dd8086
	  case CDIO_MMC_FEATURE_PROFILE_LIST:
Packit dd8086
	    {
Packit dd8086
	      uint8_t *q;
Packit dd8086
	      for ( q = p+4 ; q < p + i_feature_additional ; q += 4 ) {
Packit dd8086
		int i_profile=CDIO_MMC_GET_LEN16(q);
Packit dd8086
		const char *feature_profile_str =
Packit dd8086
		  mmc_feature_profile2str(i_profile);
Packit dd8086
		report( stdout, "\t%s", feature_profile_str );
Packit dd8086
		if (q[2] & 1) {
Packit dd8086
		  report( stdout, " - on");
Packit dd8086
		}
Packit dd8086
		report( stdout, "\n");
Packit dd8086
	      }
Packit dd8086
	      report( stdout, "\n");
Packit dd8086
Packit dd8086
	      break;
Packit dd8086
	    }
Packit dd8086
	  case CDIO_MMC_FEATURE_CORE:
Packit dd8086
	    {
Packit dd8086
	      uint8_t *q = p+4;
Packit dd8086
	      uint32_t 	i_interface_standard = CDIO_MMC_GET_LEN32(q);
Packit dd8086
	      switch(i_interface_standard) {
Packit dd8086
	      case CDIO_MMC_FEATURE_INTERFACE_UNSPECIFIED:
Packit dd8086
		report( stdout, "\tunspecified interface\n");
Packit dd8086
		break;
Packit dd8086
	      case CDIO_MMC_FEATURE_INTERFACE_SCSI:
Packit dd8086
		report( stdout, "\tSCSI interface\n");
Packit dd8086
		break;
Packit dd8086
	      case CDIO_MMC_FEATURE_INTERFACE_ATAPI:
Packit dd8086
		report( stdout, "\tATAPI interface\n");
Packit dd8086
		break;
Packit dd8086
	      case CDIO_MMC_FEATURE_INTERFACE_IEEE_1394:
Packit dd8086
		report( stdout, "\tIEEE 1394 interface\n");
Packit dd8086
		break;
Packit dd8086
	      case CDIO_MMC_FEATURE_INTERFACE_IEEE_1394A:
Packit dd8086
		report( stdout, "\tIEEE 1394A interface\n");
Packit dd8086
		break;
Packit dd8086
	      case CDIO_MMC_FEATURE_INTERFACE_FIBRE_CH:
Packit dd8086
		report( stdout, "\tFibre Channel interface\n");
Packit dd8086
	      }
Packit dd8086
	      report( stdout, "\n");
Packit dd8086
	      break;
Packit dd8086
	    }
Packit dd8086
	  case CDIO_MMC_FEATURE_MORPHING:
Packit dd8086
	    report( stdout,
Packit dd8086
		    "\tOperational Change Request/Notification %ssupported\n",
Packit dd8086
		    (p[4] & 2) ? "": "not " );
Packit dd8086
	    report( stdout, "\t%synchronous GET EVENT/STATUS NOTIFICATION "
Packit dd8086
		    "supported\n",
Packit dd8086
		    (p[4] & 1) ? "As": "S" );
Packit dd8086
	    report( stdout, "\n");
Packit dd8086
	    break;
Packit dd8086
	    ;
Packit dd8086
Packit dd8086
	  case CDIO_MMC_FEATURE_REMOVABLE_MEDIUM:
Packit dd8086
	    switch(p[4] >> 5) {
Packit dd8086
	    case 0:
Packit dd8086
	      report( stdout,
Packit dd8086
		      "\tCaddy/Slot type loading mechanism\n" );
Packit dd8086
	      break;
Packit dd8086
	    case 1:
Packit dd8086
	      report( stdout,
Packit dd8086
		      "\tTray type loading mechanism\n" );
Packit dd8086
	      break;
Packit dd8086
	    case 2:
Packit dd8086
	      report( stdout, "\tPop-up type loading mechanism\n");
Packit dd8086
	      break;
Packit dd8086
	    case 4:
Packit dd8086
	      report( stdout,
Packit dd8086
		      "\tEmbedded changer with individually changeable discs\n");
Packit dd8086
	      break;
Packit dd8086
	    case 5:
Packit dd8086
	      report( stdout,
Packit dd8086
		      "\tEmbedded changer using a magazine mechanism\n" );
Packit dd8086
	      break;
Packit dd8086
	    default:
Packit dd8086
	      report( stdout,
Packit dd8086
		      "\tUnknown changer mechanism\n" );
Packit dd8086
	    }
Packit dd8086
Packit dd8086
	    report( stdout,
Packit dd8086
		    "\tcan%s eject the medium or magazine via the normal "
Packit dd8086
		    "START/STOP command\n",
Packit dd8086
		    (p[4] & 8) ? "": "not" );
Packit dd8086
	    report( stdout, "\tcan%s be locked into the Logical Unit\n",
Packit dd8086
		    (p[4] & 1) ? "": "not" );
Packit dd8086
	    report( stdout, "\n" );
Packit dd8086
	    break;
Packit dd8086
	  case CDIO_MMC_FEATURE_CD_READ:
Packit dd8086
	    report( stdout, "\tC2 Error pointers are %ssupported\n",
Packit dd8086
		    (p[4] & 2) ? "": "not " );
Packit dd8086
	    report( stdout, "\tCD-Text is %ssupported\n",
Packit dd8086
		    (p[4] & 1) ? "": "not " );
Packit dd8086
	    report( stdout, "\n" );
Packit dd8086
	    break;
Packit dd8086
	  case CDIO_MMC_FEATURE_ENHANCED_DEFECT:
Packit dd8086
	    report( stdout, "\t%s-DRM mode is supported\n",
Packit dd8086
		    (p[4] & 1) ? "DRT": "Persistent" );
Packit dd8086
	    report( stdout, "\n" );
Packit dd8086
	    break;
Packit dd8086
	  case CDIO_MMC_FEATURE_CDDA_EXT_PLAY:
Packit dd8086
	    report( stdout, "\tSCAN command is %ssupported\n",
Packit dd8086
		    (p[4] & 4) ? "": "not ");
Packit dd8086
	    report( stdout,
Packit dd8086
		    "\taudio channels can %sbe muted separately\n",
Packit dd8086
		    (p[4] & 2) ? "": "not ");
Packit dd8086
	    report( stdout,
Packit dd8086
		    "\taudio channels can %shave separate volume levels\n",
Packit dd8086
		    (p[4] & 1) ? "": "not ");
Packit dd8086
	    {
Packit dd8086
	      uint8_t *q = p+6;
Packit dd8086
	      uint16_t i_vol_levels = CDIO_MMC_GET_LEN16(q);
Packit dd8086
	      report( stdout, "\t%d volume levels can be set\n", i_vol_levels );
Packit dd8086
	    }
Packit dd8086
	    report( stdout, "\n");
Packit dd8086
	    break;
Packit dd8086
	  case CDIO_MMC_FEATURE_DVD_CSS:
Packit dd8086
#if 0
Packit dd8086
	    report( stdout, "\tMedium does%s have Content Scrambling (CSS/CPPM)\n",
Packit dd8086
		    (p[2] & 1) ? "": "not " );
Packit dd8086
#endif
Packit dd8086
	    report( stdout, "\tCSS version %d\n", p[7] );
Packit dd8086
	    report( stdout, "\t\n");
Packit dd8086
	    break;
Packit dd8086
	  case CDIO_MMC_FEATURE_LU_SN: {
Packit dd8086
	    uint8_t i_serial = *(p+3);
Packit dd8086
	    char serial[257] = { '\0', };
Packit dd8086
Packit dd8086
	    memcpy(serial, p+4, i_serial );
Packit dd8086
	    report( stdout, "\t%s\n\n", serial );
Packit dd8086
Packit dd8086
	    break;
Packit dd8086
	  }
Packit dd8086
	  default:
Packit dd8086
	    report( stdout, "\n");
Packit dd8086
	    break;
Packit dd8086
	  }
Packit dd8086
      }
Packit dd8086
      p += i_feature_additional + 4;
Packit dd8086
    }
Packit dd8086
  } else {
Packit dd8086
    report( stdout, "Didn't get all feature codes\n");
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
/* Prints out drive capabilities */
Packit dd8086
void
Packit dd8086
print_drive_capabilities(cdio_drive_read_cap_t  i_read_cap,
Packit dd8086
			 cdio_drive_write_cap_t i_write_cap,
Packit dd8086
			 cdio_drive_misc_cap_t  i_misc_cap)
Packit dd8086
{
Packit dd8086
  if (CDIO_DRIVE_CAP_ERROR == i_misc_cap) {
Packit dd8086
    report( stdout, "Error in getting drive hardware properties\n");
Packit dd8086
  }  else if (CDIO_DRIVE_CAP_UNKNOWN == i_misc_cap) {
Packit dd8086
    report( stdout, "Uknown drive hardware properties\n");
Packit dd8086
  } else {
Packit dd8086
    report( stdout, _("Hardware                                  : %s\n"),
Packit dd8086
	   i_misc_cap & CDIO_DRIVE_CAP_MISC_FILE
Packit dd8086
	   ? "Disk Image"  : "CD-ROM or DVD");
Packit dd8086
    report( stdout, _("Can eject                                 : %s\n"),
Packit dd8086
	   i_misc_cap & CDIO_DRIVE_CAP_MISC_EJECT        ? "Yes" : "No" );
Packit dd8086
    report( stdout, _("Can close tray                            : %s\n"),
Packit dd8086
	   i_misc_cap & CDIO_DRIVE_CAP_MISC_CLOSE_TRAY   ? "Yes" : "No" );
Packit dd8086
    report( stdout, _("Can disable manual eject                  : %s\n"),
Packit dd8086
	   i_misc_cap & CDIO_DRIVE_CAP_MISC_LOCK         ? "Yes" : "No" );
Packit dd8086
    report( stdout, _("Can select juke-box disc                  : %s\n\n"),
Packit dd8086
	   i_misc_cap & CDIO_DRIVE_CAP_MISC_SELECT_DISC  ? "Yes" : "No" );
Packit dd8086
Packit dd8086
    report( stdout, _("Can set drive speed                       : %s\n"),
Packit dd8086
	   i_misc_cap & CDIO_DRIVE_CAP_MISC_SELECT_SPEED ? "Yes" : "No" );
Packit dd8086
#ifdef FIXME
Packit dd8086
    report( stdout, _("Can detect if CD changed                  : %s\n"),
Packit dd8086
	   i_misc_cap & CDIO_DRIVE_CAP_MISC_MEDIA_CHANGED ? "Yes" : "No" );
Packit dd8086
#endif
Packit dd8086
    report( stdout, _("Can read multiple sessions (e.g. PhotoCD) : %s\n"),
Packit dd8086
	   i_misc_cap & CDIO_DRIVE_CAP_MISC_MULTI_SESSION ? "Yes" : "No" );
Packit dd8086
    report( stdout, _("Can hard reset device                     : %s\n\n"),
Packit dd8086
	   i_misc_cap & CDIO_DRIVE_CAP_MISC_RESET        ? "Yes" : "No" );
Packit dd8086
  }
Packit dd8086
Packit dd8086
Packit dd8086
  if (CDIO_DRIVE_CAP_ERROR == i_read_cap) {
Packit dd8086
      report( stdout, "Error in getting drive reading properties\n" );
Packit dd8086
  }  else if (CDIO_DRIVE_CAP_UNKNOWN == i_misc_cap) {
Packit dd8086
    report( stdout, "Uknown drive reading properties\n" );
Packit dd8086
  } else {
Packit dd8086
    report( stdout, "Reading....\n");
Packit dd8086
    report( stdout, _("  Can read Mode 2 Form 1                  : %s\n"),
Packit dd8086
	   i_read_cap & CDIO_DRIVE_CAP_READ_MODE2_FORM1  ? "Yes" : "No" );
Packit dd8086
    report( stdout, _("  Can read Mode 2 Form 2                  : %s\n"),
Packit dd8086
	   i_read_cap & CDIO_DRIVE_CAP_READ_MODE2_FORM2  ? "Yes" : "No" );
Packit dd8086
    report( stdout, _("  Can read (S)VCD (i.e. Mode 2 Form 1/2)  : %s\n"),
Packit dd8086
	   i_read_cap &
Packit dd8086
	    (CDIO_DRIVE_CAP_READ_MODE2_FORM1|CDIO_DRIVE_CAP_READ_MODE2_FORM2)
Packit dd8086
	    ? "Yes" : "No" );
Packit dd8086
    report( stdout, _("  Can read C2 Errors                      : %s\n"),
Packit dd8086
	   i_read_cap & CDIO_DRIVE_CAP_READ_C2_ERRS      ? "Yes" : "No" );
Packit dd8086
    report( stdout, _("  Can read IRSC                           : %s\n"),
Packit dd8086
	   i_read_cap & CDIO_DRIVE_CAP_READ_ISRC         ? "Yes" : "No" );
Packit dd8086
    report( stdout, _("  Can read Media Channel Number (or UPC)  : %s\n"),
Packit dd8086
	   i_read_cap & CDIO_DRIVE_CAP_READ_MCN          ? "Yes" : "No" );
Packit dd8086
    report( stdout, _("  Can play audio                          : %s\n"),
Packit dd8086
	   i_read_cap & CDIO_DRIVE_CAP_READ_AUDIO        ? "Yes" : "No" );
Packit dd8086
    report( stdout, _("  Can read CD-DA                          : %s\n"),
Packit dd8086
	   i_read_cap & CDIO_DRIVE_CAP_READ_CD_DA        ? "Yes" : "No" );
Packit dd8086
    report( stdout, _("  Can read CD-R                           : %s\n"),
Packit dd8086
	   i_read_cap & CDIO_DRIVE_CAP_READ_CD_R         ? "Yes" : "No" );
Packit dd8086
    report( stdout, _("  Can read CD-RW                          : %s\n"),
Packit dd8086
	   i_read_cap & CDIO_DRIVE_CAP_READ_CD_RW        ? "Yes" : "No" );
Packit dd8086
    report( stdout, _("  Can read DVD-ROM                        : %s\n"),
Packit dd8086
	   i_read_cap & CDIO_DRIVE_CAP_READ_DVD_ROM      ? "Yes" : "No" );
Packit dd8086
  }
Packit dd8086
Packit dd8086
Packit dd8086
  if (CDIO_DRIVE_CAP_ERROR == i_write_cap) {
Packit dd8086
      report( stdout, "Error in getting drive writing properties\n" );
Packit dd8086
  }  else if (CDIO_DRIVE_CAP_UNKNOWN == i_misc_cap) {
Packit dd8086
    report( stdout, "Uknown drive writing properties\n" );
Packit dd8086
  } else {
Packit dd8086
    report( stdout, "\nWriting....\n");
Packit dd8086
#ifdef FIXED
Packit dd8086
    report( stdout, _("  Can write using Burn Proof              : %s\n"),
Packit dd8086
	   i_write_cap & CDIO_DRIVE_CAP_WRITE_BURN_PROOF ? "Yes" : "No" );
Packit dd8086
#endif
Packit dd8086
    report( stdout, _("  Can write CD-RW                         : %s\n"),
Packit dd8086
	   i_write_cap & CDIO_DRIVE_CAP_WRITE_CD_RW      ? "Yes" : "No" );
Packit dd8086
    report( stdout, _("  Can write DVD-R                         : %s\n"),
Packit dd8086
	   i_write_cap & CDIO_DRIVE_CAP_WRITE_DVD_R      ? "Yes" : "No" );
Packit dd8086
    report( stdout, _("  Can write DVD-RAM                       : %s\n"),
Packit dd8086
	   i_write_cap & CDIO_DRIVE_CAP_WRITE_DVD_RAM    ? "Yes" : "No" );
Packit dd8086
    report( stdout, _("  Can write DVD-RW                        : %s\n"),
Packit dd8086
	   i_write_cap & CDIO_DRIVE_CAP_WRITE_DVD_RW     ? "Yes" : "No" );
Packit dd8086
    report( stdout, _("  Can write DVD+RW                        : %s\n"),
Packit dd8086
	   i_write_cap & CDIO_DRIVE_CAP_WRITE_DVD_RPW    ? "Yes" : "No" );
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*! Common place for output routine. In some environments, like XBOX,
Packit dd8086
  it may not be desireable to send output to stdout and stderr. */
Packit dd8086
void
Packit dd8086
report (FILE *stream, const char *psz_format,  ...)
Packit dd8086
{
Packit dd8086
  va_list args;
Packit dd8086
  va_start (args, psz_format);
Packit dd8086
#ifdef _XBOX
Packit dd8086
  OutputDebugString(psz_format, args);
Packit dd8086
#else
Packit dd8086
  vfprintf (stream, psz_format, args);
Packit dd8086
#endif
Packit dd8086
  va_end(args);
Packit dd8086
}
Packit dd8086
Packit dd8086
/* Prints "ls"-like file attributes */
Packit dd8086
void
Packit dd8086
print_fs_attrs(iso9660_stat_t *p_statbuf, bool b_rock, bool b_xa,
Packit dd8086
	       const char *psz_name_untranslated,
Packit dd8086
	       const char *psz_name_translated)
Packit dd8086
{
Packit dd8086
  char date_str[30];
Packit dd8086
Packit dd8086
#ifdef HAVE_ROCK
Packit dd8086
  if (yep == p_statbuf->rr.b3_rock && b_rock) {
Packit dd8086
    report ( stdout, "  %s %3d %d %d [LSN %6lu] %9u",
Packit dd8086
	     iso9660_get_rock_attr_str (p_statbuf->rr.st_mode),
Packit dd8086
	     p_statbuf->rr.st_nlinks,
Packit dd8086
	     p_statbuf->rr.st_uid,
Packit dd8086
	     p_statbuf->rr.st_gid,
Packit dd8086
	     (long unsigned int) p_statbuf->lsn,
Packit dd8086
	     S_ISLNK(p_statbuf->rr.st_mode)
Packit dd8086
	     ? strlen(p_statbuf->rr.psz_symlink)
Packit dd8086
	     : (unsigned int) p_statbuf->size );
Packit dd8086
Packit dd8086
  } else
Packit dd8086
#endif
Packit dd8086
  if (b_xa) {
Packit dd8086
    report ( stdout, "  %s %d %d [fn %.2d] [LSN %6lu] ",
Packit dd8086
	     iso9660_get_xa_attr_str (p_statbuf->xa.attributes),
Packit dd8086
	     uint16_from_be (p_statbuf->xa.user_id),
Packit dd8086
	     uint16_from_be (p_statbuf->xa.group_id),
Packit dd8086
	     p_statbuf->xa.filenum,
Packit dd8086
	     (long unsigned int) p_statbuf->lsn );
Packit dd8086
Packit dd8086
    if (uint16_from_be(p_statbuf->xa.attributes) & XA_ATTR_MODE2FORM2) {
Packit dd8086
      report ( stdout, "%9u (%9u)",
Packit dd8086
	       (unsigned int) p_statbuf->secsize * M2F2_SECTOR_SIZE,
Packit dd8086
	       (unsigned int) p_statbuf->size );
Packit dd8086
    } else
Packit dd8086
      report (stdout, "%9u", (unsigned int) p_statbuf->size);
Packit dd8086
  } else {
Packit dd8086
    report ( stdout,"  %c [LSN %6lu] %9u",
Packit dd8086
	     (p_statbuf->type == _STAT_DIR) ? 'd' : '-',
Packit dd8086
	     (long unsigned int) p_statbuf->lsn,
Packit dd8086
	     (unsigned int) p_statbuf->size );
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (yep == p_statbuf->rr.b3_rock && b_rock) {
Packit dd8086
    struct tm tm;
Packit dd8086
Packit dd8086
    strftime(date_str, sizeof(date_str), "%b %d %Y %H:%M:%S ", &p_statbuf->tm);
Packit dd8086
Packit dd8086
    /* Now try the proper field for mtime: attributes  */
Packit dd8086
    if (p_statbuf->rr.modify.b_used) {
Packit dd8086
      if (p_statbuf->rr.modify.b_longdate) {
Packit dd8086
	iso9660_get_ltime(&p_statbuf->rr.modify.t.ltime, &tm;;
Packit dd8086
      } else {
Packit dd8086
	iso9660_get_dtime(&p_statbuf->rr.modify.t.dtime, true, &tm;;
Packit dd8086
      }
Packit dd8086
      strftime(date_str, sizeof(date_str), "%b %d %Y %H:%M:%S ", &tm;;
Packit dd8086
    }
Packit dd8086
Packit dd8086
    report (stdout," %s %s", date_str, psz_name_untranslated );
Packit dd8086
Packit dd8086
    if (S_ISLNK(p_statbuf->rr.st_mode)) {
Packit dd8086
      report(stdout, " -> %s", p_statbuf->rr.psz_symlink);
Packit dd8086
    }
Packit dd8086
Packit dd8086
  } else {
Packit dd8086
    strftime(date_str, sizeof(date_str), "%b %d %Y %H:%M:%S ", &p_statbuf->tm);
Packit dd8086
    report (stdout," %s %s", date_str, psz_name_translated);
Packit dd8086
  }
Packit dd8086
Packit dd8086
  report(stdout, "\n");
Packit dd8086
}