C program to detect USB drive in Linux - c

I have a embedded device running Linux Angstrom. I need to detect a USB drive. So when a USB drive is inserted, I need to automatically copy data from the USB to internal memory of the embedded device.
To detect the USB, I am using below code:
DIR* dir = opendir("/media/sda1/");
if (dir)
{
printf("USB detected\n");
//rest of the code
//to copy data from the USB
}
This works normally but sometimes after copying is done, I remove the USB but the name of the mount point (sda1) remains there. So after removing the USB, it again try to copy the data (because sda1 is there in media) and then shows error because physical no USB is connected. What is the best way to detect if USB is connected and if connected then after copying how to eject it properly. Here I cannot use udisks because its not available for the linux angstrom I am using for this embedded device. So only generic linux commands will work.
Any help. Thanks

One naive approach is the following:
execute mount | grep /dev/sda1
parse the output: if there is no output, that means that sda1 is not mounted
You may have to adapt the code to your specific platform.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
/* launch a command and gets its output */
FILE *f = popen("mount | grep /dev/sda1", "r");
if (NULL != f)
{
/* test if something has been outputed by
the command */
if (EOF == fgetc(f))
{
puts("/dev/sda1 is NOT mounted");
}
else
{
puts("/dev/sda1 is mounted");
}
/* close the command file */
pclose(f);
}
return 0;
}

Related

get list of removable media in c (on linux)

I was trying to make a program to copy files from the documents folder on my Linux machine into the documents folder onto a USB with Windows on it. So far, it only creates files without copying any actual data to them, but that's not the problem I'm trying to solve right now. The code looks like this (there are no real errors, more information is written under the code):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
int main()
{
DIR *folder;
struct dirent *entry;
int files = 0;
folder = opendir("/home/ubuntumate/Documents");
if(folder == NULL)
{
perror("Unable to read directory");
return(1);
}
while( (entry=readdir(folder)) )
{
if(entry->d_type == DT_REG)
{
files++;
char newfilename[100];
snprintf(newfilename, sizeof(newfilename), "/media/ubuntumate/7494348594344C3C/Users/John/Documents/%s", entry->d_name);
FILE *clone = fopen(newfilename, "w");
fclose(clone);
}
}
closedir(folder);
return(0);
}
You may have noticed that I hard-coded the media's location, including both the username and the media's id. (my username is "ubuntumate" because I'm on a virtual machine running Ubuntu MATE). The question I'm asking is how do i get a list of all the medias attached to the machine, so that this program can still work with a different user, and on a different USB that also contains windows?
You can check whether a block device is removable under the sys hierarchy. E.g. something like
$ stat /dev/sdc|grep Device
Device: 6h/6d Inode: 347 Links: 1 Device type: 8,20
From here you see the device is major number 8, minor 20 (in hex). Then check
$ cat /sys/dev/block/8\:32/removable
0
Never mind, I found an answer. I can just list all the folders in the media/[username] folder. There are a lot of tutorials on getting the username so that one wont be a problem, cuz i can just search it up.

Linux fread() call to USB device freezes when exposed to high CPU utilization

Recently I've written a driver for a drawing tablet called the "Boogie Board RIP" to be able to use it as an input device for linux. It can be connected via usb to a computer. When the provided pen is near or touching the device's screen, it will send data telling where the pen is on the screen.
Basically the driver works great. I can write on it as if it was a wacom tablet.
At unpredictable times, the program will hang on the line below and the cursor on my computer screen will stay in place
fread(packet, sizeof(char), BYTES, f);
Where:
"packet" is an array of 8 bytes
"BYTES" is 8
"f" is a file opened in binary read (rb) mode. In my case it's /dev/usb/hiddev0
The basic program layout is a while loop that reads a byte at a time. Below is a mock-up of the much larger thing:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
char *path = argv[1];
unsigned char packet[8];
FILE *f = fopen(path, "rb");
int i;
while (1) {
fread(packet, sizeof(char), 8, f);
for(i=0;i<8;i++) {
printf("%x", packet[i]);
fflush(stdout);
}
}
}
I started to notice that my driver would "freeze" more often when I was running more things, like watching youtube, playing music... These aren't great examples. Basically I began to suspect it was related to CPU utilization. So I wrote the program below to test it:
#include <stdio.h>
int main() {
while(1) {
printf("a");
fflush(stdout);
fflush(stdout);
fflush(stdout);
fflush(stdout);
fflush(stdout);
fflush(stdout);
fflush(stdout);
}
}
Running this "infinite loop" program in a separate terminal while running the other program above in another terminal will result in harshly more frequent freezes. Basically the program will stop at the fread() line without fail within 2 seconds.
I learned that when the call to fread() doesn't get any data I can still read from the device with another instance of that program or simply printing out the contents of the file via sudo cat /dev/usb/hiddev0. The original process remains stuck while the new program will spit out the data coming from the device.
It seems as though the file simply closes. But that doesn't make sense because then fread would segfault on the next read. Looking for any ideas.
EDIT:
I solved this by using libusb to deal with reading from my device rather than trying to read directly from the device file.

embedded linux C code to perform cp from USB drive to directory on host keeping directory structure in tact

I have an embedded linux kit AM335x (running angstrom 3.2.0, pc is running ubuntu 12.0.4) where I can plug in a USB Flash Drive.
The USB Flash Drive has multiple folders, sub-folders and files.
I would like to create some C code to copy these folders and files from the mass storage device to the file system on my kit.
I would want to do this somewhat in multiple copies so I could check to see if there was still room in the file system I am copying to.
I had found the following (see code below) and was trying to use it. Unfortunately it does not keep keep the directory structure on the USB drive intact when copying over.
For example if I tried the following: Copy(/media/sda1/foo/foo.txt, "/home/Usb_Files");
I see foo.txt at /home/Usb_Files/foo.txt instead of /home/Usb_Files/foo/foo.txt
Also if I try Copy(/media/sda1/foo/foo.txt, "/home/Usb_Files/foo");
It says the cp cannot stat no such file or directory
Any idea on how to do this?
I am really stuck.
int Copy(char *source, char *dest)
{
int childExitStatus;
pid_t pid;
int status;
if (!source || !dest) {
/* handle as you wish */
}
pid = fork();
if (pid == 0) { /* child */
execl("/bin/cp", "/bin/cp", "-R", source, dest, (char *)0);
}
else if (pid < 0) {
/* error - couldn't start process - you decide how to handle */
}
else {
/* parent - wait for child - this has all error handling, you
* could just call wait() as long as you are only expecting to
* have one child process at a time.
*/
pid_t ws = waitpid( pid, &childExitStatus, WNOHANG);
if (ws == -1)
{ /* error - handle as you wish */
}
if( WIFEXITED(childExitStatus)) /* exit code in childExitStatus */
{
status = WEXITSTATUS(childExitStatus); /* zero is normal exit */
/* handle non-zero as you wish */
}
else if (WIFSIGNALED(childExitStatus)) /* killed */
{
}
else if (WIFSTOPPED(childExitStatus)) /* stopped */
{
}
}
}
This happened because your embedded linux filesystem don't have foo directory,so you need to create foo directory before copying.
You need to add logic to check whether directory is present or not before any operation.
When you look at /media/sda1/foo/foo.txt you implicitly know that you would divide it into the two parts /media/sd1a and /foo/foo.txt -- the question is how do you implement this knowledge into your program? For example, is the dividing point always the second slash or is it some other rule?
Once you have this information, you will want do divide it again before the last slash (e.g. giving /foo in this case) -- this will give you the directory structure you need to create in the destination. Take a look at mkdir -p to help with this (e.g. mkdir -p /home/Usb_Files/foo).

Why is my serial communication not working?

I looked in the manual (page 177) for the DE2 and as far as I understand it should be possible to do serial communication for instance via putty and a usb-to-serial cable to the board, so I take the program from the manual:
/* A simple program that recognizes the characters 't' and 'v' */
#include <stdio.h>
#include <string.h>
int main ()
{
char* msg = "Detected the character 't'.\n";
FILE* fp;
char prompt = 0;
fp = fopen ("/dev/uart1", "r+"); //Open file for reading and writing
if (fp)
{
while (prompt != 'v')
{ // Loop until we receive a 'v'.
prompt = getc(fp); // Get a character from the JTAG UART.
if (prompt == 't')
{ // Print a message if character is 't'.
fwrite (msg, strlen (msg), 1, fp);
}
if (ferror(fp))// Check if an error occurred with the file pointer
clearerr(fp); // If so, clear it.
}
fprintf(fp, "Closing the JTAG UART file handle.\n");
fclose (fp);
}
return 0;
}
And I try to run it as Nios2 hardware but then I get this message when I have configured std i/o to use uart
nios2-terminal: can't open uart: No such file or directory
And then when I connect with a terminal program (putty serial connection) it doesn't connect. What am I doing wrong? I tried in the propeties of the projet to change the std i/o to uart but that didn't help. Can you help me?
HOW TO DEBUG SERIAL COMMUNICATION:
Take your 9 pin serial cable and put a jumper pins 2 and 3 together. You can use a paperclip or whatever you have handy. Pins 2 and 3 are TX and RX. If you connect them together, any command you send from the computer will be received by the computer. You have created a serial loopback!
Open Putty, try to connect to your serial cable. Hit any key on your keyboard. Baud rate and things don't matter because it's a loopback.
If you see the character you sent out received on the terminal, your serial cable works! If not, you have a problem with your cable or with putty. I have had issues with putty in the past with serial communication. Try downloading Tera Term if you have a problem with Putty not connecting.
Or find new drivers for your serial cable! Good luck.
In Linux, I would do the following.
fp = fopen ("/dev/ttyS0", "r+"); //Open file for reading and writing
or
look for ttyS1; if ttyS0 is being used.
fp = fopen ("/dev/ttyS1", "r+"); //Open file for reading and writing
Do dmesg to know which exact device are you have attached.
$tail -f /var/log/messages
For USB-serial, it might be
/dev/ttyUSB0; the exact number can be find out using /var/log/messages

Opening a device file using erlang

Is there any way to open a terminal device file in erlang ?
I am on Solaris and I am trying the following::
Erlang (BEAM) emulator version 5.6 [source] [64-bit] [async-threads:0] [kernel-poll:false]
/xlcabpuser1/xlc/abp/arunmu/Dolphin/ebin
Eshell V5.6 (abort with ^G)
1> file:open("/dev/pts/2",[write]).
{error,eisdir}
2> file:open("/dev/null",[write]).
{ok,}
3>
As can be seen above the erlang file driver has no problem in opening a null fle but does not open a terminal device file!!
Unable to come to a conclusion as the file driver is able to open a null file.
Is there any other way to open terminal device files ?
Thanks
Update: I was able to work around the limitation described below using a port. For example, here is a sample program that prints "hello world" to /dev/stdout:
-module(test).
-export([main/1]).
main(X) ->
P = open_port({spawn, "/bin/cat >/dev/stdout"}, [out]),
P ! {self(), {command, "hello world"}}.
This is a bit inconvenient because a port doesn't act like a regular file, but at least it's one way to get the job done.
In efile_openfile() (in erts/emulator/drivers/unix/unix_efile.c) there is the following code:
if (stat(name, &statbuf) >= 0 && !ISREG(statbuf)) {
#if !defined(VXWORKS) && !defined(OSE)
/*
* For UNIX only, here is some ugly code to allow
* /dev/null to be opened as a file.
*
* Assumption: The i-node number for /dev/null cannot be zero.
*/
static ino_t dev_null_ino = 0;
if (dev_null_ino == 0) {
struct stat nullstatbuf;
if (stat("/dev/null", &nullstatbuf) >= 0) {
dev_null_ino = nullstatbuf.st_ino;
}
}
if (!(dev_null_ino && statbuf.st_ino == dev_null_ino)) {
#endif
errno = EISDIR;
return check_error(-1, errInfo);
#if !defined(VXWORKS) && !defined(OSE)
}
#endif
}
This code (confusingly) returns the EISDIR error if the file is not a regular file (which is the ISREG(statbuf) check), unless the file specifically is /dev/null. The file(3) documentation states:
eisdir :
The named file is not a regular file. It may be a directory, a
fifo, or a device.
so it's actually documented to do that. I'm not sure why that restriction exists, though—perhaps it's got something to do with performance because device drivers might block for more time than an ordinary file generally will.

Resources