udev example -- detect usb and write test file
摘自:https://www.cnblogs.com/jlmgary/p/6742630.html
之前学习了下Udev,就随便做了个测试小程序.....设计什么的也没考虑,就实现了一个基本功能,插入U盘,识别,循环检测到有特定文件后,就然后往U盘里面写数据,插拔多次,都能正常工作。
里面的warning和不规范的写法请自己修改。
1 #include <unistd.h> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <stddef.h> 5 #include <string.h> 6 #include <errno.h> 7 #include <getopt.h> 8 #include <fcntl.h> 9 #include <errno.h> 10 #include <signal.h> 11 #include <getopt.h> 12 #include <sys/time.h> 13 #include <sys/socket.h> 14 #include <sys/un.h> 15 #include <sys/select.h> 16 #include <linux/types.h> 17 #include <linux/netlink.h> 18 #include <sys/types.h> 19 #include <libudev.h> 20 #include <iostream> 21 #include <pthread.h> 22 #include <sys/mount.h> 23 #include <sys/stat.h> 24 #include <dirent.h> 25 #include <time.h> 26 using namespace std; 27 static std::string record_path=""; 28 29 static bool FindRecord=false; 30 void File_Opreation(); 31 void GetUsbFolderLocation(char *basePath); 32 void MountTheSystem(char *basePath); 33 static bool NeedToCheck=false; 34 int ListDevice() 35 { 36 udev *udev; 37 struct udev_enumerate *enumerate; 38 struct udev_list_entry *devices, *dev_list_entry; 39 struct udev_device *dev; 40 41 /* Create the udev object */ 42 udev = udev_new(); 43 if (!udev) 44 { 45 printf("Can't create udev\n"); 46 exit(1); 47 } 48 49 /* Create a list of the devices in the 'hidraw' subsystem. */ 50 enumerate = udev_enumerate_new(udev); 51 udev_enumerate_add_match_subsystem(enumerate, "block"); 52 udev_enumerate_scan_devices(enumerate); 53 devices = udev_enumerate_get_list_entry(enumerate); 54 /* For each item enumerated, print out its information. 55 udev_list_entry_foreach is a macro which expands to 56 a loop. The loop will be executed for each member in 57 devices, setting dev_list_entry to a list entry 58 which contains the device's path in /sys. */ 59 udev_list_entry_foreach(dev_list_entry, devices) 60 { 61 const char *path; 62 63 /* Get the filename of the /sys entry for the device 64 and create a udev_device object (dev) representing it */ 65 path = udev_list_entry_get_name(dev_list_entry); 66 dev = udev_device_new_from_syspath(udev, path); 67 68 /* usb_device_get_devnode() returns the path to the device node 69 itself in /dev. */ 70 printf("Device Node Path: %s\n", udev_device_get_devnode(dev)); 71 72 /* The device pointed to by dev contains information about 73 the hidraw device. In order to get information about the 74 USB device, get the parent device with the 75 subsystem/devtype pair of "usb"/"usb_device". This will 76 be several levels up the tree, but the function will find 77 it.*/ 78 dev = udev_device_get_parent_with_subsystem_devtype( 79 dev, 80 "usb", 81 "usb_device"); 82 if (!dev) 83 { 84 cout<<"Unable to find parent usb device"<<endl; 85 exit(1); 86 } 87 88 /* From here, we can call get_sysattr_value() for each file 89 in the device's /sys entry. The strings passed into these 90 functions (idProduct, idVendor, serial, etc.) correspond 91 directly to the files in the directory which represents 92 the USB device. Note that USB strings are Unicode, UCS2 93 encoded, but the strings returned from 94 udev_device_get_sysattr_value() are UTF-8 encoded. */ 95 printf(" VID/PID: %s %s\n", 96 udev_device_get_sysattr_value(dev,"idVendor"), 97 udev_device_get_sysattr_value(dev, "idProduct")); 98 printf(" %s\n %s\n", 99 udev_device_get_sysattr_value(dev,"manufacturer"), 100 udev_device_get_sysattr_value(dev,"product")); 101 printf(" serial: %s\n", 102 udev_device_get_sysattr_value(dev, "serial")); 103 udev_device_unref(dev); 104 } 105 /* Free the enumerator object */ 106 udev_enumerate_unref(enumerate); 107 108 udev_unref(udev); 109 110 return 0; 111 } 112 113 void Udev_Enumrate() 114 { 115 struct udev* udev_ancestor=NULL; 116 struct udev_enumerate* udev_enum=NULL; 117 struct udev_list_entry* device_fistentry=NULL; 118 struct udev_list_entry *dev_list_entry=NULL; //entry to store the current position 119 struct udev_device *dev=NULL; 120 udev_ancestor=udev_new(); 121 udev_enum=udev_enumerate_new(udev_ancestor); 122 if(udev_enumerate_add_match_subsystem (udev_enum, "block")==0) 123 { 124 cout<<"add block device to match subsystem successful"<<endl; 125 } 126 127 if(udev_enumerate_add_match_subsystem (udev_enum, "usb")==0) 128 { 129 cout<<"add usb device to match subsystem successful"<<endl; 130 } 131 132 if(udev_enumerate_add_match_subsystem (udev_enum, "scsi")==0) 133 { 134 cout<<"add scsi device to match subsystem successful"<<endl; 135 } 136 137 //Scan the system under /sys/ 138 udev_enumerate_scan_devices(udev_enum); 139 140 //get the first entry of the device list 141 device_fistentry=udev_enumerate_get_list_entry(udev_enum); 142 143 /* For each item enumerated, print out its information. 144 udev_list_entry_foreach is a macro which expands to 145 a loop. The loop will be executed for each member in 146 devices, setting dev_list_entry to a list entry 147 which contains the device's path in /sys. */ 148 udev_list_entry_foreach(dev_list_entry, device_fistentry) 149 { 150 const char *path; 151 152 /* Get the filename of the /sys entry for the device 153 and create a udev_device object (dev) representing it */ 154 path = udev_list_entry_get_name(dev_list_entry); 155 dev = udev_device_new_from_syspath(udev_ancestor, path); 156 157 /* usb_device_get_devnode() returns the path to the device node 158 itself in /dev. */ 159 printf("Test Device Node Path: %s\n", udev_device_get_devnode(dev)); 160 161 162 /* The device pointed to by dev contains information about 163 the hidraw device. In order to get information about the 164 USB device, get the parent device with the 165 subsystem/devtype pair of "usb"/"usb_device". This will 166 be several levels up the tree, but the function will find 167 it.*/ 168 dev = udev_device_get_parent_with_subsystem_devtype( 169 dev, 170 "usb", 171 "usb_device"); 172 if (!dev) 173 { 174 cout<<"Test Unable to find parent usb device"<<endl; 175 //exit(1); 176 } 177 else 178 { 179 printf(" VID/PID: %s %s\n",udev_device_get_sysattr_value(dev,"idVendor"), udev_device_get_sysattr_value(dev, "idProduct")); 180 printf(" %s\n %s\n",udev_device_get_sysattr_value(dev,"manufacturer"), udev_device_get_sysattr_value(dev,"product")); 181 printf(" serial: %s\n",udev_device_get_sysattr_value(dev, "serial")); 182 } 183 184 udev_device_unref(dev); 185 } 186 udev_enumerate_unref(udev_enum); 187 udev_unref(udev_ancestor); 188 189 } 190 191 void* udev_Monitor(void*) 192 { 193 struct udev* udev=NULL; 194 struct udev_monitor * mon=NULL; 195 struct udev_device *dev; 196 int fd; 197 fd_set fds; 198 struct timeval tv; 199 static int flag=0; 200 201 udev=udev_new(); 202 mon=udev_monitor_new_from_netlink(udev,"udev"); 203 204 udev_monitor_filter_add_match_subsystem_devtype(mon, "sound", "usb_device"); 205 udev_monitor_filter_add_match_subsystem_devtype(mon, "usb", "usb_device"); 206 udev_monitor_filter_add_match_subsystem_devtype(mon, "block", "disk"); 207 udev_monitor_filter_add_match_subsystem_devtype(mon, "block", "partition"); 208 udev_monitor_filter_add_match_subsystem_devtype(mon, "usb", "usb_interface"); 209 udev_monitor_enable_receiving(mon); 210 fd = udev_monitor_get_fd(mon); 211 while(1) 212 { 213 214 fd_set fds; 215 struct timeval tv; 216 int ret; 217 218 FD_ZERO(&fds); 219 FD_SET(fd, &fds); 220 tv.tv_sec = 0; 221 tv.tv_usec = 0; 222 223 ret = select(fd+1, &fds, NULL, NULL, &tv); 224 //ret means there's an event fd_isset means fd is readable 225 if(ret>0 & FD_ISSET(fd,&fds)) 226 { 227 //cout<<"There's a change with Num="<<flag<<endl; 228 //flag++; 229 /* Make the call to receive the device. 230 select() ensured that this will not block. */ 231 dev = udev_monitor_receive_device(mon); 232 if (dev) 233 { 234 const char* sysPath = udev_device_get_syspath(dev); 235 const char* action = udev_device_get_action(dev); 236 const char* subsystem = udev_device_get_subsystem(dev); 237 const char* devType = udev_device_get_devtype(dev); 238 if (0 == strncmp(action, "add", strlen("add"))) 239 { 240 241 const char* devClass = udev_device_get_sysattr_value(dev, "bDeviceClass"); 242 const char* devInterfaceClass = udev_device_get_sysattr_value(dev, "bInterfaceClass"); 243 244 cout<<"The devClass: "<<devClass<<endl; 245 cout<<"The devInterfaceClass:"<<devInterfaceClass<<endl; 246 247 NeedToCheck=true; 248 249 } 250 printf("Got Device\n"); 251 printf(" Node: %s\n", udev_device_get_devnode(dev)); 252 printf(" Subsystem: %s\n", udev_device_get_subsystem(dev)); 253 printf(" Devtype: %s\n", udev_device_get_devtype(dev)); 254 printf(" Action: %s\n",udev_device_get_action(dev)); 255 printf(" Path: %s\n",udev_device_get_syspath(dev)); 256 257 udev_device_unref(dev); 258 } 259 else 260 { 261 printf("No Device from receive_device(). An error occured.\n"); 262 } 263 } 264 } 265 } 266 267 268 269 int LoopileList(char *basePath) 270 { 271 DIR *dir; 272 struct dirent *ptr; 273 char base[1000]; 274 275 if ((dir=opendir(basePath)) == NULL) 276 { 277 perror("Open dir error..."); 278 exit(1); 279 } 280 281 while ((ptr=readdir(dir)) != NULL) 282 { 283 if(strcmp(ptr->d_name,".")==0 || strcmp(ptr->d_name,"..")==0) ///current dir OR parrent dir 284 { 285 continue; 286 } 287 else if(ptr->d_type == 8) ///file 288 { 289 printf("d_name:%s/%s\n",basePath,ptr->d_name); 290 } 291 else if(ptr->d_type == 10) ///link file 292 { 293 printf("d_name:%s/%s\n",basePath,ptr->d_name); 294 } 295 else if(ptr->d_type == 4) ///dir 296 { 297 memset(base,'\0',sizeof(base)); 298 strcpy(base,basePath); 299 strcat(base,"/"); 300 strcat(base,ptr->d_name); 301 LoopileList(base); 302 } 303 } 304 closedir(dir); 305 return 1; 306 } 307 308 static bool stopLoopflag=false; 309 void GetUsbFolderLocation(char *basePath) 310 { 311 bool ret=false; 312 DIR *dir; 313 struct dirent *ptr; 314 char base[1000]; 315 MountTheSystem(basePath); 316 //cout<<"Loop check file "<<basePath<<endl; 317 if ((dir=opendir(basePath)) == NULL) 318 { 319 //perror("Open dir error..."); 320 //exit(1); 321 } 322 else 323 { 324 while ((ptr=readdir(dir)) != NULL && !stopLoopflag) 325 { 326 327 if(strcmp(ptr->d_name,".")==0 || strcmp(ptr->d_name,"..")==0) ///current dir OR parrent dir 328 { 329 continue; 330 } 331 else if(ptr->d_type == 8) ///file 332 { 333 if(strcmp(ptr->d_name,"Record_HFC")==0) 334 { 335 record_path=basePath; 336 printf("File :%s/%s\n",basePath,ptr->d_name); 337 strcat(basePath,"/"); 338 record_path=basePath; 339 cout<<"Record Path is="<<record_path<<endl; 340 FindRecord=true; 341 stopLoopflag=true; 342 break; 343 } 344 345 } 346 else if(ptr->d_type == 10) ///link file 347 { 348 printf("Link:%s/%s\n",basePath,ptr->d_name); 349 } 350 else if(ptr->d_type == 4) ///dir 351 { 352 memset(base,'\0',sizeof(base)); 353 strcpy(base,basePath); 354 strcat(base,"/"); 355 strcat(base,ptr->d_name); 356 GetUsbFolderLocation(base); 357 } 358 } 359 if(dir!=NULL) 360 { 361 closedir(dir); 362 } 363 } 364 365 } 366 367 string GetLocalTime() 368 { 369 //string str="/usr/bin/sgm/Conn/tmp/out_"; 370 string str=""; 371 time_t rawtime; 372 struct tm* timeinfo; 373 char timE[25]; 374 time(&rawtime); 375 timeinfo=localtime(&rawtime); 376 strftime(timE,sizeof(timE),"%Y_%m_%d_%I_%M_%S",timeinfo); 377 printf("%s",timE); 378 379 str=str+timE; 380 return str; 381 } 382 void MountTheSystem(char *basePath) 383 { 384 //cout<<"mount"<<record_path<<endl; 385 //mount(NULL, record_path.c_str(), NULL, MS_REMOUNT, "-o, rw"); 386 //cout<<"mount"<<record_path<<endl; 387 mount(NULL, basePath, NULL, MS_REMOUNT, "-o, rw"); 388 } 389 void WriteFileToUSB() 390 { 391 record_path=record_path+"test.txt"; 392 FILE* fusb_Ubuntu=NULL; 393 fusb_Ubuntu=fopen(record_path.c_str(),"w+"); 394 cout<<"path is="<<record_path<<endl; 395 if(fusb_Ubuntu==NULL) 396 { 397 cout<<"cant't write"<<endl; 398 } 399 else 400 { 401 cout<<"start write"<<endl; 402 std::string str_Ubuntu="This is test"; 403 str_Ubuntu=str_Ubuntu+GetLocalTime(); 404 char* arr_Ubuntu=new char[str_Ubuntu.length()+1]; 405 for(int i=0;i<str_Ubuntu.length();i++) 406 { 407 arr_Ubuntu[i]=str_Ubuntu[i]; 408 409 } 410 cout<<str_Ubuntu<<endl; 411 fwrite(arr_Ubuntu,str_Ubuntu.length(),sizeof(char),fusb_Ubuntu); 412 fclose(fusb_Ubuntu); 413 record_path=""; 414 NeedToCheck=false; 415 stopLoopflag=false; 416 delete []arr_Ubuntu; 417 arr_Ubuntu=NULL; 418 } 419 420 421 422 423 } 424 void File_Opreation() 425 { 426 cout<<"start to do file operation"<<endl; 427 } 428 429 void* writeFile(void*) 430 { 431 while(1) 432 { 433 if(NeedToCheck) 434 { 435 char* path="/media"; 436 GetUsbFolderLocation(path); 437 438 if(FindRecord) 439 { 440 WriteFileToUSB(); 441 } 442 } 443 else 444 { 445 cout<<"sleep for 5s"<<endl; 446 usleep(5000*1000); 447 } 448 } 449 450 } 451 //int main(int argc, char *argv[]) 452 int main() 453 { 454 #if 0 455 char* path="/media"; 456 GetUsbFolderLocation(path); 457 458 if(FindRecord) 459 { 460 File_Opreation(); 461 } 462 #endif 463 pthread_t monitor_thread=0; 464 pthread_t write_thread=0; 465 466 int err=0; 467 err=pthread_create(&monitor_thread, NULL,udev_Monitor, NULL); 468 if(err!=0) 469 { 470 cout<<"create thread error"<<endl; 471 } 472 else 473 { 474 cout<<"create thread monitor success "<<endl; 475 } 476 477 478 479 480 err=pthread_create(&write_thread, NULL,writeFile, NULL); 481 if(err!=0) 482 { 483 cout<<"create thread error"<<endl; 484 } 485 else 486 { 487 cout<<"create thread writeFile success "<<endl; 488 } 489 490 491 if(monitor_thread!=0) 492 { 493 pthread_join(monitor_thread,NULL); 494 } 495 if(write_thread!=0) 496 { 497 pthread_join(write_thread,NULL); 498 } 499 500 501 return 0; 502 }
Linux 下运行,如果要在ARM下运行就编一个arm版本的。
Makefile
# specify the compiler CC=/usr/bin/g++ # specify library INCFLAGS=-I ./ # specify library LIBFLAGS=-l pthread -l udev # specify additional compile flags FLAGS= -lm -g -Wall -Wextra # List of files specific SRC:= Udev_Monitor.cpp testapp: ${CC} -o Udev_Monitor ${SRC} ${LIBFLAGS} ${INCFLAGS} ${FLAGS} clean: rm -f Udev_Monitor
只是基本的识别插拔U盘,检测特定的文件,检测到后往U盘里面写数据,可以用来帮助cp或者记录log文件。
虽然我的blog也没人会看,但是还是希望能帮到和我一样的菜鸟。