如何在Ubuntu中通过C++从/dev/xxx路径获取USB摄像头的VID、PID及序列号
Got it, let's walk through how to read the Vendor ID (VID), Product ID (PID), and serial number of a USB camera (like your udev-mapped /dev/camera_one) in C++, then implement validation logic. This relies on Linux's sysfs filesystem, which exposes all hardware device details in a human-readable, file-based structure.
When you have a device node (like /dev/camera_one), Linux links it to corresponding metadata in /sys/class/video4linux/. We'll follow these symbolic links to reach the USB device's dedicated sysfs directory, then read the idVendor, idProduct, and serial files to extract the info we need for validation.
Here's a complete C++ example with robust error handling and comments to explain each step:
#include <iostream> #include <fstream> #include <string> #include <unistd.h> #include <limits.h> #include <algorithm> using namespace std; // Helper: Read the raw value from a sysfs text file string readSysfsValue(const string& filePath) { ifstream file(filePath); if (!file.is_open()) { cerr << "Error: Couldn't open file " << filePath << endl; return ""; } string value; getline(file, value); file.close(); // Trim trailing newlines/whitespace value.erase(find_if(value.rbegin(), value.rend(), [](int ch) { return !isspace(ch); }).base(), value.end()); return value; } // Helper: Resolve a symbolic link to its target path string resolveSymlink(const string& linkPath) { char resolvedBuffer[PATH_MAX]; ssize_t linkLength = readlink(linkPath.c_str(), resolvedBuffer, sizeof(resolvedBuffer) - 1); if (linkLength == -1) { cerr << "Error: Couldn't resolve symlink " << linkPath << endl; return ""; } resolvedBuffer[linkLength] = '\0'; return string(resolvedBuffer); } // Extract VID, PID, and serial from a udev-mapped camera device bool getCameraUsbDetails(const string& deviceNode, string& outVid, string& outPid, string& outSerial) { // Step 1: Get the sysfs path for the video device string deviceName = deviceNode.substr(deviceNode.find_last_of('/') + 1); string videoSysLink = "/sys/class/video4linux/" + deviceName + "/device"; // Resolve the link to the actual USB device directory string usbDevicePath = resolveSymlink(videoSysLink); if (usbDevicePath.empty()) { cerr << "Error: Couldn't find USB device path for " << deviceNode << endl; return false; } // Step 2: Read VID and PID outVid = readSysfsValue(usbDevicePath + "/idVendor"); outPid = readSysfsValue(usbDevicePath + "/idProduct"); if (outVid.empty() || outPid.empty()) { cerr << "Error: Failed to read VID/PID for device " << deviceNode << endl; return false; } // Step 3: Read serial number (note: not all cameras provide this) outSerial = readSysfsValue(usbDevicePath + "/serial"); if (outSerial.empty()) { cout << "Warning: No serial number found for this camera (some devices don't provide one)" << endl; } return true; } // Example validation logic: Check if the camera matches allowed specs bool validateCamera(const string& vid, const string& pid, const string& serial) { // Replace these with your allowed device values const string allowedVid = "046d"; // Logitech's VID const string allowedPid = "0825"; // Logitech C920's PID const string allowedSerial = "ABC123XYZ"; // Example serial number // First validate VID/PID (required check) if (vid != allowedVid || pid != allowedPid) { return false; } // Validate serial only if the device provides one (adjust based on your needs) if (!serial.empty() && serial != allowedSerial) { return false; } return true; } int main() { string targetDevice = "/dev/camera_one"; string vid, pid, serial; if (getCameraUsbDetails(targetDevice, vid, pid, serial)) { cout << "Camera USB Information:" << endl; cout << "VID: 0x" << vid << endl; cout << "PID: 0x" << pid << endl; if (!serial.empty()) { cout << "Serial Number: " << serial << endl; } if (validateCamera(vid, pid, serial)) { cout << "\n✅ Camera validation passed!" << endl; } else { cout << "\n❌ Camera validation failed!" << endl; } } else { cerr << "Failed to retrieve camera details." << endl; return 1; } return 0; }
- Sysfs Path Reliability: The example assumes your udev-mapped device name exists in
/sys/class/video4linux/(udev maintains these links by default). If this fails, you can runudevadm info -q path -n /dev/camera_onein the terminal to get the exact sysfs path, then adjust thevideoSysLinkvariable accordingly. - Serial Number Edge Case: Not all USB cameras expose a serial number. Adjust the
validateCamerafunction to either skip serial checks for such devices or mark them as invalid, depending on your security requirements. - Permissions: You'll need to run the compiled binary with sudo (or adjust device permissions via udev) to access sysfs files and device nodes.
- Compilation: Build with g++ using:
g++ camera_validator.cpp -o camera_validator
内容的提问来源于stack exchange,提问作者Rich

