How can ejecting an audio CD by using cdaudio's cd_eject () method produce errno #5? - ioctl

I'm trying to playback an audio CD from my app by using the cdaudio library + a USB DVD drive attached to a Raspi 3B. Trying to eject the CD after playback always makes me end up with errno #5. This is my code:
void sound::Eject ()
{
struct disc_status cd_stat;
if (sound::current_sound_source == CD) {
sound::Stop ();
cd_poll (sound::cd_drive_handler, &cd_stat);
if (sound::is_cd_stopped && cd_stat.status_present == 1) {
if ((cd_eject (sound::cd_drive_handler)) < 0) cout << "Ejecting CD failed! Error: " << strerror (errno) << endl;
}
}
}
This is the output I get:
ioctl returned -1
Ejecting CD failed! Error: Input/output error
When trying to eject the CD, I hear a noise in the drive, as if it was about to access the CD, for about half a second. This is the drive I'm using:
pi#autoradio:~ $ ls -al /dev/sr*
brw-rw----+ 1 root cdrom 11, 0 Mai 1 21:38 /dev/sr0
Ejecting the CD from the command line (eject /dev/sr0), does work, though.
Does anybody know what may cause this error? Thank you.
UPDATE #1: I gave cdcd (the command-line tool for audio CDs) a try, and I could reproduce the error there, too (even under sudo):
cdcd> eject
ioctl returned -1
UPDATE #2: I found out that cdaudio calls ioctl with the CDAUDIO_EJECT command (see sourcecode), but I can't find such a command anywhere in the linux/cdrom.h file. According to one of the developers of the cdaudio library, this is just an alias for CDROMEJECT and not a bug.
UPDATE #3: strace give me this output. I hope this is sufficient:
ioctl(3, CDROM_DISC_STATUS, 0) = 100
ioctl(3, CDROMSUBCHNL, 0x7e93e308) = 0
ioctl(3, CDROMEJECT, 0x1) = -1 EIO (Input/output error)
write(1, "ioctl returned -1\n", 18) = 18
In contrast, when tracing the eject utility, I get something slightly different:
geteuid32() = 1000
open("/dev/sr0", O_RDWR|O_NONBLOCK) = 3
ioctl(3, CDROMEJECT, 0x1) = 0
close(3) = 0
exit_group(0) = ?
+++ exited with 0 +++
A comparison of the open () calls reveals that the cdaudio library apparently opens the drive on read-only mode (which is theoretically correct, but, on the other hand, seems to choke the eject command):
open("/dev/sr0", O_RDONLY|O_NONBLOCK) = 3
SEE ALSO: Question #26240195

OK, after a couple of weeks of studying the eject utility, I found out that at least some CD drives wouldn't accept a CDROMEJECT command via ioctl (), but require a bunch of SCSI commands. In fact, eject contains a method, which is used as a fallback in such situations: eject_scsi (). I implanted this method into cdaudio. Tests were successful. So I asked the maintainers of cdaudio for a respective patch.

Related

What's a bad file descriptor?

I have the next system swi-prolog in a file call 'system.pl';
helloWorld :- read(X), write(X).
And i want to test it, then, i write it;
:- begin_tests(helloWorld_test).
test(myTest, true(Output == "hello")) :-
with_output_to(string(Output), getEntry).
:- end_tests(helloWorld_test).
getEntry :-
open('testcase.test', read, Myfile),
set_input(Myfile),
process_create(path(swipl), ['-g', 'main', '-t', 'halt', 'system.pl'], [stdin(stream(Myfile)), stdout(pipe(Stream))]),
copy_stream_data(Stream, current_output),
close(Myfile).
In testcase.test is contained the following;
hello.
Ok, now, when i call to swipl -g run_tests -t halt system.pl i get it;
% PL-Unit: helloWorld_test ERROR: -g helloWorld: read/1: I/O error in read on stream user_input (Bad file descriptor)
ERROR: c:/programasvscode/prolog/programasrandom/system.pl:40:
test myTest: wrong answer (compared using ==)
ERROR: Expected: "hello"
ERROR: Got: ""
done
% 1 test failed
% 0 tests passed
ERROR: -g run_tests: false
Warning: Process "c:\swipl\bin\swipl.exe": exit status: 2
I tried use read/2 with current_input but i got the same with the difference of read/2 instead read/1
What does mean it? any solve?

Race condition with stat and mkdir in sequence

Coverity complains of . toctou: Calling function mkdir that uses DIR after a check function. This can cause a time-of-check, time-of-use race condition
if (stat(DIR, &st) != 0)
{
if (mkdir(DIR, 0755) < 0)
{
return ERROR;
}
}
Is it good enough to change the code to ,I was using stat only for file exist check
if (mkdir(NDUID_DIR, 0755) < 0)
{
if(errno != EEXIST)
{
return ERROR;
}
}
Is there a better way to fix the code?
Both of your snippets appear to be incorrect and/or incomplete.
On OpenBSD, sys_mkdir would return -1, and set errno to EEXIST when the target file is present. However, that doesn't guarantee that the target file is a directory -- an existing regular file would still result in mkdir(2) returning the exact same EEXIST.
For guidance of the widely accepted approach, take a look at how mkdir(1) -p option is implemented across the BSDs (bin/mkdir/mkdir.c#mkpath in OpenBSD and NetBSD), all of which, on mkdir(2)'s error, appear to immediately call stat(2) to subsequently run the S_ISDIR macro to ensure that the existing file is a directory, and not just any other type of a file.

Generating .gcda coverage files via QEMU/GDB

Executive summary: I want to use GDB to extract the coverage execution counts stored in memory in my embedded target, and use them to create .gcda files (for feeding to gcov/lcov).
The setup:
I can successfully cross-compile my binary, targeting my specific embedded target - and then execute it under QEMU.
I can also use QEMU's GDB support to debug the binary (i.e. use tar extended-remote localhost:... to attach to the running QEMU GDB server, and fully control the execution of my binary).
Coverage:
Now, to perform "on-target" coverage analysis, I cross-compile with
-fprofile-arcs -ftest-coverage. GCC then emits 64-bit counters to keep track of execution counts of specific code blocks.
Under normal (i.e. host-based, not cross-compiled) execution, when the app finishes __gcov_exit is called - and gathers all these execution counts into .gcdafiles (that gcov then uses to report coverage details).
In my embedded target however, there's no filesystem to speak of - and libgcov basically contains empty stubs for all __gcov_... functions.
Workaround via QEMU/GDB: To address this, and do it in a GCC-version-agnostic way, I could list the coverage-related symbols in my binary via MYPLATFORM-readelf, and grep-out the relevant ones (e.g. __gcov0.Task1_EntryPoint, __gcov0.worker, etc):
$ MYPLATFORM-readelf -s binary | grep __gcov
...
46: 40021498 48 OBJECT LOCAL DEFAULT 4 __gcov0.Task1_EntryPoint
...
I could then use the offsets/sizes reported to automatically create a GDB script - a script that extracts the counters' data via simple memory dumps (from offset, dump length bytes to a local file).
What I don't know (and failed to find any relevant info/tool), is how to convert the resulting pairs of (memory offset,memory data) into .gcda files. If such a tool/script exists, I'd have a portable (platform-agnostic) way to do coverage on any QEMU-supported platform.
Is there such a tool/script?
Any suggestions/pointers would be most appreciated.
UPDATE: I solved this myself, as you can read below - and wrote a blog post about it.
Turned out there was a (much) better way to do what I wanted.
The Linux kernel includes portable GCOV related functionality, that abstracts away the GCC version-specific details by providing this endpoint:
size_t convert_to_gcda(char *buffer, struct gcov_info *info)
So basically, I was able to do on-target coverage via the following steps:
Step 1
I added three slightly modified versions of the linux gcov files to my project: base.c, gcc_4_7.c and gcov.h. I had to replace some linux-isms inside them - like vmalloc,kfree, etc - to make the code portable (and thus, compileable on my embedded platform, which has nothing to do with Linux).
Step 2
I then provided my own __gcov_init...
typedef struct tagGcovInfo {
struct gcov_info *info;
struct tagGcovInfo *next;
} GcovInfo;
GcovInfo *headGcov = NULL;
void __gcov_init(struct gcov_info *info)
{
printf(
"__gcov_init called for %s!\n",
gcov_info_filename(info));
fflush(stdout);
GcovInfo *newHead = malloc(sizeof(GcovInfo));
if (!newHead) {
puts("Out of memory!");
exit(1);
}
newHead->info = info;
newHead->next = headGcov;
headGcov = newHead;
}
...and __gcov_exit:
void __gcov_exit()
{
GcovInfo *tmp = headGcov;
while(tmp) {
char *buffer;
int bytesNeeded = convert_to_gcda(NULL, tmp->info);
buffer = malloc(bytesNeeded);
if (!buffer) {
puts("Out of memory!");
exit(1);
}
convert_to_gcda(buffer, tmp->info);
printf("Emitting %6d bytes for %s\n", bytesNeeded, gcov_info_filename(tmp->info));
free(buffer);
tmp = tmp->next;
}
}
Step 3
Finally, I scripted my GDB (driving QEMU remotely) via this:
$ cat coverage.gdb
tar extended-remote :9976
file bin.debug/fputest
b base.c:88 <================= This breaks on the "Emitting" printf in __gcov_exit
commands 1
silent
set $filename = tmp->info->filename
set $dataBegin = buffer
set $dataEnd = buffer + bytesNeeded
eval "dump binary memory %s 0x%lx 0x%lx", $filename, $dataBegin, $dataEnd
c
end
c
quit
And finally, executed both QEMU and GDB - like this:
$ # In terminal 1:
qemu-system-MYPLATFORM ... -kernel bin.debug/fputest -gdb tcp::9976 -S
$ # In terminal 2:
MYPLATFORM-gdb -x coverage.gdb
...and that's it - I was able to generate the .gcda files in my local filesystem, and then see coverage results over gcov and lcov.
UPDATE: I wrote a blog post showing the process in detail.

CopyFile() on VxWorks

What is simple API for copy file(s) on VxWorks (look like a CopyFile() on Windows API)?
I assume you are talking about working in the command shell, so the commands may look like:
-> ls // lists the current directory contents
Myfile1
Myfile2
YourFile2.txt
value = 0 = 0x0 //return status of the ls command - executed w/o errors*
-> copy "Myfile1","/YourDirectory/Myfile1" // FORMAT: copy "src" , "dest"*
// NB: src & dest argument must be strings*
value = 0 = 0x0 // return status of copy command.
-> cd "/YourDirectory/" // change default directory - notice the trailing slash (/)
value = 0 = 0x0 // return status of cd command
-> ls
xyzfile
Myfile1
value = 0 = 0x0
I hope this helps
HadziJo
Generally, anything that can be executed at the shell can be called from a program other than the shell.
status = copy("Myfile1", "/YourDirectory/Myfile1");
if (status == OK) .....
You might look at the man page for xcopy as well depending on the functionality you need.
You can also use "cp" command on cmd shell (vxWorks 6.x), but that is not API, so probably doesn't answer your question exactly.
The best method I found is xcopy("fromPath", "toPath"). It will recursively (including folders and subfolders) copy (duplicate) everything fromPath toPath.
check out the VxWork Manual: http://www.vxdev.com/docs/vx55man/vxworks/ref/usrFsLib.html#xcopy

get return code from plink?

In a DOS batch script, I'm running a single command on a remote (also windows) computer using plink. Formerly, this command was only run on the local machine, and was relying on the return code to determine success. Is there a way to easily get this information back through plink?
That's not possible with plink. The current consensus is to have the remote script echo its exit code to a log file, then use pscp to transfer the log file to the local machine.
See http://fixunix.com/ssh/74235-errorlevel-capturing-plink.html.
with plink 0.66
C:\Code>echo Y | "C:\Program Files (x86)\PuTTY\plink.exe" bob#myserver exit 42
C:\Code>echo %ERRORLEVEL%
42
Also for #John Wiersba's concern about when a connection cannot be made, this appears to be fixed
C:\CodeMisc>echo Y | "C:\Program Files (x86)\PuTTY\plink.exe" bob#garbageservername exit 42
Unable to open connection:
Host does not exist
C:\Code>echo %ERRORLEVEL%
1
Also note the piping of echo Y ... this enables you to accept the server fingerprint automatically (a little dangerous to say the least ... but our login server is load balanced, so you are always getting different fingerprints :( )
However as #LeonBloy notes, plink still has some connection conditions which return a zero exit code. If you know your exit code range and you don't have a good way of communicating back to windows via a file. You could either +3 to the exit code (if you know the exit code will never == 253-255) or you could apply a bitwise OR (I'd suggest exit $(($?|128)) - in bash).
Or if you don't care about the exact exit code, you could return 2 for success, and zero for failure. Thus a non-two exit code would indicate failure. In bash this would be: echo $((($?==0) << 1)). This would be by far the most robust general purpose solution, but you should make sure your exit code is logged for debug-ability.