绕来绕去,回到 pcscdaemon.c
346 else 347 { 348 if (HotPlug) 349 { 350 Log1(PCSC_LOG_CRITICAL, "file " PCSCLITE_RUN_PID " do not exist"); 351 Log1(PCSC_LOG_CRITICAL, "Hotplug failed"); 352 return EXIT_FAILURE; 353 } 354 355 Log1(PCSC_LOG_CRITICAL, 356 "file " PCSCLITE_PUBSHM_FILE " already exists."); 357 Log1(PCSC_LOG_CRITICAL, 358 "Maybe another pcscd is running?"); 359 Log1(PCSC_LOG_CRITICAL, 360 "I can't read process pid from " PCSCLITE_RUN_PID); 361 Log1(PCSC_LOG_CRITICAL, 362 "Remove " PCSCLITE_PUBSHM_FILE " and " PCSCLITE_CSOCK_NAME); 363 Log1(PCSC_LOG_CRITICAL, 364 "if pcscd is not running to clear this message."); 365 return EXIT_FAILURE; 366 } |
346~366 行,如果从 PCSCLITE_RUN_PID 无法正确读取 pid, 则打印一大堆错误。
367 } 368 else 369 if (HotPlug) 370 { 371 Log1(PCSC_LOG_CRITICAL, "Hotplug failed: pcscd is not running"); 372 return EXIT_FAILURE; 373 } |
369~373 行,如果共享内存文件不存在,则命令行有 HotPlug 则错误直接退出。
当然也可以采用不退出,继续创建必要的文件,并启动 pcscd. 但是这里采用了前者的方法。
374 375 /* 376 * If this is set to one the user has asked it not to fork 377 */ 378 if (!setToForeground) 379 { 380 if (SYS_Daemon(0, 0)) 381 Log2(PCSC_LOG_CRITICAL, "SYS_Daemon() failed: %s", 382 strerror(errno)); 383 }
|
374~383 行,如果不是前台运行模式,也就是采用后台运行模式,则采用 daemon 方式启动 pcscd.
384 385 /* 386 * cleanly remove /var/run/pcscd/files when exiting 387 */ 388 (void)signal(SIGQUIT, signal_trap); 389 (void)signal(SIGTERM, signal_trap); 390 (void)signal(SIGINT, signal_trap); 391 (void)signal(SIGHUP, signal_trap); 392 |
384~392 行,系统信号处理。
SIGQUIT 可以从控制终端发 SIGQUIT 给进程, 请求进程 dump core 。
SIGTERM kill 命令引发的信号。
SIGINT 按下 ctrl+c 引发的信号。
SIGHUP 在用户终端连接 ( 正常或非正常 ) 结束时发出,通常是在终端的控制进程结束时,
通知同一 session 内的各个作业,这时它们与控制终端不再关联。
OK. 关于信号的内容很多很多。适可而止。
上面重定向了这 4 个信号。采用统一个处理函数, 整齐划一,泯灭个性。 这个处理函数是 signal_trap.
也在 pcscdaemon.c 中实现。
581 static void signal_trap(/*@unused@*/ int sig) 582 { 583 (void)sig; 584 585 /* the signal handler is called several times for the same Ctrl-C */ 586 if (AraKiri == FALSE) 587 { 588 Log1(PCSC_LOG_INFO, "Preparing for suicide"); 589 AraKiri = TRUE; 590 591 /* if still in the init/loading phase the AraKiri will not be 592 * seen by the main event loop 593 */ 594 if (Init) 595 { 596 Log1(PCSC_LOG_INFO, "Suicide during init"); 597 at_exit(); 598 } 599 } 600 } |
Init 是个特殊标志,代表 pcscd 是否处于初始化阶段。
main 函数的
517 Init = FALSE;
之后,就代表过了初始化阶段。仅仅而已。
这个处理过程,仅仅变动了一个标志 AraKiri. 这个标志的目的,等吧 ... 等以后解释。
不能等,那么就看看 175 页吧。答应了,就一定会说到做到的。
at_exit 也实现在同一个文件中,
535 static void at_exit(void) 536 { 537 Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR); 538 539 clean_temp_files(); 540 541 SYS_Exit(ExitValue); 542 } |
535~542 行,清除上面提到的4组临时文件,进程退出 .
ExitValue 有两个自解释的枚举值:
EXIT_SUCCESS
EXIT_FAILURE
通过上面的分析知道,共享文件不存在的情况下,则需要创建包括共享文件在内的上面
提到的临时文件。包括
PCSCLITE_RUN_PID 文件 (/var/run/pcscd/pcscd.pid)
PCSCLITE_EVENTS_DIR 目录 (/var/run/pcscd/pcscd.events)
下面创建存放 PCSCLITE_RUN_PID 文件的目录
393 /* 394 * If PCSCLITE_IPC_DIR does not exist then create it 395 */ 396 rv = SYS_Stat(PCSCLITE_IPC_DIR, &fStatBuf); 397 if (rv < 0) 398 { 399 int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU; 400 401 rv = SYS_Mkdir(PCSCLITE_IPC_DIR, mode); 402 if (rv != 0) 403 { 404 Log2(PCSC_LOG_CRITICAL, 405 "cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno)); 406 return EXIT_FAILURE; 407 } 408 409 /* set mode so that the directory is world readable and 410 * executable even is umask is restrictive 411 * The directory containes files used by libpcsclite */ 412 (void)SYS_Chmod(PCSCLITE_IPC_DIR, mode); 413 } |
414 415 /* 416 * Record our pid to make it easier 417 * to kill the correct pcscd 418 */ 419 { 420 int f; 421 int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 422 423 if ((f = SYS_OpenFile(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode)) != -1) 424 { 425 char pid[PID_ASCII_SIZE]; 426 427 (void)snprintf(pid, sizeof(pid), "%u/n", (unsigned) getpid()); 428 (void)SYS_WriteFile(f, pid, strlen(pid)); 429 (void)SYS_CloseFile(f); 430 431 /* set mode so that the file is world readable even is umask is 432 * restrictive 433 * The file is used by libpcsclite */ 434 (void)SYS_Chmod(PCSCLITE_RUN_PID, mode); 435 } 436 else 437 Log2(PCSC_LOG_CRITICAL, "cannot create " PCSCLITE_RUN_PID ": %s", 438 strerror(errno)); 439 } |
414~439 行,创建 PCSCLITE_RUN_PID 文件,并往文件中写入当前进程的 pid.
这样其它的进程,包括后续启动的 pcscd 可以方便地得到这个 pcscd 的进程 pid.
440 441 /* 442 * If PCSCLITE_EVENTS does not exist then create it 443 */ 444 rv = SYS_Stat(PCSCLITE_EVENTS_DIR, &fStatBuf); 445 if (rv < 0) 446 { 447 /* 1733 : world writable + sticky bit */ 448 int mode = S_IRWXU | S_IWGRP | S_IXGRP | S_IWOTH | S_IXOTH | S_ISVTX; 449 450 rv = SYS_Mkdir(PCSCLITE_EVENTS_DIR, mode); 451 if (rv != 0) 452 { 453 Log2(PCSC_LOG_CRITICAL, 454 "cannot create " PCSCLITE_EVENTS_DIR ": %s", strerror(errno)); 455 return EXIT_FAILURE; 456 } 457 (void)SYS_Chmod(PCSCLITE_EVENTS_DIR, mode); 458 } |
440~458 行,创建 PCSCLITE_EVENTS_DIR 目录,方便 APPLICATION 和 pcscd 的事件通讯。
459 460 /* cleanly remove /var/run/pcscd/pcsc.* files when exiting */ 461 if (atexit(at_exit)) 462 Log2(PCSC_LOG_CRITICAL, "atexit() failed: %s", strerror(errno)); 463 |
atexit 设置程序正常结束前调用的函数。
当程序通过 exit 或从 main 中返回,参数 function 所指定的函数会先被调用,
然后真正由 exit 结束程序。
也就是说,如果程序正常退出,则调用 at_exit. 很像析构吧。
at_exit 在上面解释了。移除 /var/run/pcscd/ 下, pcsc 开头的 3 个文件和一个目录。
3 个文件是:
/var/run/pcscd/pcscd.pub
/var/run/pcscd/pcscd.comm
/var/run/pcscd/pcscd.pid
1 个目录是:
/var/run/pcscd/pcscd.events
继续,继续。