C++ find mounting path of USB flash device (linux) - c++

(sorry for bad English, I'm German)
I'm trying to write a program on linux that writes data on any inserted USB flash device that is inserted.
But this:
file = fopen("/run/media/abc/xyz/logFile.txt", "w");
will fail if the username is not abc, or the name of the device is not xyz or linux does not want my program to work.
I found a program that outputs this:
sysfs /sys
proc /proc
devtmpfs /dev
securityfs /sys/kernel/security
tmpfs /dev/shm
devpts /dev/pts
tmpfs /run
tmpfs /sys/fs/cgroup
cgroup /sys/fs/cgroup/systemd
pstore /sys/fs/pstore
cgroup /sys/fs/cgroup/freezer
cgroup /sys/fs/cgroup/cpu,cpuacct
cgroup /sys/fs/cgroup/perf_event
cgroup /sys/fs/cgroup/memory
cgroup /sys/fs/cgroup/pids
cgroup /sys/fs/cgroup/net_cls,net_prio
cgroup /sys/fs/cgroup/blkio
cgroup /sys/fs/cgroup/devices
cgroup /sys/fs/cgroup/cpuset
cgroup /sys/fs/cgroup/hugetlb
configfs /sys/kernel/config
/dev/mapper/fedora_msi--linux-root /
selinuxfs /sys/fs/selinux
systemd-1 /proc/sys/fs/binfmt_misc
debugfs /sys/kernel/debug
hugetlbfs /dev/hugepages
tmpfs /tmp
mqueue /dev/mqueue
binfmt_misc /proc/sys/fs/binfmt_misc
nfsd /proc/fs/nfsd
/dev/sda1 /boot
/dev/mapper/fedora_msi--linux-home /home
sunrpc /var/lib/nfs/rpc_pipefs
tmpfs /run/user/1000
gvfsd-fuse /run/user/1000/gvfs
fusectl /sys/fs/fuse/connections
/dev/sdc1 /run/media/username/usbname
But using this looks like bad style to me and I don't know how to differ between "/dev/sdc1 /run/media/username/usbname" (the right one) and "/dev/sda1 /boot" (the false one).
Note: The Program is does not have to run on non-Linux operating systems.
Note: I do not want to write directly into /dev/sdc1
I would be thankful if anyone knows how to find the correct mounting points, or if anyone gives me a link to (official) documentation.

In Linux generally, you need to mount the attached device into a directory on your filesystem for reading and writing from that.
In your case, as I can see your distro (Ubuntu perhaps?) has already mounted the device into /run/media/username/usbname, which has been done automatically for end-user. So, your code may works on this distro and does not work on others(or even in Ubuntu server) which requires the mounting progress should be done manually.
I can suggest you research tutorial like this to understand how to work with usb flash drive on Linux first. How to mount the devices manually using command line.
Then make yourself a directory, name it whatever you want. Automatically mount devices to that directory when it is plugged (a bit of Bash scripting, perhaps)
Finally, you can do whatever you want on your directory using C++ without worrying the name changing.
UPDATE
How can I know if the device has been plugged?
Everytime you plug the usb in, dmesg will write logs for the event. Here is the example from my Ubuntu Desktop when I plug my 32GB Kingston USB.
....
[ 39.647394] scsi 4:0:0:0: Direct-Access Kingston DataTraveler 3.0 PMAP PQ: 0 ANSI: 6
[ 39.647950] sd 4:0:0:0: Attached scsi generic sg1 type 0
[ 41.108262] sd 4:0:0:0: [sdb] 60632064 512-byte logical blocks: (31.0 GB/28.9 GiB)
[ 41.108722] sd 4:0:0:0: [sdb] Write Protect is off
[ 41.108726] sd 4:0:0:0: [sdb] Mode Sense: 23 00 00 00
[ 41.109185] sd 4:0:0:0: [sdb] No Caching mode page found
[ 41.109190] sd 4:0:0:0: [sdb] Assuming drive cache: write through
[ 41.114913] sdb: sdb1
[ 41.120164] sd 4:0:0:0: [sdb] Attached SCSI removable disk
And then the mount command (without root privilege) can give you the mount point in your filesystem. Eg:
/dev/sdb1 on /media/nuc/MULTIBOOT type fuseblk (rw,nosuid,nodev,allow_other,default_permissions,blksize=4096)
Alternative, you can also read /proc/mounts to get the same report.
How can I automatically get all this information to my code?
It's your job. In C/C++, you can trigger the commands to the Shell, get the output string, analyzing it using key-words. The output report from Linux is pretty universal, which mean you expect it will be the same from time to time.

In linux you don't have (in general, it depends on the distribution you use) a fixed path to mount usb devices. Even you don't have them to be mounted automatically (this is something configured in your distribution, but not a general issue). So there's no general standard way to detect that some usb device has been plugged and mounted.
The procedure for mounting automatically usb devices comes from udevd(8) that is, the daemon in charge of detecting the kernel events about plugged devices into the several buses linux can have attached, receives a message telling some special device has been attached and installs the proper device driver to cope with it (normally, for a usb pendrive, this is a chain of device drivers, terminating in a script that creates the device inodes in /dev/... and mounts them if applicable). If you read that daemon documentation, you'll see how to install a shell script that will be executed as soon as you detect a new plugged device and it's ready to be mounted.
What is expected this shell script to do. Well, if you want to be conservative, you'll not overwrite each device plugged, if you don't detect something else, that allows you to identify the plugged device. This can be a special labeled partition or something like this, that allows you to recognise the device you want to overwrite or no. It can be something so simple as a magic name in the root directory of that device.
In order to be pragmatic and give you a solution that works without having to read long manual pages, something that should work is to scan periodically the mount table (you get it from /proc/mounts or reading the output of the mount(8) command) and detecting which entries have changed since the last time you executed them. If some entry has been added, just check (entries from mount(8) command have the format mount_device\tmount_directory\tmount_options\t... and you have to keep the mount_directory to check if some special named file is in there, and then proceed to copy there all the information you want.
To periodically check the mount table, you have to include in your crontab(7) file something like:
* * * * check_mounts.sh
and this shell script will be executed each minute to do this kind of work.
Something that can be also useful is to write a timestamp of when it was the last time you wrote information to the plugged device, so you can get information of what has changed since you last wrote to it (this can be the contents of that special file you use to check if this mount point is suitable to write the information you want to store there)

Related

How to map a usb device with a known bus address to the mounted path?

I have an application which is using libusb for detecting connected usb devices. This library gives me the VID/PID and bus as well as port number of the connected devices. I however need (after recognizing the device by PID/VID) to talk to the device via boost::asio::io_service, for this i need the device path in the /dev directory. The device usually gets mounted as something like /dev/ttyUSBx. How do I match the bus and port number to the path? A cross platform solution which works on linux and macOS would be preferable. If there is no cross platform solution, are there ways for both OS?
Thanks a lot!
The not so straight forward but feasible way is to use sysfs like this:
Find the USB device you are looking for by browsing /sys/class/tty/ttyUSBx
cd into the directory of the device of your choice.
Execute realpath .
This will show you something like this: /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/ttyUSB0/tty/ttyUSB0
cd to /sys/devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0 and cat uevent.
This will contain the USB VID/PID under PRODUCT=xxxxxxxx
There is obviously some work required to automate it with C++ but it is doable.

How to programmatically discover the filesystem without mounting the device (like "fdisk -l")

I need to find a system call in linux to discover the filesystem of a connected pendrive in my application. I found out that the 'fdisk -l' do the job however I need now to discover how this happens. I wasn't capable to discover reading the fdisk code, the only certain think is that:
The structs statfs or statvfs are not used;
The fdisk doesn't need to mount the device to find the filesystem;
Obs: My application is written in C++ and is running in a embedded linux system.
The command fdisk -l displays the file system represented by the System ID byte. This byte is in the Partition Table which is inside the Master Boot Record (MBR). The MBR is usually stored on the first cylinder on the first hard drive (although any hard drive can have an MBR).
I would think you could simply use the open and read system calls to read the MBR from the disk assuming the user running your program has permission:
char buf[446];
int fd = open("/dev/hda", O_RDONLY);
read(fd, buf, 446);
Look over the MBR Format and then read out the partition table to get the System ID bytes. Here's a list of types for the System ID byte.
I am only aware of how fdisk on Linux works, and last time I checked it didn't support GPT or any other partitioning formats. So this answer is relevant only to the classical MBR format.
You can use libblkid from util-linux to do this. The source distribution includes a sample which lists the partitions on a specified device, including filesystem type.

How to get information on the drive where the executable is located in c++

My app will be running from a USB key which have specific information like vendor-id, device-id, ... which I need.
I tried using libusb, but despite the fact that I still can't make it work properly, how could I find the right usb drive to get information from?
Note that I would like the code to be cross-platform, that's why I firstly choose libusb.
Edit :
I have found a program (usbviewer) that enumerates all usb ports and the specific informations on the drive when it's connected.
I have read the sources for linux, infos are directly extracted from /proc/bus/usb/devices, it's quite straightforward.
But on windows, to get usb node connection information, it takes about 1000 lines before you get the actual information in a data structure (enumerate hub controllers, root hubs, ports...).
libusb on the otherside force me to generate an INF file and install a driver via inf-wizard.exe for each device before I can reach the information (didn't try on linux though).
Edit 2 :
I have found a way to get the device serial number with Windows, Linux and Mac OS X (didn't try MAC OS X but it should work just as Linux). For Windows, I use the function GetVolumeInformation(), on Linux, to read the serial number of drives with a FAT filesystem, I read 4 bytes in the corresponding /dev/* file starting from 0x27 or 0x43 depending on the FAT version.
But this reading requieres a root access which the program won't have, and it seems to me a little bit unreliable.
Any ideas ?
I have found the solution that fits me, for thoses who are insterested.
For Windows :
I extract the serial number of the device from the registry knowing the drive letter : HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices\DosDevices\X:
For Unix :
I get the /dev file with the df command, then I read the link in /sys/block corresponding to the /dev file (e.g : The drive is /dev/sdb, I read link of /sys/block/sdb. Then I read the file serial which is located in the directory pointed by the link, 6x directory backwards.
Hope it helps.

linux -- getting from /proc/partitions contents to something I can 'ls'

I am writing (yet another) file manager (to learn stuff:) and have a silly/stupid block.
On Linux, to enumerate the storage devices which can contain files, I believe the best approach is to parse the contents of the /proc/partitions file and extract the /dev/sda* entries. (right?) However, how can I map the /dev/sda* to something that I can explore programmatically to get directory contents? I am planning on using boost/filesystem, but since I cannot ls /dev/sda I assume I cannot use boost to iterate over it.
Synopsis: how can I convert /dev/sda* to something that I can 'ls'
I think you're mis-understanding exactly what /dev/sd* actually are to a program. They are devices not directories. You use the mount command to tell the operating system to "interpret" the device as a filesystem, and to attach it somewhere (root, or otherwise). It's this step that makes it into "a directory" somewhere on your filesystem. So other than raw I/O commands (which you don't want to do), get the filesystem mounted, and THEN try and explore it.
It's kind of like opening a file really. When you do this, the operating system gives your program a stream of bytes that you can randomly access the file through. But on the disk, that file could actually be scattered all over the hard drive (or whatever device). But the OS is "making" it into a "nice" format for you to deal with transparently. The same is true of the disk itself when accessing directory/file listings.
I hope my example made it clearer as to why what you're trying to do isn't as simple as you think it is.
Off the cuff, I'd say that the output of mount with no arguments might be a faster choice. That should show you the mounted filesystems and devices while /proc would show you all the devices and partitions.
the device /dev/sda* is a block device and needs to be mounted. To be able to ls it you need to have something that can interpret the file system type. First step: identify the file system type, in raw code there is usually a header code in the partition table in the first segment of the harddrive which would just be /dev/sda On a Linux system it would be something like ext3
Next you need to either write or use a library for interfacing with that filesystem, if you get the Kernel source code for Linux it has a LOT of API code for interfacing with common filesystems, and wrappers for standard POSIX calls which is exactly what you're looking for. Things like ls and cwd use system calls to retrieve information about a mounted filesystem, the disk is a block (or sometimes a character) device and you need the ability to talk to it and speak the same language.

How do I programmatically create a bootable CD?

I'm using a barebones tutorial as the basis for an OS I'm working on, and it seems to be an older tutorial: it has be compiling the kernel down to a floppy image, and then loading it with GRUB.
Basically, I still want to use GRUB, but I'd like to have my OS run from a CD instead. The main reason is that I don't actually have a real floppy drive available (I'm testing in VirtualBox currently) and I thus have no way to test my OS on real hardware.
I've been poking around on the net, and I can find lots of utilities that create a bootable CD from a floppy image, but these all seem to require an actual floppy drive, plus it's not really what I'm looking for. I'd like to be able to end up with a bootable CD during my make step ideally, without needing to first place the image on a floppy, which seems rather pointless.
I guess the easy way to answer this: How do I set up GRUB to read my kernel image from a CD? Will I need a special utility to do this from Windows? (The kernel can't compile itself yet, that's not for a looong while)
Thanks!
I found the solution for my project on my own, with some advice from the folks over at OSdev. There is a utility called mkisofs (which can run under Windows using a cygwin dll) that takes a directory, and makes that directory into an ISO image that can be burned to a CD. Using the -b flag, you can specify which file should reside in the boot sector of the disk.
The solution is just to have GRUB in the bootsector, and use GRUB to load the kernel image, which I can compile out in non-floppy form easily.
AFAIK a bootable CD is pretty much the same as a bootable floppy. You need to put the boot loader (GRUB) into the boot sector etc., the BIOS will take care of the low level stuff until you switch to protected mode.
You will probably have to make your image and then dd it to the actual physical disk.
Here's the El Torito Bootable CD specification:
http://www.phoenix.com/NR/rdonlyres/98D3219C-9CC9-4DF5-B496-A286D893E36A/0/specscdrom.pdf
EDIT: An alternative way to test your kernel would be a bootable USB stick. Again, the BIOS will take care of the low level USB stuff until you turn on A20 and jump to protected mode.
If you're interested in looking at code, then the Moblin Image Creator is probably a good application to check out. It's written in python and can create different types of bootable images (CD, USB and NAND) for both Live and installable configurations of Moblin Linux.