Blame lib/cdda_interface/scan_devices.c

Packit cb6d3d
/*
Packit cb6d3d
  $Id: scan_devices.c,v 1.33 2008/06/16 19:45:44 flameeyes Exp $
Packit cb6d3d
Packit cb6d3d
  Copyright (C) 2004, 2005, 2007, 2008, 2009 Rocky Bernstein <rocky@gnu.org>
Packit cb6d3d
  Copyright (C) 1998 Monty xiphmont@mit.edu
Packit cb6d3d
Packit cb6d3d
  This program is free software: you can redistribute it and/or modify
Packit cb6d3d
  it under the terms of the GNU General Public License as published by
Packit cb6d3d
  the Free Software Foundation, either version 3 of the License, or
Packit cb6d3d
  (at your option) any later version.
Packit cb6d3d
Packit cb6d3d
  This program is distributed in the hope that it will be useful,
Packit cb6d3d
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit cb6d3d
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit cb6d3d
  GNU General Public License for more details.
Packit cb6d3d
Packit cb6d3d
  You should have received a copy of the GNU General Public License
Packit cb6d3d
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit cb6d3d
*/
Packit cb6d3d
Packit cb6d3d
/******************************************************************
Packit cb6d3d
 *
Packit cb6d3d
 * Autoscan for or verify presence of a CD-ROM device
Packit cb6d3d
 *
Packit cb6d3d
 ******************************************************************/
Packit cb6d3d
Packit cb6d3d
#include "common_interface.h"
Packit cb6d3d
#include "low_interface.h"
Packit cb6d3d
#include "utils.h"
Packit cb6d3d
#include "cdio/mmc.h"
Packit cb6d3d
#include "cdio/util.h"
Packit cb6d3d
#include <limits.h>
Packit cb6d3d
#include <ctype.h>
Packit cb6d3d
Packit cb6d3d
#ifdef HAVE_PWD_H
Packit cb6d3d
#include <pwd.h>
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
#ifdef HAVE_SYS_STAT_H
Packit cb6d3d
#include <sys/stat.h>
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
#ifndef PATH_MAX
Packit cb6d3d
#define PATH_MAX 4096
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
static const char cdrom_devices[][32]={
Packit cb6d3d
  "/dev/cdrom",
Packit cb6d3d
  "/dev/cdroms/cdrom?",
Packit cb6d3d
  "/dev/hd?",
Packit cb6d3d
  "/dev/sg?",
Packit cb6d3d
  "/dev/cdu31a",
Packit cb6d3d
  "/dev/cdu535",
Packit cb6d3d
  "/dev/sbpcd",
Packit cb6d3d
  "/dev/sbpcd?",
Packit cb6d3d
  "/dev/sonycd",
Packit cb6d3d
  "/dev/mcd",
Packit cb6d3d
  "/dev/sjcd",
Packit cb6d3d
  /* "/dev/aztcd", timeout is too long */
Packit cb6d3d
  "/dev/cm206cd",
Packit cb6d3d
  "/dev/gscd",
Packit cb6d3d
  "/dev/optcd",
Packit cb6d3d
  ""};
Packit cb6d3d
Packit cb6d3d
static cdrom_drive_t *
Packit cb6d3d
cdda_identify_device_cdio(CdIo_t *p_cdio, const char *psz_device,
Packit cb6d3d
			  int messagedest, char **ppsz_messages);
Packit cb6d3d
Packit cb6d3d
/* Functions here look for a cdrom drive; full init of a drive type
Packit cb6d3d
   happens in interface.c */
Packit cb6d3d
Packit cb6d3d
cdrom_drive_t *
Packit cb6d3d
cdio_cddap_find_a_cdrom(int messagedest, char **ppsz_messages){
Packit cb6d3d
  /* Brute force... */
Packit cb6d3d
Packit cb6d3d
  int i=0;
Packit cb6d3d
  cdrom_drive_t *d;
Packit cb6d3d
Packit cb6d3d
  while(*cdrom_devices[i]!='\0'){
Packit cb6d3d
Packit cb6d3d
    /* is it a name or a pattern? */
Packit cb6d3d
    char *pos;
Packit cb6d3d
    if((pos=strchr(cdrom_devices[i],'?'))){
Packit cb6d3d
      int j;
Packit cb6d3d
      /* try first eight of each device */
Packit cb6d3d
      for(j=0;j<4;j++){
Packit cb6d3d
	char *buffer=strdup(cdrom_devices[i]);
Packit cb6d3d
Packit cb6d3d
	/* number, then letter */
Packit cb6d3d
Packit cb6d3d
	buffer[pos-(cdrom_devices[i])]=j+48;
Packit cb6d3d
	if((d=cdda_identify(buffer, messagedest, ppsz_messages)))
Packit cb6d3d
	  return(d);
Packit cb6d3d
	idmessage(messagedest, ppsz_messages, "", NULL);
Packit cb6d3d
	buffer[pos-(cdrom_devices[i])]=j+97;
Packit cb6d3d
	if((d=cdda_identify(buffer, messagedest, ppsz_messages)))
Packit cb6d3d
	  return(d);
Packit cb6d3d
	idmessage(messagedest, ppsz_messages, "", NULL);
Packit cb6d3d
	free(buffer);
Packit cb6d3d
      }
Packit cb6d3d
    }else{
Packit cb6d3d
      /* Name.  Go for it. */
Packit cb6d3d
      if((d=cdda_identify(cdrom_devices[i], messagedest, ppsz_messages)))
Packit cb6d3d
	return(d);
Packit cb6d3d
Packit cb6d3d
      idmessage(messagedest, ppsz_messages, "", NULL);
Packit cb6d3d
    }
Packit cb6d3d
    i++;
Packit cb6d3d
  }
Packit cb6d3d
  {
Packit cb6d3d
#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
Packit cb6d3d
    struct passwd *temp;
Packit cb6d3d
    temp=getpwuid(geteuid());
Packit cb6d3d
    idmessage(messagedest, ppsz_messages,
Packit cb6d3d
	      "\n\nNo cdrom drives accessible to %s found.\n",
Packit cb6d3d
	      temp->pw_name);
Packit cb6d3d
#else
Packit cb6d3d
    idmessage(messagedest, ppsz_messages,
Packit cb6d3d
	      "\n\nNo cdrom drives accessible found.\n", NULL);
Packit cb6d3d
#endif
Packit cb6d3d
  }
Packit cb6d3d
  return(NULL);
Packit cb6d3d
}
Packit cb6d3d
Packit cb6d3d
#ifdef DEVICE_IN_FILESYSTEM
Packit cb6d3d
static char *
Packit cb6d3d
test_resolve_symlink(const char *file, int messagedest, char **ppsz_messages)
Packit cb6d3d
{
Packit cb6d3d
  char resolved[PATH_MAX];
Packit cb6d3d
  struct stat st;
Packit cb6d3d
  if (lstat(file,&st)){
Packit cb6d3d
    idperror(messagedest, ppsz_messages, "\t\tCould not stat %s",file);
Packit cb6d3d
    return(NULL);
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  if (cdio_realpath(file,resolved))
Packit cb6d3d
    return(strdup(resolved));
Packit cb6d3d
Packit cb6d3d
  idperror(messagedest, ppsz_messages, "\t\tCould not resolve symlink %s",
Packit cb6d3d
	   file);
Packit cb6d3d
  return(NULL);
Packit cb6d3d
}
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
/** Returns a paranoia CD-ROM drive object with a CD-DA in it or NULL
Packit cb6d3d
    if there was an error.
Packit cb6d3d
    @see cdio_cddap_identify_cdio
Packit cb6d3d
 */
Packit cb6d3d
cdrom_drive_t *
Packit cb6d3d
cdio_cddap_identify(const char *psz_dev, int messagedest,
Packit cb6d3d
char **ppsz_messages)
Packit cb6d3d
{
Packit cb6d3d
  CdIo_t *p_cdio = NULL;
Packit cb6d3d
Packit cb6d3d
  if (psz_dev)
Packit cb6d3d
    idmessage(messagedest, ppsz_messages, "Checking %s for cdrom...",
Packit cb6d3d
	      psz_dev);
Packit cb6d3d
  else
Packit cb6d3d
    idmessage(messagedest, ppsz_messages, "Checking for cdrom...", NULL);
Packit cb6d3d
Packit cb6d3d
#ifdef DEVICE_IN_FILESYSTEM
Packit cb6d3d
  if (psz_dev) {
Packit cb6d3d
    char *psz_device = test_resolve_symlink(psz_dev, messagedest,
Packit cb6d3d
					    ppsz_messages);
Packit cb6d3d
    if ( psz_device ) {
Packit cb6d3d
      cdrom_drive_t *d=NULL;
Packit cb6d3d
      p_cdio = cdio_open(psz_device, DRIVER_UNKNOWN);
Packit cb6d3d
      d = cdda_identify_device_cdio(p_cdio, psz_device, messagedest,
Packit cb6d3d
				    ppsz_messages);
Packit cb6d3d
      free(psz_device);
Packit cb6d3d
      return d;
Packit cb6d3d
    }
Packit cb6d3d
  }
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
  p_cdio = cdio_open(psz_dev, DRIVER_UNKNOWN);
Packit cb6d3d
  if (p_cdio) {
Packit cb6d3d
    if (!psz_dev) {
Packit cb6d3d
      psz_dev = cdio_get_arg(p_cdio, "source");
Packit cb6d3d
    }
Packit cb6d3d
    return cdda_identify_device_cdio(p_cdio, psz_dev, messagedest,
Packit cb6d3d
				     ppsz_messages);
Packit cb6d3d
  }
Packit cb6d3d
  return NULL;
Packit cb6d3d
}
Packit cb6d3d
Packit cb6d3d
/** Returns a paranoia CD-ROM drive object with a CD-DA in it or NULL
Packit cb6d3d
    if there was an error.  In contrast to cdio_cddap_identify, we
Packit cb6d3d
    start out with an initialized p_cdio object. For example you may
Packit cb6d3d
    have used that for other purposes such as to get CDDB/CD-Text
Packit cb6d3d
    information.  @see cdio_cddap_identify
Packit cb6d3d
 */
Packit cb6d3d
cdrom_drive_t *
Packit cb6d3d
cdio_cddap_identify_cdio(CdIo_t *p_cdio, int messagedest, char **ppsz_messages)
Packit cb6d3d
{
Packit cb6d3d
  if (!p_cdio) return NULL;
Packit cb6d3d
  {
Packit cb6d3d
    const char *psz_device = cdio_get_arg(p_cdio, "source");
Packit cb6d3d
    idmessage(messagedest, ppsz_messages, "Checking %s for cdrom...",
Packit cb6d3d
	      psz_device);
Packit cb6d3d
    return cdda_identify_device_cdio(p_cdio, psz_device, messagedest,
Packit cb6d3d
				     ppsz_messages);
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
}
Packit cb6d3d
Packit cb6d3d
static cdrom_drive_t *
Packit cb6d3d
cdda_identify_device_cdio(CdIo_t *p_cdio, const char *psz_device,
Packit cb6d3d
			  int messagedest, char **ppsz_messages)
Packit cb6d3d
{
Packit cb6d3d
  cdrom_drive_t *d=NULL;
Packit cb6d3d
  int drive_type = 0;
Packit cb6d3d
  char *description=NULL;
Packit cb6d3d
#ifdef HAVE_LINUX_MAJOR_H
Packit cb6d3d
  struct stat st;
Packit cb6d3d
#endif
Packit cb6d3d
Packit cb6d3d
  if (!p_cdio) {
Packit cb6d3d
    idperror(messagedest, ppsz_messages, "\t\tUnable to open %s", psz_device);
Packit cb6d3d
    return NULL;
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
#ifdef HAVE_LINUX_MAJOR_H
Packit cb6d3d
  if ( 0 == stat(psz_device, &st) ) {
Packit cb6d3d
    if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
Packit cb6d3d
      drive_type=(int)(st.st_rdev>>8);
Packit cb6d3d
      switch (drive_type) {
Packit cb6d3d
      case IDE0_MAJOR:
Packit cb6d3d
      case IDE1_MAJOR:
Packit cb6d3d
      case IDE2_MAJOR:
Packit cb6d3d
      case IDE3_MAJOR:
Packit cb6d3d
	/* Yay, ATAPI... */
Packit cb6d3d
	description=strdup("ATAPI compatible ");
Packit cb6d3d
	break;
Packit cb6d3d
      case CDU31A_CDROM_MAJOR:
Packit cb6d3d
	/* major indicates this is a cdrom; no ping necessary. */
Packit cb6d3d
	description=strdup("Sony CDU31A or compatible");
Packit cb6d3d
	break;
Packit cb6d3d
      case CDU535_CDROM_MAJOR:
Packit cb6d3d
	/* major indicates this is a cdrom; no ping necessary. */
Packit cb6d3d
	description=strdup("Sony CDU535 or compatible");
Packit cb6d3d
	break;
Packit cb6d3d
Packit cb6d3d
      case MATSUSHITA_CDROM_MAJOR:
Packit cb6d3d
      case MATSUSHITA_CDROM2_MAJOR:
Packit cb6d3d
      case MATSUSHITA_CDROM3_MAJOR:
Packit cb6d3d
      case MATSUSHITA_CDROM4_MAJOR:
Packit cb6d3d
	/* major indicates this is a cdrom; no ping necessary. */
Packit cb6d3d
	description=strdup("non-ATAPI IDE-style Matsushita/Panasonic CR-5xx or compatible");
Packit cb6d3d
	break;
Packit cb6d3d
      case SANYO_CDROM_MAJOR:
Packit cb6d3d
	description=strdup("Sanyo proprietary or compatible: NOT CDDA CAPABLE");
Packit cb6d3d
	break;
Packit cb6d3d
      case MITSUMI_CDROM_MAJOR:
Packit cb6d3d
      case MITSUMI_X_CDROM_MAJOR:
Packit cb6d3d
	description=strdup("Mitsumi proprietary or compatible: NOT CDDA CAPABLE");
Packit cb6d3d
	break;
Packit cb6d3d
      case OPTICS_CDROM_MAJOR:
Packit cb6d3d
	description=strdup("Optics Dolphin or compatible: NOT CDDA CAPABLE");
Packit cb6d3d
	break;
Packit cb6d3d
      case AZTECH_CDROM_MAJOR:
Packit cb6d3d
	description=strdup("Aztech proprietary or compatible: NOT CDDA CAPABLE");
Packit cb6d3d
	break;
Packit cb6d3d
      case GOLDSTAR_CDROM_MAJOR:
Packit cb6d3d
	description=strdup("Goldstar proprietary: NOT CDDA CAPABLE");
Packit cb6d3d
	break;
Packit cb6d3d
      case CM206_CDROM_MAJOR:
Packit cb6d3d
	description=strdup("Philips/LMS CM206 proprietary: NOT CDDA CAPABLE");
Packit cb6d3d
	break;
Packit cb6d3d
Packit cb6d3d
      case SCSI_CDROM_MAJOR:
Packit cb6d3d
      case SCSI_GENERIC_MAJOR:
Packit cb6d3d
	/* Nope nope nope */
Packit cb6d3d
	description=strdup("SCSI CD-ROM");
Packit cb6d3d
	break;
Packit cb6d3d
      default:
Packit cb6d3d
	/* What the hell is this? */
Packit cb6d3d
	idmessage(messagedest, ppsz_messages,
Packit cb6d3d
		  "\t\t%s is not a cooked ioctl CDROM.",
Packit cb6d3d
		  psz_device);
Packit cb6d3d
	return(NULL);
Packit cb6d3d
      }
Packit cb6d3d
    }
Packit cb6d3d
  }
Packit cb6d3d
#endif /*HAVE_LINUX_MAJOR_H*/
Packit cb6d3d
Packit cb6d3d
  /* Minimum init */
Packit cb6d3d
Packit cb6d3d
  d=calloc(1, sizeof(cdrom_drive_t));
Packit cb6d3d
  d->p_cdio           = p_cdio;
Packit cb6d3d
  d->cdda_device_name = strdup(psz_device);
Packit cb6d3d
  d->drive_type       = drive_type;
Packit cb6d3d
  d->bigendianp       = -1; /* We don't know yet... */
Packit cb6d3d
  d->nsectors         = -1; /* We don't know yet... */
Packit cb6d3d
  d->messagedest      = messagedest;
Packit cb6d3d
  d->b_swap_bytes     = true;
Packit cb6d3d
Packit cb6d3d
  {
Packit cb6d3d
    cdio_hwinfo_t hw_info = {
Packit cb6d3d
      "UNKNOWN", "Unknown model", "????"
Packit cb6d3d
    };
Packit cb6d3d
Packit cb6d3d
    if ( mmc_get_hwinfo( p_cdio, &hw_info ) ) {
Packit cb6d3d
      unsigned int i_len = strlen(hw_info.psz_vendor)
Packit cb6d3d
	+ strlen(hw_info.psz_model)
Packit cb6d3d
	+ strlen(hw_info.psz_revision) + 5;
Packit cb6d3d
Packit cb6d3d
      if (description) {
Packit cb6d3d
	i_len += strlen(description);
Packit cb6d3d
	d->drive_model=malloc( i_len );
Packit cb6d3d
	snprintf( d->drive_model, i_len, "%s %s %s %s",
Packit cb6d3d
		  hw_info.psz_vendor, hw_info.psz_model, hw_info.psz_revision,
Packit cb6d3d
		  description );
Packit cb6d3d
      } else {
Packit cb6d3d
	d->drive_model=malloc( i_len );
Packit cb6d3d
	snprintf( d->drive_model, i_len, "%s %s %s",
Packit cb6d3d
		  hw_info.psz_vendor, hw_info.psz_model, hw_info.psz_revision
Packit cb6d3d
		  );
Packit cb6d3d
      }
Packit cb6d3d
      idmessage(messagedest, ppsz_messages, "\t\tCDROM sensed: %s\n",
Packit cb6d3d
		d->drive_model);
Packit cb6d3d
    }
Packit cb6d3d
  }
Packit cb6d3d
Packit cb6d3d
  if (description)
Packit cb6d3d
    free(description);
Packit cb6d3d
Packit cb6d3d
  return(d);
Packit cb6d3d
}