LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Slackware (http://www.linuxquestions.org/questions/slackware-14/)
-   -   Detect CD tray status (http://www.linuxquestions.org/questions/slackware-14/detect-cd-tray-status-4175450610/)

Woodsman 02-18-2013 01:21 AM

Detect CD tray status
 
Superfluous project of the day:

I'm looking for a way to detect a CD drive tray status.

Background: I have a vintage system with a nice CD writer but the drive does not support the eject -T command. I can only use eject or eject -t. On all of my other systems I have a handy desktop shortcut with the eject -T command. :) I can't use that shortcut with this drive --- I need two shortcuts. :(

I prefer to detect the tray status with the stock Slackware tools. I've seen some possible solutions but they require lshw or hwinfo. The /usr/include/linux/cdrom.h has a CDROM_DRIVE_STATUS option, but I'm not a C coder.

All I seek is something like this:

Code:

if [ $TRAY_IS_OPEN ];
  eject -t
else
  eject
fi

Using lshw, which is not part of the stock Slackware, I can use something like this (slow --- takes a few seconds to execute):

Code:

if [ "`/usr/sbin/lshw -quiet 2>/dev/null | awk '/\*-cd/,/con/' | sed -e 's/^[ \t]*//' | grep configuration | cut -d ' ' -f3`" = "status=open" ]; then
  eject -t
else
  eject
fi

Seems if lshw can pull the information that the information exists somewhere. I've been looking into /proc, sg3_utils, and udisks, but haven't found anything. Too bad the eject command is not a little more robust. :)

Thanks.

volkerdi 02-18-2013 02:01 AM

Here's a simple C program:

Code:

#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/cdrom.h>

int main(int argc,char **argv) {
    int cdrom;
    int status=1;

    if ((cdrom = open(argv[1],O_RDONLY | O_NONBLOCK)) < 0) {
        printf("Unable to open device %s",argv[1]);
        exit(1);
    }

    if (ioctl(cdrom,CDROM_DRIVE_STATUS) == CDS_TRAY_OPEN) {
        status=0;
    }

    close(cdrom);
    exit(status);
}

Compile it with gcc, call it trayopen. Then you can use it in scripts based on the exit code, like so:

./trayopen /dev/sr0 && echo tray is open || echo tray is closed

Woodsman 02-18-2013 12:46 PM

Pat, that is very kind of you. Thank you! :)

I'm not a C coder but I can read uncomplicated C code and write a basic printf command. Because I tend to forget things as I age, here is version 0.2 with some reminders for me how to use. I added two includes to fix the compile warnings (I had to search the web to learn how to do that :)).

Code:

#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/cdrom.h>

int main(int argc,char **argv) {
  int cdrom;
  int status=1;

  printf("Usage: trayopen [device]\n");
  printf("Result: Open tray exit code 0, closed tray exit code 1.\n");

  if ((cdrom = open(argv[1],O_RDONLY | O_NONBLOCK)) < 0) {
    printf("Unable to open device %s. Provide a device name (/dev/sr0, /dev/cdrom) as a parameter.\n",argv[1]);
    exit(1);
  }

  if (ioctl(cdrom,CDROM_DRIVE_STATUS) == CDS_TRAY_OPEN) {
    status=0;
  }

  close(cdrom);
  exit(status);
}

I wonder whether the eject source code could be patched with something similar to your simple program? Seems the "eject -T" parameter needs only to query the status of the device as you did and then the -T option would work on any optical disk device.

volkerdi 02-18-2013 01:56 PM

Quote:

Originally Posted by Woodsman (Post 4894541)
I wonder whether the eject source code could be patched with something similar to your simple program? Seems the "eject -T" parameter needs only to query the status of the device as you did and then the -T option would work on any optical disk device.

Could the solution be as simple as something like "eject -T -s /dev/sr0"?

Long shot, but it's worth a try.

GazL 02-18-2013 02:37 PM

LOL. Out of curiosity I just looked at the code that does the toggle in eject, and it basically does this:
  1. gets time of day
  2. opens tray
  3. gets time of day
  4. compare times
  5. if it opened very quickly then it must have already been open so close tray.

:doh:


Anyway, try this patch. It replaces the eject_for_mac.patch file in the slackbuild. (Needs to be applied with -p1 not -p4).
Works on my box, but no idea how it will behave on other people's machines

Woodsman 02-18-2013 03:57 PM

Quote:

Could the solution be as simple as something like "eject -T -s /dev/sr0"?
Nope. Been there done that. :)

Quote:

LOL. Out of curiosity I just looked at the code that does the toggle in eject, and it basically does this:
Last night I looked at the eject.c sources. I am not a C coder but I saw the same thing. Because I'm not a C coder I presumed I was not seeing something obvious. Nice to see that I was not far off base. :)

Quote:

Anyway, try this patch.
I'll give that a whirl and report later.

Woodsman 02-18-2013 04:29 PM

My report:

I tested on 4 systems here.

On two modern systems, eject -T works with the stock Slackware eject and the newly patched eject.

On a PI system with a Creative Labs (MATSHITA CR-585 ZU17) 24x CD-ROM, the stock eject -T works to open and close the drive, but the new patched version does not. With the new patch eject -T opens the tray but will not close. Further, the C code Pat provided does not correctly reflect the tray status on this machine. That is, the trayopen command reports the tray is closed when the tray is open.

On a PII system, the original problem system that started this thread, the stock Slackware eject -T does not close the tray. The newly patched version works both to open and close. That system has a HP CD-Writer+ 9300 1.0c 10x/4x/32x CD Recorder.

So with the stock eject the PI system works correctly with eject -T but not with the PII system. The newly patched eject works with the PII system but not the PI.

Seems some combination of the new patch and the "mac" patch are needed. :)

GazL 02-18-2013 04:37 PM

Pat's code above doesn't check for errors from the ioctl so if you get a 1 you don't know whether it's because the call failed or the drive is closed. If you run strace eject -T /dev/sr0 you'll see the results of the ioctls at the end of the output. You can also use strace on pats trayopen command.

What kernels are your older boxes using?

The patch I provided includes the change that the mac patch was making previously, so I don't think that matters.


Perhaps the answer is to include the time based operation as a fallback if CDROM_DRIVE_STATUS doesn't work. Maybe that would sort out your P1 machine.
If you could show me the last bit of the strace on the one that doesn't work I'll see what I can do.

GazL 02-18-2013 05:58 PM

Ok, I took a guess that the MATSHITA drive was returning CDS_NO_INFO for the CDROM_DRIVE_STATUS query.

Here's an updated patch if you want to try it.

Woodsman 02-18-2013 06:01 PM

Quote:

What kernels are your older boxes using?
I'm using the stock 3.2.29 non-smp kernels with Slackware 14.

Quote:

Maybe that would sort out your P1 machine. If you could show me the last bit of the strace on the one that doesn't work I'll see what I can do.
At this point I'm interested in a patch that Pat can merge to help everybody. :)

That said, attached are the last few lines from 8 straces.

======================================================
PI, stock Slackware (eject -T works to open and close)
======================================================

Tray is closed, attempt to open:
================================
stat64("/dev/sr0", {st_mode=S_IFBLK|0660, st_rdev=makedev(11, 0), ...}) = 0
open("/dev/sr0", O_RDONLY|O_NONBLOCK) = 3
gettimeofday({1361231138, 960547}, NULL) = 0
ioctl(3, CDROMEJECT, 0) = 0
gettimeofday({1361231140, 894047}, NULL) = 0
exit_group(0) = ?

Tray is open, attempt to close:
===============================
stat64("/dev/sr0", {st_mode=S_IFBLK|0660, st_rdev=makedev(11, 0), ...}) = 0
open("/dev/sr0", O_RDONLY|O_NONBLOCK) = 3
gettimeofday({1361231159, 60890}, NULL) = 0
ioctl(3, CDROMEJECT, 0) = 0
gettimeofday({1361231159, 194454}, NULL) = 0
ioctl(3, CDROMCLOSETRAY, 0) = 0
exit_group(0) = ?

=====================================================
PI, newly patched (eject -T opens but fails to close)
=====================================================

Tray is closed, attempt to open:
================================
stat64("/dev/sr0", {st_mode=S_IFBLK|0660, st_rdev=makedev(11, 0), ...}) = 0
open("/dev/sr0", O_RDONLY|O_NONBLOCK) = 3
ioctl(3, CDROM_DRIVE_STATUS, 0x804b82c) = 1
ioctl(3, CDROMEJECT, 0) = 0
exit_group(0) = ?

Tray is open, attempt to close FAILS:
=====================================
stat64("/dev/sr0", {st_mode=S_IFBLK|0660, st_rdev=makedev(11, 0), ...}) = 0
open("/dev/sr0", O_RDONLY|O_NONBLOCK) = 3
ioctl(3, CDROM_DRIVE_STATUS, 0x804b82c) = 1
ioctl(3, CDROMEJECT, 0) = 0
exit_group(0) = ?


========================================================
PII, stock Slackware (eject -T opens but fails to close)
========================================================

Tray is closed, attempt to open:
================================
stat64("/dev/sr0", {st_mode=S_IFBLK|0660, st_rdev=makedev(11, 0), ...}) = 0
open("/dev/sr0", O_RDONLY|O_NONBLOCK) = 3
gettimeofday({1361231700, 129791}, NULL) = 0
ioctl(3, CDROMEJECT, 0) = 0
gettimeofday({1361231702, 429991}, NULL) = 0
exit_group(0) = ?

Tray is open, attempt to close FAILS:
=====================================
stat64("/dev/sr0", {st_mode=S_IFBLK|0660, st_rdev=makedev(11, 0), ...}) = 0
open("/dev/sr0", O_RDONLY|O_NONBLOCK) = 3
gettimeofday({1361231750, 488658}, NULL) = 0
ioctl(3, CDROMEJECT, 0) = 0
gettimeofday({1361231751, 180760}, NULL) = 0
exit_group(0) = ?

=====================================================
PII, newly patched (eject -T works to open and close)
=====================================================

Tray is closed, attempt to open:
================================
stat64("/dev/sr0", {st_mode=S_IFBLK|0660, st_rdev=makedev(11, 0), ...}) = 0
open("/dev/sr0", O_RDONLY|O_NONBLOCK) = 3
ioctl(3, CDROM_DRIVE_STATUS, 0x804b82c) = 1
ioctl(3, CDROMEJECT, 0) = 0
exit_group(0) = ?

Tray is open, attempt to close:
===============================
stat64("/dev/sr0", {st_mode=S_IFBLK|0660, st_rdev=makedev(11, 0), ...}) = 0
open("/dev/sr0", O_RDONLY|O_NONBLOCK) = 3
ioctl(3, CDROM_DRIVE_STATUS, 0x804b82c) = 2
ioctl(3, CDROMCLOSETRAY, 0x804b82c) = 0
exit_group(0) = ?

Woodsman 02-18-2013 06:02 PM

Quote:

Here's an updated patch if you want to try it.
Oops! Are posts crossed paths. :)

I'll test right away.

Woodsman 02-18-2013 06:08 PM

Same results. The PI works with the stock eject -T but with the new second patch only opens. The PII opens with the stock eject but will not close. With the new second patch the tray opens and closes.

====================================================
PI, second patch (eject -T opens but fails to close)
====================================================

Tray is closed, attempt to open:
================================
stat64("/dev/sr0", {st_mode=S_IFBLK|0660, st_rdev=makedev(11, 0), ...}) = 0
open("/dev/sr0", O_RDONLY|O_NONBLOCK) = 3
ioctl(3, CDROM_DRIVE_STATUS, 0) = 1
ioctl(3, CDROMEJECT, 0) = 0
exit_group(0) = ?

Tray is open, attempt to close FAILS:
=====================================
stat64("/dev/sr0", {st_mode=S_IFBLK|0660, st_rdev=makedev(11, 0), ...}) = 0
open("/dev/sr0", O_RDONLY|O_NONBLOCK) = 3
ioctl(3, CDROM_DRIVE_STATUS, 0) = 1
ioctl(3, CDROMEJECT, 0) = 0
exit_group(0) = ?

GazL 02-18-2013 06:20 PM

Code:

=====================================================
 PI, newly patched (eject -T opens but fails to close)
 =====================================================

 Tray is open, attempt to close FAILS:
 =====================================
 stat64("/dev/sr0", {st_mode=S_IFBLK|0660, st_rdev=makedev(11, 0), ...}) = 0
 open("/dev/sr0", O_RDONLY|O_NONBLOCK) = 3
 ioctl(3, CDROM_DRIVE_STATUS, 0x804b82c) = 1
 ioctl(3, CDROMEJECT, 0) = 0
 exit_group(0) = ?

Ahh, that's the problem there. I don't think my v2 will help (unless the ', 0') I added to the ioctl call helps ( edit: which I see it didn't :( ).
Your MATSHITSA drive is returning CDS_NO_DISC to CDROM_DRIVE_STATUS whether the drive is open or closed.

Damn! Off-hand, I don't see any way around that. :(

GazL 02-18-2013 07:07 PM

The problem with your PII and the stock eject seems to be that its responding too slowly to the first CDROMEJECT of an already open drive to meet the conditions
in the TRAY_WAS_ALREADY_OPEN_USECS check and thus never trying to close it. You could try increasing that time limit, but the danger is that if you set it too high it may trigger a close instead of an open for some drives when you're trying to open them.

I've attached a v3 of the patch, Basically it'll check for CDS_TRAY_OPEN first, and then fall back to the old mechanism for everything else.

Anyway, here it is for what it is worth. I don't think I'd suggest it for inclusion in stock slackware though. It might sort your specific problems out, but IMO it's only half a solution and version 2 or even the version 1 of my patch are more correct (but unfortunately won't work with your aptly named MATSHITA drive which doesn't provide accurate status.

Woodsman 02-18-2013 07:42 PM

Quote:

Anyway, here it is for what it is worth.
Revision 3 works on all systems here. :) Good job!

Quote:

I don't think I'd suggest it for inclusion in stock slackware though.
Perhaps if other people with quirky optical drives find the patch useful that might provide some motivation. :)


All times are GMT -5. The time now is 11:21 AM.