LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Software (https://www.linuxquestions.org/questions/linux-software-2/)
-   -   Program to check whether a disk is in a drive? (https://www.linuxquestions.org/questions/linux-software-2/program-to-check-whether-a-disk-is-in-a-drive-218995/)

g4c9z 08-17-2004 07:48 PM

Program to check whether a disk is in a drive?
 
Hello,

Is there a Linux command to check whether there's a disk in a drive? Even an API function in C or C++? Basically, what I'm looking for is something that would be used like this:

if diskin /dev/cdrom
then ...
fi

The best I've been able to come up with is to mount it, then try to unmount it, and if the umount command returns successfully, there was a disk in the drive. But this doesn't work for music CDs, DVDs, or blank CDs - only for media that contain a filesystem that Linux recognizes.

My primary use for this is I want to make all the disks in all my drives get ejected automatically at shutdown, just like on a Mac (I often forget disks in drives), but I don't want my CD trays popping out if there's nothing in them.

arvind_sv 08-17-2004 09:21 PM

How about a small hack which uses the Workman library used by KDE? Here's the program:

Code:

int main (void) {
    if (wm_cd_init (0, "/dev/cdrom", 0, 0, 0) == 10) {
        return (1);
    }
    return (0);
}

Compile using:
gcc diskin.c -L`kde-config --prefix`/lib -lworkman -I `kde-config --prefix`/include -o diskin

Use as you mentioned: (argv[1] = /dev/cdrom not really used)
Code:

if diskin /dev/cdrom
then
    unmount and eject
    ...
fi

As I said, this is just a hack. I don't even know whether it'll work everywhere. The same code, maybe a little more portable and easier to understand six months down the line:

Code:

#include <libwm/wm_cdrom.h>

int main (int argc, char **argv) {
    char *DEFAULT_DEV = "/dev/cdrom";
    char *dev = DEFAULT_DEV;

    if (argc > 1) {
        dev = argv[1];
    }

    if (wm_cd_init (0, dev, 0, 0, 0) == WM_CDM_NO_DISC) {
        return (1);
    }

    return (0);
}

If you don't have KDE, then, you can look at how the "eject" command (http://eject.sourceforge.net/) handles the CD drive or directly use the CDROM interface provided by the Linux kernel. Look at the documentation at: /usr/src/linux/Documentation/cdrom/

Arvind

arvind_sv 08-17-2004 09:26 PM

I forgot to mention. If argv[1] is an invalid device, it still returns 0. I don't believe it's that much of a big problem.

Arvind

g4c9z 08-17-2004 09:57 PM

Thanks! I'll have to look into that wm_cd_init function.

I think it would definitely be worthwhile to make sure the argument is valid - after all, a program should work every single time and people sometimes make typos. That could be done by checking whether the device file exists. Better still would be to check whether it's actually a disk drive, but I don't know how.

arvind_sv 08-17-2004 11:24 PM

Quote:

Originally posted by g4c9z
I think it would definitely be worthwhile to make sure the argument is valid - after all, a program should work every single time and people sometimes make typos. That could be done by checking whether the device file exists. Better still would be to check whether it's actually a disk drive, but I don't know how.
Oh, of course, the program should work every single time. But, the "worthwhile" part is where I have to disagree. It's certainly not worth MY while to write the whole program with error-checking for you. ;)

The main part of checking if a CD is in is done. You do the rest.

Arvind

g4c9z 08-18-2004 07:38 AM

Of course; I didn't mean it that way. I meant it's worth my while to do the checking. I'm grateful for your suggestions.

g4c9z 08-20-2004 08:59 AM

I just got around to trying that wm_cd_init function, and the program wouldn't compile. It seems that I don't have the "workman" library installed. What package is it part of?

arvind_sv 08-26-2004 04:06 AM

Hi,

Somehow I did not receive the notification for the message of yours. So, I'm this late in replying.

The workman library is a part of "kdemultimedia" package. I think you can use the "eject" command's source directly. You will just have to prevent it from opening the drive if it fails to find a CD. I'm looking at the sources now. I'll tell you if I find out more about it.

Arvind

arvind_sv 08-26-2004 04:38 AM

Hi,

/usr/include/linux/cdrom.h says:
Code:

/* drive status possibilities returned by CDROM_DRIVE_STATUS ioctl */
#define CDS_NO_INFO    0  /* if not implemented */
#define CDS_NO_DISC    1
#define CDS_TRAY_OPEN      2
#define CDS_DRIVE_NOT_READY 3
#define CDS_DISC_OK    4

Just as a test, I added the following lines to the eject source after the line:
"if (n_option)" [Line 903] [eject-2.0.13]

Code:

#ifdef CDROM_DRIVE_STATUS
    int status = 0, xfd = 0;
    xfd = OpenDevice(deviceName);
    status = ioctl(xfd, CDROM_DRIVE_STATUS);
    fprintf (stderr, "Status: %d\n", status);
#endif

As I said, according to cdrom.h, it *should* return 4 when there's a disc in it, and 1 when it's not. It does return 4, but seems to return 2 (instead of 1) when there's a disc in it. If you think it's reliable (fails reliably) enough, try it out.

You can rip out everything you don't want from eject.c.

Arvind

g4c9z 08-26-2004 01:12 PM

Thanks a lot! I'll have to try that, but I might not get a chance for a few days. That ioctl looks promising.

arvind_sv 08-26-2004 08:33 PM

Sure. But, tell me how it goes.

Arvind

g4c9z 08-27-2004 02:00 PM

I've completed the program. You're right that ioctl returns 2 when, according to the documentation, it should return 1. I've tried it on both my internal DVD-ROM and external CD Writer. Strange. Do you think it's a bug in the Linux kernel?

I was just thinking, too bad this only works for CD-ROM drives; I was looking for a way to check whether a disk is in any drive. I guess there's no single command to do that, right, since each piece of hardware is different? Anyway, for my purposes, this is just fine, and is much less of an ugly hack than I was doing before.

Here's the complete C program:
Code:

/*This code may be used in any way, except you may not call it your own
(you need not explicitly say it's mine).*/

#include <linux/cdrom.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>

int main(int argc, char** argv) {
        int fd, status;
        if (argc != 2) {
                printf("Usage: %s <device>\n", argv[0]);
        }
        else if ((fd = open(argv[1], O_RDONLY | O_NONBLOCK)) == -1) {  /* Without
                        O_NONBLOCK and if there's no disk in the drive, it for some reason won't open
                        it, and perror returns an error message "No medium found".*/
                if (errno == EACCES)
                        fprintf(stderr, "Error: You don't have permission to read from %s\n", argv[1]);
                else if (errno == ENOENT)
                        fprintf(stderr, "Error: There is no such device as: %s\n", argv[1]);
                else if (errno == ENXIO || errno == ENODEV)
                        fprintf(stderr, "Error: The device file \"%s\" exists, but "
                                "it seems like the device itself is not attached to the computer.\n", argv[1]);
                else {
                        fprintf(stderr, "Error: Couldn't access device: %s. ", argv[1]);
                        perror("The error message returned by the system is");
                }
        }
        else {
                /* For some reason when a disk isn't in but the tray is closed, ioctl returns 2.
                It seems from the documentation in linux/cdrom.h that it should return 1. */
                status = ioctl(fd, CDROM_DRIVE_STATUS);
                close(fd);

#ifdef DEBUG
                printf("%d\n", status);
#endif
                if (status == -1)
                        fprintf(stderr, "Error when trying to get the CDROM drive status.  "
                                "Probably %s isn't a CDROM drive.", argv[1]);
                else if (status == 0)
                        fprintf(stderr, "That CDROM drive doesn't seem to support "
                                "checking its \"disk present\" status.");
                else if (status == 4)
                        return 0;
        }
        return 1;  /*Any alternative except the one leading to "return 0" means there's no disk.*/
}

Thanks for all your help!

arvind_sv 08-27-2004 08:12 PM

Hi,

Quote:

Do you think it's a bug in the Linux kernel?
I don't know. I don't think so. Such blatant bugs are normally found and corrected. Maybe the documentation is wrong. I saw a small note somewhere online:

Quote:

/*
* If not using Mt Fuji extended media tray reports,
* just return TRAY_OPEN since ATAPI doesn't provide
* any other way to detect this...
*/
So, maybe the capability is not present in some drives. Who knows? But, this has been a known "bug" from kernel 2.2.12, going by http://www.mail-archive.com/linux-de.../msg00071.html

The cdrom.h is meant to be a uniform CDROM device interfce. I think it supports (or will support) DVD drives. It has some "capability" flags to find out whether the drive is a DVD drive. But, I don't know why it's not working. What happens when you try? Maybe you got the device wrong?

If I get some time, I'll see what's going on.

Arvind

arvind_sv 08-27-2004 08:16 PM

Ah good, the kernel maintainers know about this, and it's specifically introduced so that newer drives will work properly, as far as I can see. See this:

http://www.ussg.iu.edu/hypermail/lin...02.2/0281.html

Arvind

g4c9z 08-27-2004 08:41 PM

Quote:

I think it supports (or will support) DVD drives. It has some "capability" flags to find out whether the drive is a DVD drive. But, I don't know why it's not working. What happens when you try?
I would be willing to try it, but I don't know what kind of function to call. cdrom.h gave a bunch of different #defines for DVDs but didn't say how to use them. I don't see why DVDs wouldn't be supported if the stuff is in that file, but if it isn't working for you, just give me some code and I'll try to run it with my DVD drive.


All times are GMT -5. The time now is 03:03 PM.