Извлечение компакт-диска с помощью кода C

Я пытаюсь извлечь свой компакт-диск с помощью кода C. И он не хочет работать. ioctl вернул ошибку ввода-вывода «5», в чем может быть проблема?

#include <stdio.h>
#include <fcntl.h>
#include <linux/cdrom.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
int eject_cdrom()
{
    char path_to_cdrom[20]="/dev/cdrom";
    int fd = open("/dev/cdrom", O_RDONLY| O_NONBLOCK);
    printf("%d\n",fd );
    int lala = ioctl(fd, CDROMEJECT);
    printf("%d\n",lala);
    close(fd);
    return lala;
}

int main(int argc, char* argv[])
{
    //eject_cdrom_system();
    int value = eject_cdrom();
    printf("%d\n",value );
    if (value == -1) 
    {
        int errsv = errno;
        printf("somecall() failed\n");
        printf("%d\n",errsv );
    }

    return 0;
}

Когда я пробовал эту функцию

void eject_cdrom_system()
    {
        system("/usr/bin/eject");
    }

Это работает отлично. Но я хочу сделать это с помощью первой функции (eject_cdrom).

Вывод из strace:

strace -f ./cdrom

execve("./cdrom", ["./cdrom"], [/* 76 vars */]) = 0
brk(0)                                  = 0xf9c000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcb50cd7000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=131512, ...}) = 0
mmap(NULL, 131512, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fcb50cb6000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\37\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1845024, ...}) = 0
mmap(NULL, 3953344, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fcb506f1000
mprotect(0x7fcb508ad000, 2093056, PROT_NONE) = 0
mmap(0x7fcb50aac000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1bb000) = 0x7fcb50aac000
mmap(0x7fcb50ab2000, 17088, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fcb50ab2000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcb50cb5000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fcb50cb3000
arch_prctl(ARCH_SET_FS, 0x7fcb50cb3740) = 0
mprotect(0x7fcb50aac000, 16384, PROT_READ) = 0
mprotect(0x600000, 4096, PROT_READ)     = 0
mprotect(0x7fcb50cd9000, 4096, PROT_READ) = 0
munmap(0x7fcb50cb6000, 131512)          = 0
open("/dev/cdrom", O_RDONLY|O_NONBLOCK) = 3
ioctl(3, CDROMEJECT, 0)                 = -1 EIO (Input/output error)
close(3)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

person Community    schedule 26.06.2014    source источник
comment
Вы пытались использовать strace, чтобы увидеть, что делает eject?   -  person Juan    schedule 26.06.2014
comment
только с: strace ./program_name ?   -  person    schedule 26.06.2014
comment
strace -f /usr/bin/eject может быть лучше, так как -f ловит форки.   -  person Juan    schedule 26.06.2014
comment
Я отредактировал свой пост с выводом strace ... я вижу только эту ошибку ввода-вывода, ничего больше   -  person    schedule 26.06.2014


Ответы (1)


Для пользы всех, кто забредет в негугл, я перечислю все возможные причины, которые вижу:

  1. Вы явно указываете /dev/cdrom в своем коде, но разрешаете eject автоматически определять это.

    Некоторые дистрибутивы не устанавливают /dev/cdrom как символическую ссылку на /dev/sr0 или эквивалентную. Типа он подключен? вопрос, но включен для полноты.

  2. Я не уверен, что необработанный ioctl будет разрешать символические ссылки

    Возможно, /usr/bin/eject должен сделать дополнительный вызов API, чтобы добиться успеха.

  3. Вы просто предполагаете, что eject будет использовать этот API

    Согласно man eject, утилита /usr/bin/eject поддерживает как минимум четыре различных API извлечения, два из которых (CDROM и SCSI) могут применяться к оптическим устройствам.

Я на самом деле проверил это в своей системе, и когда я принудительно использовал API, который вы используете, запустив eject с параметром -r, он потерпел неудачу с той же ошибкой.

$ eject -r /dev/cdrom
eject: unable to eject, last error: Input/output error

Тем не менее, форсирование SCSI API (который был расширен, чтобы охватить также SATA, а затем PATA) работает для меня.

$ eject -s /dev/cdrom
person ssokolow    schedule 21.10.2016