ttyusb udev naming by hardware port - linux

I Have two usb->serial adapters, both ftdi, lets name them ftdiA, and ftdiB.
The device (in this case raspberry pi but it is kind of irrelevant) has 2 USB ports, let's name them 'top' and 'bottom'.
Is there a way to create udev rule so, that no matter which adapter is used in top port it gets name for example /dev/ttyUSBTop
I would like to name them based on the port where they were plugged in.
Even if there is a ftdiC adapter plugged in top port its name should be /dev/ttyUSBTop
Is it possible for xxxxA device that is not ftdi, but moschip, pl2013, or some other manufacturer that also creates /dev/ttyUSBX device, to get the same name based on connection -> /dev/ttuUSBTop or /dev/ttyUSBBottom?
I cant find similar request, all point to opposite requirement, they all want /dev/ttyUSBftdiA no matter where it is plugged in.

There is already a rules file (60-persistent-serial.rules) that creates pretty paths in /dev/serial/by-path/ that match the port. For example, when my USB serial device got inserted in a USB 3.0 port:
$ ls -l serial/by-path/
total 0
lrwxrwxrwx 1 root root 13 Apr 2 22:20 pci-0000:02:00.0-usb-0:1:1.0-port0 -> ../../ttyUSB0
And when the same device is connected to a different USB 2.0 port:
$ ls -l /dev/serial/by-path/
total 0
lrwxrwxrwx 1 root root 13 Apr 2 22:20 pci-0000:00:1d.0-usb-0:1.2:1.0-port0 -> ../../ttyUSB0

Related

How to troubleshoot an expected CDROM device on custom Linux kernel?

I'm looking for some hints while troubleshooting missing CDROM device.
The problem is, missing configuration option for my custom kernel (linux-5.4.78).
My current .config has:
CONFIG_CDROM=y
CONFIG_BLK_DEV_SR=y
CONFIG_VHOST_SCSI=y
CONFIG_BLK_SCSI_REQUEST=y
CONFIG_SCSI_MOD=y
CONFIG_SCSI=y
CONFIG_SCSI_DMA=y
CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
CONFIG_SCSI_SPI_ATTRS=y
CONFIG_SCSI_FC_ATTRS=y
CONFIG_SCSI_ISCSI_ATTRS=y
CONFIG_SCSI_SAS_ATTRS=y
CONFIG_SCSI_SAS_LIBSAS=y
CONFIG_SCSI_SAS_HOST_SMP=y
CONFIG_SCSI_LOWLEVEL=y
CONFIG_ISCSI_TCP=y
CONFIG_ISCSI_BOOT_SYSFS=y
CONFIG_SCSI_CXGB3_ISCSI=y
CONFIG_SCSI_CXGB4_ISCSI=y
CONFIG_SCSI_BNX2_ISCSI=y
CONFIG_BE2ISCSI=y
CONFIG_SCSI_HPSA=y
CONFIG_SCSI_3W_9XXX=y
CONFIG_SCSI_3W_SAS=y
CONFIG_SCSI_ACARD=y
CONFIG_SCSI_AACRAID=y
CONFIG_SCSI_AIC7XXX=y
CONFIG_SCSI_AIC79XX=y
CONFIG_SCSI_AIC94XX=y
CONFIG_SCSI_HISI_SAS=y
CONFIG_SCSI_HISI_SAS_PCI=y
CONFIG_SCSI_MVSAS=y
CONFIG_SCSI_MVSAS_TASKLET=y
CONFIG_SCSI_MVUMI=y
CONFIG_SCSI_DPT_I2O=y
CONFIG_SCSI_ADVANSYS=y
CONFIG_SCSI_ARCMSR=y
CONFIG_SCSI_ESAS2R=y
CONFIG_SCSI_MPT3SAS=y
CONFIG_SCSI_MPT2SAS=y
CONFIG_SCSI_SMARTPQI=y
CONFIG_SCSI_UFSHCD=y
CONFIG_SCSI_UFSHCD_PCI=y
CONFIG_SCSI_UFSHCD_PLATFORM=y
CONFIG_SCSI_UFS_CDNS_PLATFORM=y
CONFIG_SCSI_UFS_HISI=y
CONFIG_SCSI_UFS_BSG=y
CONFIG_SCSI_HPTIOP=y
CONFIG_SCSI_BUSLOGIC=y
CONFIG_SCSI_FLASHPOINT=y
CONFIG_SCSI_MYRB=y
CONFIG_SCSI_MYRS=y
CONFIG_VMWARE_PVSCSI=y
CONFIG_SCSI_SNIC=y
CONFIG_SCSI_DMX3191D=y
CONFIG_SCSI_FDOMAIN=y
CONFIG_SCSI_FDOMAIN_PCI=y
CONFIG_SCSI_GDTH=y
CONFIG_SCSI_ISCI=y
CONFIG_SCSI_IPS=y
CONFIG_SCSI_INITIO=y
CONFIG_SCSI_INIA100=y
CONFIG_SCSI_PPA=y
CONFIG_SCSI_IMM=y
CONFIG_SCSI_STEX=y
CONFIG_SCSI_SYM53C8XX_2=y
CONFIG_SCSI_SYM53C8XX_MMIO=y
CONFIG_SCSI_IPR=y
CONFIG_SCSI_IPR_TRACE=y
CONFIG_SCSI_IPR_DUMP=y
CONFIG_SCSI_QLOGIC_1280=y
CONFIG_SCSI_QLA_FC=y
CONFIG_SCSI_QLA_ISCSI=y
CONFIG_SCSI_LPFC=y
CONFIG_SCSI_DC395x=y
CONFIG_SCSI_AM53C974=y
CONFIG_SCSI_WD719X=y
CONFIG_SCSI_PMCRAID=y
CONFIG_SCSI_PM8001=y
CONFIG_SCSI_BFA_FC=y
CONFIG_SCSI_VIRTIO=y
CONFIG_SCSI_CHELSIO_FCOE=y
CONFIG_SCSI_LOWLEVEL_PCMCIA=y
CONFIG_SCSI_DH=y
CONFIG_SCSI_DH_RDAC=y
CONFIG_SCSI_DH_HP_SW=y
CONFIG_SCSI_DH_EMC=y
CONFIG_SCSI_DH_ALUA=y
CONFIG_ISCSI_TARGET=y
CONFIG_ISCSI_TARGET_CXGB4=y
CONFIG_QED_ISCSI=y
I'm expecting to see /dev/sr0. It's not there. dmesg is mute about sr0.
However, I'm able to see it using stock kernel and I've identified it was bring by BLK_DEV_SR on my target:
# ls -l /dev/sr0
brw-rw---- 1 root optical 11,0 Apr 21 15:02 /dev/sr0
# readlink /sys/dev/block/11\:0/device/driver
../../../../../../../../../../../../bus/scsi/driver/sr
I'd appreciate any help.
If your custom linux has udev, try udevadm monitor.
When you eject or insert a cd, you should see a change event on the terminal with the device path.
Also it's normally standard for a cdrom drive, no matter the actual device path, to be forwarded to /media/cdrom

Udev rule for input device

I have a camera device that has an input device listed under /dev/input. I would like to add that input device to the group plugdev.
When I plug in the camera:
[ 704.406837] input: See3CAM_CU51 as /devices/pci0000:00/0000:00:14.0/usb4/4-2/4-2:1.0/input/input21
[ 705.157657] hid-generic 0003:2560:C152.0007: hiddev0,hidraw4: USB HID v1.11 Device [e-con Systems See3CAM_CU51] on usb-0000:00:1
It's now symlinked under /dev/input/by-id
0 lrwxrwxrwx 1 root root 10 Aug 31 10:50 usb-e-con_Systems_See3CAM_CU51_172A0202-event-if00 -> ../event20
However, event20 has the following permissions:
0 crw-rw---- 1 root input 13, 84 Aug 31 10:50 event20
I've written udev rules for the hiddevice itself with success, but for some reason, I can't get the rule right for the input device. Here's what I've tried:
KERNEL=="input", ATTR{name}=="See3CAM_CU51", MODE="0666" GROUP="plugdev"
But it does not appear to work. There's not a huge deal of examples of changing the ownership of input devices out there (that I've found at least).
Update:
When I change my udev rule to
KERNEL=="input", MODE="0666" GROUP="plugdev"
that is, I leave out the device name, all my input devices in /dev/input have the correct permissions.
So basically, I'm saying "every input device gets set to mode 0666, and belong to the plugdev group", which works. But adding the ATTR{name}== breaks it.
Here's the output of udevadm info:
udevadm info -a -p /devices/pci0000:00/0000:00:14.0/usb4/4-2/4-2:1.0/input/input21
looking at device '/devices/pci0000:00/0000:00:14.0/usb4/4-2/4-2:1.0/input/input21':
KERNEL=="input21"
SUBSYSTEM=="input"
DRIVER==""
ATTR{name}=="See3CAM_CU51"
ATTR{phys}=="usb-0000:00:14.0-2/button"
ATTR{properties}=="0"
ATTR{uniq}==""
It should be working, I have the correct name set for the device, what stupid mistake am I making?
udev rules support string matching, you're probably looking for:
ACTION=="...", KERNEL=="input[0-9]*", SUBSYSTEM=="input", ...
to match on the specific action for any inputN devices, then you can add your ATTR filter(s) to select the specific device.

Disconnect and reconnect ttyUSB0 programmatically in Linux

Trying to solve this problem (ttyUSB0 that works properly than stop working after about 1hr)I'm thinking on if disconnecting and reconnecting the usb device could be a good fix.
So, it is possibile to cut down power to the USB device and repower it programmatically (bash)?
# lsusb -t
1-1:1.0: No such file or directory
/: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=musb-hdrc/1p, 480M
|__ Port 1: Dev 2, If 0, Class=vend., Driver=, 12M
|__ Port 1: Dev 2, If 1, Class=vend., Driver=cp210x, 12M
On am335x, kernel 3.2.0, ubuntu core armhf.
[ 1.784332] usb 1-1: cp210x converter now attached to ttyUSB0
At the moment I need a complete power cycle to have ttyUSB0 back.
This is the solution:
Find the identity of your usb device.
# tree /sys/bus/usb/drivers/cp210x/
/sys/bus/usb/drivers/cp210x/
|-- 1-1:1.1 -> ../../../../devices/platform/omap/musb-ti81xx/musb-hdrc.1/usb1/1-1/1-1:1.1
|-- bind
|-- module -> ../../../../module/cp210x
|-- remove_id
|-- uevent
-- unbind
So 1-1:1.1 is the identifier of my ttyUSB0(it can be discovered also via dmesg).
Then, disconnect the device (as root):
# echo -n "1-1:1.1" > /sys/bus/usb/drivers/cp210x/unbind
reconnect it
# echo -n "1-1:1.1" > /sys/bus/usb/drivers/cp210x/bind
At this point I had the same device but with a different name, it was now ttyUSB1 instead of ttyUSB0.
- To avoid this I added a new rule in /etc/udev/rules.d/ by creating a new file named 99-usb-serial.rules with this line:
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea70", ATTRS{serial}=="002DCFAF", SYMLINK+="sameName", MODE:="0666"
where idVendor, idProduct and serial must be the values of your device. This rule will create a new device called sameName linked to the ttyUSB* device normally generated from the OS.
As #Robert Harvey Said,
You first need to find our driver that will help you 'unplug and plug' the usb. Type: ls /sys/bus/usb/drivers which should print something like this: btusb ftdi_sio hub usb usbfs usbhid usbserial_generic uvcvideo. These, are all the drivers for each usb device. Now, lets say mine is ftdi_sio, which is a device i use to program my arduino (atmega328p chip). I am not sure how Your/other usb devices name themselves there. Like, i dont know which of these is my mouse.
Now, you can see the driver's commands using:
ls /sys/bus/usb/drivers/ftdi_sio/, which will print something like: 1-4:1.0 bind module uevent unbind, Where 1-4:1.0 is the device's characteristic code, and the bind and unbind command, which are the 'plug' and 'unplug' command respectively.
Now, if i want to unplug programatically the ftdi usb port, i will type:
echo -n "1-4:1.0" > /sys/bus/usb/drivers/ftdi_sio/unbind
and, to plug it again:
echo -n "1-4:1.0" > /sys/bus/usb/drivers/ftdi_sio/bind
Now, we can combine all the commands together, with a ';':
echo -n "1-4:1.0" > /sys/bus/usb/drivers/ftdi_sio/unbind ; echo -n "1-4:1.0" > /sys/bus/usb/drivers/ftdi_sio/bind

Some high level questions about how PAM is designed

I'm creating a PAM module for a project. The PAM module will be using a library that will be re-used by some command line utilities (rather than re-writing everything each time). In this library, I want to have it interpret policy that discriminate against and/or logs according to subnet memberships of the remote host. Near as I can tell this value is probably coming from the authenticating application, but I don't know. Since the shared object won't have access to the pamh structure from libpam I can't just do a pam_get_item (like I would be able to from the PAM module itself) so I've had to resort to other means.
The best solution I've come up with is to have the shared object look for a connected TTY, if it's there go to utmp and find the login process associated with that TTY, extract the IP address from there. If there isn't a TTY, assume it's an initial login of a network user. The library then iterates over the sockets (which I've defined as basically any symlink with the word "socket" in the target's filename when you do a ls -l /proc/<pid>/fd) and uses the socket inode number to cross reference with /proc/net/tcp and extracts the remote IP address associated with that inode number. If it doesn't find an inode there then it assumes it's Unix domain or tcp6 (IPv6 support in this is forthcoming and not terribly important for the near future). If it still isn't able to find it, assume that some daemon has called an application linking against it and interpret it as such (might do something eventually, if it's worthwhile, but for now it's just a big NOOP if the first two don't return anything.
It seems to work but I have some high level questions about how PAM is supposed to work:
Is there some official standard that governs PAM operation? For example, is it covered by a POSIX standard somewhere? I know there are multiple PAM implementations (four or five that I've found thusfar) but I don't know if existing commonalities are de jure or de facto or just how I happen to have my system configured.
After I did a ls -l /proc/<pid>/fd > /lsOutput from the module itself (via system()):
[root#hypervisor pam]# cat /lsOutput total 0
lrwx------. 1 root root 64 Jun 15 15:09 0 -> /dev/null
lrwx------. 1 root root 64 Jun 15 15:09 1 -> /dev/null
lrwx------. 1 root root 64 Jun 15 15:09 2 -> /dev/null
lr-x------. 1 root root 64 Jun 15 15:09 3 -> socket:[426180]
[root#hypervisor pam]#
And issuing a manual ls after the user logins in:
[root#hypervisor pam]# ls -l /proc/18261/fd
total 0
lrwx------. 1 root root 64 Jun 15 15:15 0 -> /dev/null
lrwx------. 1 root root 64 Jun 15 15:15 1 -> /dev/null
lrwx------. 1 root root 64 Jun 15 15:15 11 -> /dev/ptmx
lrwx------. 1 root root 64 Jun 15 15:15 12 -> /dev/ptmx
lrwx------. 1 root root 64 Jun 15 15:15 13 -> socket:[426780]
lrwx------. 1 root root 64 Jun 15 15:15 14 -> socket:[426829]
lrwx------. 1 root root 64 Jun 15 15:15 2 -> /dev/null
lrwx------. 1 root root 64 Jun 15 15:15 3 -> socket:[426180]
lrwx------. 1 root root 64 Jun 15 15:15 4 -> socket:[426322]
lr-x------. 1 root root 64 Jun 15 15:15 5 -> pipe:[426336]
l-wx------. 1 root root 64 Jun 15 15:15 6 -> pipe:[426336]
lrwx------. 1 root root 64 Jun 15 15:15 7 -> socket:[426348]
lrwx------. 1 root root 64 Jun 15 15:15 8 -> socket:[426349]
lrwx------. 1 root root 64 Jun 15 15:15 9 -> /dev/ptmx
[root#hypervisor pam]#
So basically, it seems like both the TTY and any additional sockets get opened only AFTER the session modules finish (my temporary test module's session handling is the last in the stack for the sshd service). I've been unable to get it to be otherwise (or even think of a time when the connecting client won't be a TCP socket at descriptor 3).
Is this just due to my lack of imagination or is it necessarily so? I'm leaning towards the latter as it would seem that communicating with the client would be a pre-requisite to doing pretty much anything else that's useful. I don't know that for sure, so I feel I should ask somebody. Will descriptor 3 always be the authenticating client (my .so only makes the assumption that it's the lowest numbered TCP socket, and only if there's no TTY, but it seems like 3 should always be the descriptor for the connecting client). Would pulling the first TCP descriptor be a "deterministic" way of establishing the remote client's identity? Or is there no prescribed way this is supposed to play out and that's just how either my system is configured or how SSH has chosen to interface with PAM?
Is it sshd that's setting the rhost value or is that coming from some place else? I've tried grep-ing over the source code for both SSH and libpam, but no dice. I can see where libpam handles the setting of the host value when something call pam_set_item, but not were pam_set_item actually gets called to set it to be this or that particular host.
Any amount of help would be appreciated, I've googled but I'm starting to get splinters on my fingertips from scraping the bottom of the barrel.
Main reason I'm interested in knowing this is so that I'll end up not only with the "right" answer but mostly so that I won't have any surprises later on down the road. We have some Solaris platforms we may do this on, but my main motivation is to have assumptions that are grounded in things that are actually going to be constant.
I also realize that I could have the client programs/modules feed the host information to the library, but that would likely involve code re-write two or three times (as the CLI tools prepare session information from utmp and the PAM module from pam_get_item) and potentially make the project look more complex than it really needs to be.
Answering some of your questions:
"Is there some official standard that governs PAM operation?"
Apparently, yes. Wikipedia's entry on Pluggable_Authentication_Modulesays "PAM was standardized as part of the X/Open UNIX standardization process, resulting in the X/Open Single Sign-on (XSSO) standard." I have never found this particularly relevant to my dealings with it.
"Is this just due to my lack of imagination or is it necessarily so?"
<magicEightBall>"Concentrate and ask again"</magicEightBall> (It's ambiguous which "this" is being referred to - perhaps you can clarify?
"Will descriptor 3 always be the authenticating client?"
This is a behaviour of the application, rather than PAM.
Would pulling the first TCP descriptor be a "deterministic" way of establishing the remote client's identity?
Also a behaviour of the application.
"Is it sshd that's setting the rhost value or is that coming from some place else?"
It is sshd that sets the rhost value. In openssh's file auth-pam.c, function sshpam_init(), you'll find:
sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST, pam_rhost);
Some general notes:
rather than keying off the TTY - which, as you've discovered get set later - you can walk the process lineage via getppid() and /proc.
don't trust system() in PAM modules - it uses a user's environment, and may not be the one you expect. Use fork()/execlp() instead.

Device node at /dev/tty* not getting created for uart serial driver

I have written a simple UART serial driver in embedded Linux running busybox with mdev rules. I have provided .dev_name as "ttyC2C" in my driver code.
static struct uart_driver serial_omap_reg = {
.owner = THIS_MODULE,
.driver_name = "Omap-C2C-Serial",
.dev_name = "ttyC2C",
.nr = OMAP_MAX_HSUART_PORTS,
.cons = NULL,
};
However the node is getting created in
./sys/devices/platform/omap_c2c_uart.0/tty/ttyC2C0
./sys/class/tty/ttyC2C0
/ # ls -l ./sys/class/tty/ttyC2C0
lrwxrwxrwx 1 root 0 0 Jan 1 00:14 ./sys/class/tty/ttyC2C0 -> ../../devices/platform/omap_c2c_uart.0/tty/ttyC2C0
/ # ls -l ./sys/devices/platform/omap_c2c_uart.0/tty/ttyC2C0
-r--r--r-- 1 root 0 4096 Jan 1 00:14 dev
lrwxrwxrwx 1 root 0 0 Jan 1 00:14 device -> ../../../omap_c2c_uart.0
drwxr-xr-x 2 root 0 0 Jan 1 00:14 power
lrwxrwxrwx 1 root 0 0 Jan 1 00:14 subsystem -> ../../../../../class/tty
-rw-r--r-- 1 root 0 4096 Jan 1 00:14 uevent
/ #
The mdev rules for tty are:
tty 0:5 0666
tty.* 0:0 0620
How to get device node as /dev/ttyC2C ?
You are confusing two things. The sysfs nodes you are seeing are indeed maintained by the kernel based on the kobject hierarchy. However device nodes are entirely a user space problem and can exist anywhere (although by convention are under /dev).
So by hand you would first find the major:minor numbers:
cat /sys/class/tty/ttyC2C0/dev
And then:
mknod /dev/ttyC2C0 c ${MAJOR} ${MINOR}
However as you have already indicated you are using the fork of udev, mdev to handle the user space creation of device nodes. However the matching rules look odd to me. I assume mdev has the equivalent of udevadm which should help you write the matching rules. For example my USB tty driver can be queried like this:
udevadm info -a -p /sys/class/tty/ttyUSB0
And looking at the tree produced I can see a list of udev attributes which I could use to match. So in my case:
KERNEL=="ttyUSB0", DRIVERS=="ftdi_sio", NAME="ttyUSB0"
Would be enough to match (although my distro has a lot more complex matching rules to deal with dynamic setups).
I'm guessing but I suspect the mapping rule you want would look more like:
KERNEL=="ttyC2C", NAME="ttyC2C"
Although you might need a bit more to ensure you get device nodes created for each port (minor number?).
Does adding a specific mdev rule to your /etc/mdev.conf for ttyC2C resolve your problem ?
Something like one of the following ?
ttyC2C[0-9]+ root:tty 620
or
ttyC2C[0-9]+ root:tty 620 #/bin/ln -sf $MDEV ttyC2C

Resources