Blame test/driver/mmc_read.c

Packit dd8086
/* -*- C -*-
Packit dd8086
  Copyright (C) 2009 Thomas Schmitt <scdbackup@gmx.net>
Packit dd8086
  Copyright (C) 2010-2013, 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
/**
Packit dd8086
   Regression test for MMC commands which don't involve write access.
Packit dd8086
 */
Packit dd8086
#ifdef HAVE_CONFIG_H
Packit dd8086
#include "config.h"
Packit dd8086
#define __CDIO_CONFIG_H__ 1
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_STDIO_H
Packit dd8086
#include <stdio.h>
Packit dd8086
#endif
Packit dd8086
#ifdef HAVE_SYS_TYPES_H
Packit dd8086
#include <sys/types.h>
Packit dd8086
#endif
Packit dd8086
#ifdef HAVE_STDLIB_H
Packit dd8086
#include <stdlib.h>
Packit dd8086
#endif
Packit dd8086
#ifdef HAVE_STRING_H
Packit dd8086
#include <string.h>
Packit dd8086
#endif
Packit dd8086
#ifdef HAVE_UNISTD_H
Packit dd8086
#include <unistd.h>
Packit dd8086
#endif
Packit dd8086
#ifdef _WIN32
Packit dd8086
#  undef HAVE_SLEEP
Packit dd8086
#endif
Packit dd8086
#if !defined(HAVE_SLEEP)
Packit dd8086
#  if defined(_WIN32)
Packit dd8086
#     include <windows.h>
Packit dd8086
#     define sleep(s) Sleep(1000*s)
Packit dd8086
#  elif defined(HAVE_USLEEP)
Packit dd8086
#     define sleep(s) usleep(1000000*s)
Packit dd8086
#  else
Packit dd8086
#     define sleep(s) { int i; for(i=0; i<=1000*s; i++); }
Packit dd8086
#  endif
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#include <cdio/cdio.h>
Packit dd8086
#include <cdio/logging.h>
Packit dd8086
#include <cdio/mmc_cmds.h>
Packit dd8086
Packit dd8086
#define SKIP_TEST 77
Packit dd8086
Packit dd8086
/* gcc may warn if no prototypes are given before function definition */
Packit dd8086
Packit dd8086
static int handle_outcome(CdIo_t *p_cdio, driver_return_code_t i_status,
Packit dd8086
			  int *pi_sense_avail,
Packit dd8086
			  cdio_mmc_request_sense_t * p_sense_reply,
Packit dd8086
			  unsigned int i_flag);
Packit dd8086
Packit dd8086
static int get_disctype(CdIo_t *p_cdio, bool b_verbose);
Packit dd8086
Packit dd8086
static driver_return_code_t get_disc_erasable(const CdIo_t *p_cdio,
Packit dd8086
					      const char *psz_source,
Packit dd8086
					      bool verbose);
Packit dd8086
Packit dd8086
static int mode_sense(CdIo_t *p_cdio, int *pi_sense_avail,
Packit dd8086
		      cdio_mmc_request_sense_t *p_sense_reply,
Packit dd8086
		      unsigned int page_code, unsigned int subpage_code,
Packit dd8086
		      int i_alloc_len,
Packit dd8086
		      unsigned char *p_buf, int *pi_size,
Packit dd8086
		      unsigned int i_flag);
Packit dd8086
Packit dd8086
static void print_status_sense(int i_status, int i_sense_valid,
Packit dd8086
			       cdio_mmc_request_sense_t *p_sense_reply,
Packit dd8086
			       unsigned int i_flag);
Packit dd8086
Packit dd8086
static int test_read(char *psz_drive_path, unsigned int i_flag);
Packit dd8086
Packit dd8086
static int test_unit_ready(CdIo_t *p_cdio, int *pi_sense_avail,
Packit dd8086
			   cdio_mmc_request_sense_t *p_sense_reply,
Packit dd8086
			   unsigned int i_flag);
Packit dd8086
Packit dd8086
static int wait_for_drive(CdIo_t *p_cdio, unsigned int max_tries, bool b_verbose);
Packit dd8086
Packit dd8086
Packit dd8086
/* ------------------------- Helper functions ---------------------------- */
Packit dd8086
Packit dd8086
static driver_return_code_t
Packit dd8086
get_disc_erasable(const CdIo_t *p_cdio, const char *psz_source,
Packit dd8086
		       bool b_verbose)
Packit dd8086
{
Packit dd8086
    driver_return_code_t i_status;
Packit dd8086
    bool b_erasable;
Packit dd8086
Packit dd8086
    i_status = mmc_get_disc_erasable(p_cdio, &b_erasable);
Packit dd8086
    if (b_verbose && DRIVER_OP_SUCCESS == i_status)
Packit dd8086
	printf("Disc is %serasable.\n", b_erasable ? "" : "not ");
Packit dd8086
    return i_status;
Packit dd8086
}
Packit dd8086
Packit dd8086
static int
Packit dd8086
get_disctype(CdIo_t *p_cdio, bool b_verbose)
Packit dd8086
{
Packit dd8086
    cdio_mmc_feature_profile_t disctype;
Packit dd8086
    driver_return_code_t i_status = mmc_get_disctype(p_cdio, 0, &disctype);
Packit dd8086
    if (DRIVER_OP_SUCCESS == i_status) {
Packit dd8086
	if (b_verbose)
Packit dd8086
	    fprintf(stderr, "test_disctype: profile is %s (0x%X)\n",
Packit dd8086
		    mmc_feature_profile2str(disctype),
Packit dd8086
		    disctype);
Packit dd8086
    }
Packit dd8086
    return DRIVER_OP_SUCCESS;
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
/**
Packit dd8086
    @param flag         bit0= verbose
Packit dd8086
*/
Packit dd8086
static int
Packit dd8086
handle_outcome(CdIo_t *p_cdio, driver_return_code_t i_status,
Packit dd8086
	       int *pi_sense_avail,
Packit dd8086
	       cdio_mmc_request_sense_t * p_sense_reply,
Packit dd8086
	       unsigned int i_flag)
Packit dd8086
{
Packit dd8086
    cdio_mmc_request_sense_t *p_temp_sense_reply = NULL;
Packit dd8086
    *pi_sense_avail = mmc_last_cmd_sense(p_cdio, &p_temp_sense_reply);
Packit dd8086
    print_status_sense(i_status, *pi_sense_avail, p_temp_sense_reply, i_flag & 1);
Packit dd8086
    if (18 <= *pi_sense_avail) {
Packit dd8086
        memset(p_sense_reply, 0, sizeof(cdio_mmc_request_sense_t));
Packit dd8086
        memcpy(p_sense_reply, p_temp_sense_reply, *pi_sense_avail);
Packit dd8086
    } else
Packit dd8086
        memset(p_sense_reply, 0, sizeof(cdio_mmc_request_sense_t));
Packit dd8086
    cdio_free(p_temp_sense_reply);
Packit dd8086
    return i_status;
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
/**
Packit dd8086
    @param i_flag bit0= verbose
Packit dd8086
*/
Packit dd8086
static void
Packit dd8086
print_status_sense(int i_status, int i_sense_valid,
Packit dd8086
		   cdio_mmc_request_sense_t *p_sense_reply,
Packit dd8086
		   unsigned int i_flag)
Packit dd8086
{
Packit dd8086
    if (!(i_flag & 1))
Packit dd8086
	return;
Packit dd8086
    printf("return= %d , sense(%d)", i_status, i_sense_valid);
Packit dd8086
    if (i_sense_valid >= 14)
Packit dd8086
	printf(":  KEY=%s (%1.1X), ASC= %2.2X , ASCQ= %2.2X",
Packit dd8086
		mmc_sense_key2str[p_sense_reply->sense_key],
Packit dd8086
		p_sense_reply->sense_key,
Packit dd8086
		p_sense_reply->asc,
Packit dd8086
		p_sense_reply->ascq);
Packit dd8086
    printf("\n");
Packit dd8086
}
Packit dd8086
Packit dd8086
/* --------------------------- MMC commands ------------------------------ */
Packit dd8086
Packit dd8086
Packit dd8086
/**
Packit dd8086
   @param flag         bit0= verbose
Packit dd8086
   @param sense_avail  Number of available sense bytes
Packit dd8086
   (18 get copied if all 18 exist)
Packit dd8086
Packit dd8086
   @param sense_reply  eventual sense bytes
Packit dd8086
   @return             return value of mmc_run_cmd()
Packit dd8086
 */
Packit dd8086
static int
Packit dd8086
test_unit_ready(CdIo_t *p_cdio,
Packit dd8086
		int *pi_sense_avail,
Packit dd8086
		cdio_mmc_request_sense_t *p_sense_reply,
Packit dd8086
		unsigned int i_flag)
Packit dd8086
{
Packit dd8086
  int i_status;
Packit dd8086
  int old_log_level = cdio_loglevel_default;
Packit dd8086
Packit dd8086
  cdio_loglevel_default = CDIO_LOG_WARN;
Packit dd8086
Packit dd8086
  if (i_flag & 1)
Packit dd8086
    printf("test_unit_ready ... ");
Packit dd8086
Packit dd8086
  i_status = mmc_test_unit_ready(p_cdio, 0);
Packit dd8086
  cdio_loglevel_default = old_log_level;
Packit dd8086
Packit dd8086
  return handle_outcome(p_cdio, i_status, pi_sense_avail, p_sense_reply,
Packit dd8086
                             i_flag & 1);
Packit dd8086
}
Packit dd8086
Packit dd8086
Packit dd8086
/* BARELY OBTRUSIVE: MIGHT RUIN A SIMULTANEOUS BURNING OPERATION ON THE DRIVE */
Packit dd8086
/**
Packit dd8086
   Fetch a mode page or a part of it from the drive.
Packit dd8086
   @param i_alloc_len  The number of bytes to be requested from the drive and to
Packit dd8086
                       be copied into parameter buf.
Packit dd8086
                       This has to include the 8 bytes of header and may not
Packit dd8086
                       be less than 10.
Packit dd8086
   @param p_buf        Will contain at most alloc_len many bytes. The first 8 are
Packit dd8086
                       a Mode Parameter Header as of SPC-3 7.4.3, table 240.
Packit dd8086
                       The further bytes are the mode page, typically as of
Packit dd8086
                       MMC-5 7.2. There are meanwhile deprecated mode pages which
Packit dd8086
                       appear only in older versions of MMC.
Packit dd8086
   @param i_size       Will return the number of actually read bytes resp. the
Packit dd8086
                       number of available bytes. See flag bit1.
Packit dd8086
   @param i_flag       bit0= verbose
Packit dd8086
                       bit1= Peek mode:
Packit dd8086
                           Reply number of available bytes in *i_size and not
Packit dd8086
                           the number of actually read bytes.
Packit dd8086
   @return             return value of mmc_run_cmd(),
Packit dd8086
                       or other driver_return_code_t
Packit dd8086
*/
Packit dd8086
static driver_return_code_t
Packit dd8086
mode_sense(CdIo_t *p_cdio, int *pi_sense_avail,
Packit dd8086
		cdio_mmc_request_sense_t *p_sense_reply,
Packit dd8086
                unsigned int i_page_code, unsigned int subpage_code, int i_alloc_len,
Packit dd8086
                unsigned char *p_buf, int *pi_size, unsigned int i_flag)
Packit dd8086
{
Packit dd8086
  driver_return_code_t i_status;
Packit dd8086
Packit dd8086
  if (i_alloc_len < 10)
Packit dd8086
    return DRIVER_OP_BAD_PARAMETER;
Packit dd8086
Packit dd8086
  if (i_flag & 1)
Packit dd8086
    printf("mode_sense(0x%X, %X, %d) ... ",
Packit dd8086
	   i_page_code, subpage_code, i_alloc_len);
Packit dd8086
Packit dd8086
  i_status = mmc_mode_sense_10(p_cdio, p_buf, i_alloc_len, i_page_code);
Packit dd8086
  handle_outcome(p_cdio, i_status, pi_sense_avail, p_sense_reply, i_flag & 1);
Packit dd8086
  if (DRIVER_OP_SUCCESS != i_status)
Packit dd8086
    return i_status;
Packit dd8086
  if (i_flag & 2)
Packit dd8086
    *pi_size = p_buf[9] + 10;                  /* MMC-5 7.2.3 */
Packit dd8086
  else
Packit dd8086
    *pi_size = p_buf[0] * 256 + p_buf[1] + 2;  /* SPC-3 7.4.3, table 240 */
Packit dd8086
  return i_status;
Packit dd8086
}
Packit dd8086
Packit dd8086
/**
Packit dd8086
   Watch drive by test unit ready loop until ready, no media or timeout.
Packit dd8086
   @param b_verbose verbose
Packit dd8086
   @return     1= unit ready , 0= error , -1= severe failure, 2 = no media
Packit dd8086
*/
Packit dd8086
static int
Packit dd8086
wait_for_drive(CdIo_t *p_cdio, unsigned int i_max_tries, bool b_verbose)
Packit dd8086
{
Packit dd8086
  int i_ret, i, i_sense_avail;
Packit dd8086
  cdio_mmc_request_sense_t sense_reply;
Packit dd8086
Packit dd8086
  memset(&sense_reply, 0, sizeof(sense_reply));
Packit dd8086
  for (i = 0; i < i_max_tries; i++) {
Packit dd8086
    i_ret = test_unit_ready(p_cdio, &i_sense_avail, &sense_reply, b_verbose);
Packit dd8086
    if (i_ret == 0) /* Unit is ready */
Packit dd8086
      return 1;
Packit dd8086
    if (i_sense_avail < 18)
Packit dd8086
      return -1;
Packit dd8086
    if (2 == sense_reply.sense_key && 0x04 == sense_reply.asc) {
Packit dd8086
Packit dd8086
      /* Not ready */;
Packit dd8086
Packit dd8086
    } else if (6 == sense_reply.sense_key && 0x28 == sense_reply.asc &&
Packit dd8086
               0 == sense_reply.ascq) {
Packit dd8086
Packit dd8086
      /* Media change notice = try again */;
Packit dd8086
Packit dd8086
    } else if (2 == sense_reply.sense_key && 0x3a == sense_reply.asc) {
Packit dd8086
      /* Medium not present */;
Packit dd8086
        return 2;
Packit dd8086
    } else if (0 == sense_reply.sense_key && 0 == sense_reply.asc) {
Packit dd8086
Packit dd8086
      /* Error with no sense */;
Packit dd8086
Packit dd8086
      return -1;
Packit dd8086
  break;
Packit dd8086
    } else {
Packit dd8086
Packit dd8086
      /* Other error */;
Packit dd8086
Packit dd8086
      return 0;
Packit dd8086
    }
Packit dd8086
    sleep(1);
Packit dd8086
  }
Packit dd8086
  fprintf(stderr, "wait_for_drive: Drive not ready after %d retries\n",
Packit dd8086
          i_max_tries);
Packit dd8086
  return -1;
Packit dd8086
}
Packit dd8086
Packit dd8086
/**
Packit dd8086
   This function bundles tests for the read capability to perform MMC
Packit dd8086
   commands and detecting the sense reply of MMC commands, which
Packit dd8086
   indicates error causes or important drive events.
Packit dd8086
Packit dd8086
   @param drive_path  a drive address suitable for cdio_open_am()
Packit dd8086
   @param flag        bit0= verbose
Packit dd8086
   @return            0= no severe failure
Packit dd8086
                      else an proposal for an exit() value is returned
Packit dd8086
*/
Packit dd8086
static int
Packit dd8086
test_read(char *psz_drive_path, unsigned int i_flag)
Packit dd8086
{
Packit dd8086
    int sense_avail = 0, i_ret = 0, i_sense_valid, i_size, alloc_len = 10;
Packit dd8086
    bool b_verbose = !!(i_flag & 1);
Packit dd8086
    int old_log_level = cdio_loglevel_default;
Packit dd8086
    cdio_mmc_request_sense_t sense_reply;
Packit dd8086
    unsigned char buf[10];
Packit dd8086
    CdIo_t *p_cdio;
Packit dd8086
    const char *scsi_tuple;
Packit dd8086
Packit dd8086
Packit dd8086
    p_cdio = cdio_open(psz_drive_path, DRIVER_DEVICE);
Packit dd8086
    if (!p_cdio)
Packit dd8086
	i_ret = SKIP_TEST - 16;
Packit dd8086
Packit dd8086
    /* The further code produces some intentional failures which should not be
Packit dd8086
       reported by mmc_run_cmd() as INFO messages.
Packit dd8086
    */
Packit dd8086
    cdio_loglevel_default = CDIO_LOG_WARN;
Packit dd8086
Packit dd8086
    /* Test availability of info for cdrecord style adresses .
Packit dd8086
     */
Packit dd8086
    scsi_tuple = cdio_get_arg(p_cdio, "scsi-tuple");
Packit dd8086
    if (scsi_tuple == NULL) {
Packit dd8086
	fprintf(stderr, "Error: cdio_get_arg(\"scsi-tuple\") returns NULL.\n");
Packit dd8086
	i_ret += 6; goto ex;
Packit dd8086
    } else if (i_flag & 1)
Packit dd8086
	printf("Drive '%s' has cdio_get_arg(\"scsi-tuple\") = '%s'\n",
Packit dd8086
	       psz_drive_path, scsi_tuple);
Packit dd8086
Packit dd8086
    /* Test availability of sense reply in case of unready drive.
Packit dd8086
       E.g. if the tray is already ejected.
Packit dd8086
    */
Packit dd8086
    i_ret = test_unit_ready(p_cdio, &sense_avail, &sense_reply, b_verbose);
Packit dd8086
    if (i_ret != 0 && sense_avail < 18) {
Packit dd8086
	fprintf(stderr,
Packit dd8086
		"Error: Drive not ready. Only %d sense bytes. Expected >= 18.\n",
Packit dd8086
		sense_avail);
Packit dd8086
	i_ret += 2; goto ex;
Packit dd8086
    }
Packit dd8086
Packit dd8086
    /* Cause sense reply failure by requesting inappropriate mode page 3Eh */
Packit dd8086
    i_ret += mode_sense(p_cdio, &sense_avail, &sense_reply,
Packit dd8086
			    0x3e, 0, alloc_len, buf, &i_size, b_verbose);
Packit dd8086
    if (i_ret != 0 && sense_avail < 18) {
Packit dd8086
Packit dd8086
	fprintf(stderr,
Packit dd8086
		"Error: Deliberately illegal command yields only %d sense bytes. Expected >= 18.\n",
Packit dd8086
		sense_avail);
Packit dd8086
	i_ret = 3; goto ex;
Packit dd8086
    } else  {
Packit dd8086
	if (sense_reply.sense_key != 5)  {
Packit dd8086
	    fprintf(stderr,
Packit dd8086
		    "Error: Sense key should be 5, got %d\n",
Packit dd8086
		    sense_reply.sense_key);
Packit dd8086
	    i_ret = 3; goto ex;
Packit dd8086
	} else if (sense_reply.asc != 0x24)  {
Packit dd8086
	    fprintf(stderr,
Packit dd8086
		    "Error: Sense code should be 24, got %d\n",
Packit dd8086
		    sense_reply.asc);
Packit dd8086
	    i_ret = 4; goto ex;
Packit dd8086
	} else if (sense_reply.ascq != 0)  {
Packit dd8086
	    fprintf(stderr,
Packit dd8086
		    "Error: Sense code should be 24, got %d\n",
Packit dd8086
		    sense_reply.ascq);
Packit dd8086
	    i_ret = 4; goto ex;
Packit dd8086
	}
Packit dd8086
    }
Packit dd8086
Packit dd8086
    /* How are we, finally ? */
Packit dd8086
    i_ret = test_unit_ready(p_cdio, &i_sense_valid, &sense_reply, b_verbose);
Packit dd8086
    if ((i_flag & 1) && 0 != i_ret && 2 == sense_reply.sense_key &&
Packit dd8086
	0x3a == sense_reply.asc)
Packit dd8086
	fprintf(stderr, "test_unit_ready: Note: No loaded media detected.\n");
Packit dd8086
Packit dd8086
    /* Call mmc_read with a null pointer and check that we get
Packit dd8086
       the right return code. */
Packit dd8086
Packit dd8086
    if (DRIVER_OP_BAD_POINTER !=
Packit dd8086
	(i_ret = mmc_read_cd(p_cdio,
Packit dd8086
			     NULL, /* wrong! should be a buffer. */
Packit dd8086
			     200,  CDIO_MMC_READ_TYPE_ANY,
Packit dd8086
			     false, false, 0, true, false, false,
Packit dd8086
			     1, 2448, 1))) {
Packit dd8086
	fprintf(stderr,
Packit dd8086
		"mmc_read_cd: expecting bad pointer return, got %d\n",
Packit dd8086
		i_ret);
Packit dd8086
    } else {
Packit dd8086
	    i_ret = 0;
Packit dd8086
    }
Packit dd8086
Packit dd8086
  ex:;
Packit dd8086
    cdio_loglevel_default = old_log_level;
Packit dd8086
    cdio_destroy(p_cdio);
Packit dd8086
    return i_ret;
Packit dd8086
}
Packit dd8086
Packit dd8086
/* ---------------------------      main       ----------------------------- */
Packit dd8086
Packit dd8086
int
Packit dd8086
main(int argc, const char *argv[])
Packit dd8086
{
Packit dd8086
  CdIo_t *p_cdio;
Packit dd8086
  char **ppsz_drives     = NULL;
Packit dd8086
  const char *psz_source = NULL;
Packit dd8086
  int i_ret;
Packit dd8086
  int exitrc = 0;
Packit dd8086
  bool b_verbose = (argc > 1);
Packit dd8086
  driver_return_code_t i_status;
Packit dd8086
Packit dd8086
  cdio_loglevel_default = b_verbose ? CDIO_LOG_DEBUG : CDIO_LOG_WARN;
Packit dd8086
Packit dd8086
  if (0 !=
Packit dd8086
      strncmp("TEST UNIT READY", mmc_cmd2str(CDIO_MMC_GPCMD_TEST_UNIT_READY),
Packit dd8086
	      sizeof("TEST UNIT READY"))) {
Packit dd8086
      printf("Expecting mmc_cmd2str to give 'TEST UNIT READY' for code 0x%x\n",
Packit dd8086
	     CDIO_MMC_GPCMD_TEST_UNIT_READY);
Packit dd8086
      exit(1);
Packit dd8086
  }
Packit dd8086
Packit dd8086
  ppsz_drives = cdio_get_devices(DRIVER_DEVICE);
Packit dd8086
  if (!ppsz_drives) {
Packit dd8086
    printf("Can't find a CD-ROM drive. Skipping test.\n");
Packit dd8086
    exit(SKIP_TEST);
Packit dd8086
  }
Packit dd8086
Packit dd8086
  p_cdio = cdio_open(ppsz_drives[0], DRIVER_DEVICE);
Packit dd8086
Packit dd8086
  if (p_cdio) {
Packit dd8086
    const char *psz_have_mmc = cdio_get_arg(p_cdio, "mmc-supported?");
Packit dd8086
Packit dd8086
    psz_source = cdio_get_arg(p_cdio, "source");
Packit dd8086
    if (0 != strncmp(psz_source, ppsz_drives[0],
Packit dd8086
                     strlen(ppsz_drives[0]))) {
Packit dd8086
      fprintf(stderr,
Packit dd8086
              "Got %s; should get back %s, the name we opened.\n",
Packit dd8086
              psz_source, ppsz_drives[0]);
Packit dd8086
      exit(1);
Packit dd8086
    }
Packit dd8086
Packit dd8086
    i_ret = wait_for_drive(p_cdio, 30, b_verbose);
Packit dd8086
    if (0 >= i_ret) {
Packit dd8086
	fprintf(stderr, "Wait for drive error\n");
Packit dd8086
	exit(2);
Packit dd8086
    } else {
Packit dd8086
	if (1 == i_ret)  {
Packit dd8086
	    i_status = get_disc_erasable(p_cdio, psz_source, b_verbose);
Packit dd8086
	    if (DRIVER_OP_SUCCESS != i_status) {
Packit dd8086
		printf("Got status %d back from get_disc_erasable(%s)\n",
Packit dd8086
		       i_status, psz_source);
Packit dd8086
	    }
Packit dd8086
	    get_disctype(p_cdio, b_verbose);
Packit dd8086
Packit dd8086
	    if ( psz_have_mmc
Packit dd8086
		 && 0 == strncmp("true", psz_have_mmc, sizeof("true")) ) {
Packit dd8086
Packit dd8086
		/* Test the MMC enhancements of version 0.83 in december 2009 */
Packit dd8086
		i_ret = test_read(ppsz_drives[0],
Packit dd8086
				  cdio_loglevel_default == CDIO_LOG_DEBUG);
Packit dd8086
		if (0 != i_ret) exit(i_ret + 16);
Packit dd8086
	    }
Packit dd8086
	} else if (2 == i_ret && b_verbose)
Packit dd8086
	    printf("Drive is empty... skipping remaining tests.\n");
Packit dd8086
    }
Packit dd8086
    cdio_destroy(p_cdio);
Packit dd8086
  } else {
Packit dd8086
    fprintf(stderr, "cdio_open('%s') failed\n", ppsz_drives[0]);
Packit dd8086
    exit(2);
Packit dd8086
  }
Packit dd8086
Packit dd8086
  cdio_free_device_list(ppsz_drives);
Packit dd8086
Packit dd8086
  return exitrc;
Packit dd8086
}