opendir for usb device /dev/sdb - linux

I am trying to implement in c program a way to detect if usb is connected or not.
I noticed that when the usb is connected, then the following command from shell will result as following:
root:~# ls /dev/sdb
/dev/sdb
If usb is disconnected then I get
root:~# ls /dev/sdb
ls: /dev/sdb: No such file or directory
I therefore assumed that best way to detect usb connected from c program shall be by doing opendir("/dev/sdb"), but the open call is always failed.
Do you have any idea what's best methd to do this detection ?
The main goal, is knowing in run-time program where the udev mounted the harddisk, and where the usb flash drive (if plugged in).
Thanks,
Ran

A) Why your opendir call failed? It's easy to understand. Because /dev/sdb is not a directory. For me it's hard to understand what you expect, when you try to open device as a directory. If you want to get file list from you usb drive, you need to mount the partition (/dev/sdb1, /dev/sdb2, etc. not the /dev/sdb) to some mount point (directory). And if you mount it successfully, then you can open the directory with your call. Many linux distributions mount usb drive automatically. You can look to your distribution documentation to get the information about automatical mounting of the usb drives.
B) I think it's easy to understand why detecting the usb device this way is bad idea.
=> Different computers have different amount of drives. So on many computers
/dev/sdb - is a hard drive.
=> Asuming you know that there is only one hard drive, the disk naming still can change after computer reboot, so it's possible that after reboot the usb drive will become sda and hard drive will become sdb (but usually this doesn't happen).
=> Generally, it's not possible to predict a new letter (sdb or sdc or sde).
=> You can't access to the usb devices, that are not usb drives.
=> There are tonns of other problems with such solution.
C) I didn't understand your goal completely, but if you want your program to be make some action if the usb device is plugged in, that the best solution you can do is read about udev and the event system of your distribution. If you want to make with your usb device some low level operations, you can read about libusb. You can get the general information about usb devices with lsusb command which is usually a part of a distributions. You can google for some other infermer commands.

The device /dev/sdb is not a directory, it's just a device, so you should use a system call like stat that will tell you whether a file exists instead of trying to calling opendir on it.
Please note that /dev/sdb could be any kind of hard drive depending on the setup of your specific system; it is not necessarily a USB drive.
Alternatively, you could execute the lsusb utility and parse its output.

Related

Does Linux have mount limit for device/hardware?

I noticed for general USB storage device, as long as I have enough USB end points. The Kernel will recognize the device.
Another example is I noticed when I mount two cdc-acm devices(USB modem) on a board, the Kernel only recognized one of them.
And when I configured the Kernel, there's no option for the number of the device I can mount, but only the option to turn it on/off.

C++ Detecting USB serial device plugged/unplugged

I need to detect when a USB serial device is plugged or unplugged on my embedded system and know what is the tty associated with it.
My system runs over a 2.6 Linux Kernel.
Since I don't have write access to udev rules, nowadays I'm trying to get this information from the file system, looking for modifications in /sys/bus/usb/devices directory. However, I'm facing some problems with this approach.
I know what is the Id BUS of the USB port connected (e.g 1-1.3). So, I search for the associated tty (looking for a directory in /sys/bus/usb/devices/<Id BUS>:1.0/tty/ - e.g. /sys/bus/usb/devices/1-1.3:1.0/tty/ttyACM0). This way I know that I should use /dev/ttyACM0 to communicate with my device.
But, sometimes, this device (/dev/ttyACM0) does not exist.
Is there any better way to get this information?
I even thought trying to get this information from the syslog, but I don't know whether this is a pretty good idea.
Edit:
Only to clarify, my system needs to be able to detect state changes in the USB bus, i.e. detecting when a new device is plugged (and getting the tty name linked to it) or an existing one is unplugged.
The system is monitoring up to N USB/serial devices, which are plugged to it using an USB HUB. During its normal execution new devices can be plugged, existing devices can be removed (or rebooted by a remote command - out of this scope). When a device is rebooted, it could receive a different tty from the previous one used before (e.g. ttyACM0 -> ttyACM3), since the kernel designates to it a tty which is free at the moment, and it is a big problem to me.
Netlink is the preferred mechanism for communication between kernel and userspace.
You would create a Netlink socket with family NETLINK_KOBJECT_UEVENT, listen on that socket and filter out messages that contain SUBSYSTEM=usb and ACTION=add for USB plug events or ACTION=remove for USB unplug events.
I wrote a USB abstraction library called libusbp. You should look at its port_name example, which shows how to use libusbp to get the serial port name (e.g. /dev/ttyACM0) for a USB serial device. Behind the scenes, libusbp gets this information using libudev.
Check if the virtual file is deleted using stat.
#include <sys/statvfs.h>
...
struct stat sb;
return (stat("/dev/ttyUSB0", &sb) == 0); // true if open, false otherwise

Mounting a read only drive as write

I have a special bespoke device with a USB interface. When plugging in the device to my laptop - Ubuntu 12.04 it mounts as a read only USB drive - with a file on it. This file is created by the device and writes to the file when the device scans stuff.
I however, want to be able to write to the drive so the device 'thinks' it has already scanned x amount of entries.
Basically I want to replace the file 'File1.txt' my version of 'File1.txt' however I cannot because the drive is mounting as Read only.
I have tried the following commands:
andy#andy-ThinkPad-W530:/media/iRead$ touch giveme.txt
touch: cannot touch `giveme.txt': Read-only file system
andy#andy-ThinkPad-W530:/media/iRead$ sudo mount -o remount,rw '/media/iRead'
[sudo] password for andy:
mount: cannot remount block device /dev/sdb read-write, is write-protected
andy#andy-ThinkPad-W530:/media/iRead$
Can anybody suggest anything I can try to mount this as writable drive?
I have a very strong feeling that the chip which is storing this data is the following:
ARM STM32F103 RBT6 22oUP _ 93 MLT22950
Hope this helps somebody to help me!
If processing write commands coming from USB wasn't part of the requirements, it's very unlikely that the device processes write commands.
A read-only USB mass storage device is not a read-write mass storage device with write-protection slapped on top. It's a USB device that doesn't have logic for understanding write requests at all.
After the device is finished and delivered is a little late for deciding
I want to be able to write to the drive so the device 'thinks' it has already scanned x amount of entries.
Of course the flash memory used inside the device is written during its operation. But the way data is stored inside might not look anything like its USB presentation, and the conversion is most likely one-way only.
Since the developer probably did not implement mass storage support from scratch, and the library they used probably has write support, they may be able to easily supply you with firmware modified to be writable and do something with the written data. But without changing the firmware, you get nowhere.

How to intercept data sent to a USB flash drive in the Linux kernel?

Where in the Linux kernel source code can I find the function(s) that deal with sending data to a USB flash drive? By "data", I mean the actual file contents. For example, when I drag and drop "Report.docx" to the USB thumb drive, I need to be able to intercept this data to the point where I could modify the contents of the file before it is written to the USB thumb drive.
I understand that the USB storage module (drivers/usb/storage) is where USB mass storage devices like thumb drives are handled, but I failed to find the right place to look. I looked around transfer.c but my debugging attempts just show the functions get called whether or not I'm transferring any files. Also, from my understanding, everything is done with URBs and I'm not clear on how to deal with those. Am I looking in the right place?
For the purposes of my project, I need to modify the driver (not using any third-party libraries or user-space code). I am working with Linux 3.12.0.
Not an expert in usb subsystem, but I would start by looking at
drivers/usb/storage/transport.c::usb_stor_bulk_transfer_buf()

How can I prevent all USB mass storages from mounting?

I want to prevent every kind of USB mass storage from mounting using udev rules.
Already I can detect all of USB mass storage devices connected to my system using the following rule:
SUBSYSTEMS=="scsi", SUBSYSTEM=="block" KERNEL=="sd[b-h]1"
But how can I prevent them from mounting?
I know I have to set the authorized file of its relevant USB device to zero! But how can I find the USB device path? The $DEVPATH gives me the path of storage device block for example sdb1!
I have an application which should give permission to some of USB mass storage devices. So the used method for blocking the USB mass storage devices should not be very static!
The following rule prevents all except the first partition from being auto-mounted:
# Rule: Only mount first partition found on /dev/sd* (USB) devices.
ACTION=="add|change", SUBSYSTEM=="block", KERNEL=="sd*[2-9]", ENV{UDISKS_PRESENTATION_NOPOLICY}="1"
Reason: In USB disks with multiple partitions, I only want to automount the first one. I manually mount the others, if I want them.
You should be able to substitute the partition matcher with KERNEL=="sd*", to get:
# Rule: Do not automount any partitions found on /dev/sd* (USB) devices.
ACTION=="add|change", SUBSYSTEM=="block", KERNEL=="sd*", ENV{UDISKS_PRESENTATION_NOPOLICY}="1"
This prevents auto-mounting, which you can then manually manage.
I have only tested this on Ubuntu 10.10
The easiest way to do this is to blacklist the usb-storage kernel module. This will only work if it has been compiled as a module however, rather than directly into the kernel. You can check with modprobe -n usb-storage.ko, or by looking for it in /lib/modules/$(uname -r)/kernel/drivers/usb/storage/
If it's compiled as a module, you can black list it by adding an entry to /etc/modprobe.d/blacklist(.conf) For Debian, see this guide

Resources