Mercurial > pt1.oyama
view src/pt1_lnbd.c @ 172:89e24a1c8a64
Fix problem: If boot argument channel had selected by DLNA. Stream will interrupted.
author | Naoya OYAMA <naoya.oyama@gmail.com> |
---|---|
date | Mon, 29 Oct 2012 22:25:59 +0900 |
parents | 9c7bc6c0327e |
children |
line wrap: on
line source
#include <fcntl.h> #include <limits.h> #include <pwd.h> #include <sys/ioctl.h> #include <sys/stat.h> #include <sys/types.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "pt1_ioctl.h" #ifdef O_NOFOLLOW #define OPEN_FLAGS O_NOFOLLOW | O_NONBLOCK #else #define OPEN_FLAGS O_NONBLOCK #endif /* ヘッダに移動すること */ #define C_RET_OK 0 #define C_RET_NG -1 #define MYNAME "pt1_lnb_enabler" #define PID_DIR "/var/run/" #define PIDFILENAME PID_DIR MYNAME ".pid" #define NUMBER "0123456789" #define device "/dev/pt1video0" #define ROOT "root" /* ヘッダに移動すること */ mode_t umask_val = 0133; void fin_action(int); int main() { struct sigaction ign_sigaction; struct sigaction fin_sigaction; FILE *fp; int i; int i_ret; int fd; int pt1_fd; int string_length; int number_length; int i_pid; struct stat orig_st; struct stat open_st; int flags; char file_name[] = PIDFILENAME; char buf[1024] = ""; pid_t mypid; char *p; struct passwd *p_st_passwd; uid_t uid_root; /* 初期処理 */ /* root権限で動作していなければ終了 */ p_st_passwd = getpwnam(ROOT); if (p_st_passwd == NULL) { printf("faile to get pwent. id=[%s].\n", ROOT); exit(C_RET_NG); } uid_root = p_st_passwd->pw_uid; if( uid_root != getuid() ) { /* root 意外の実行権限なのでエラー */ printf("This process must be run by root. uid=[%d].\n", getuid()); exit(C_RET_NG); } /* fork して親は即自殺してターミナルを離す */ mypid = fork(); if( mypid == -1 ) { /* fork エラー */ printf("fork error.\n"); exit(C_RET_NG); } else if ( mypid != 0 ) { /* 親プロセスは即終了(プロンプトに戻す) */ return(C_RET_OK); } umask(umask_val); ign_sigaction.sa_handler = SIG_IGN; fin_sigaction.sa_handler = fin_action; if (sigaction(SIGHUP, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGHUP\n"); exit(C_RET_NG); } if (sigaction(SIGTERM, &fin_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGTERM\n"); exit(C_RET_NG); } if (sigaction(SIGPIPE, &fin_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGPIPE\n"); exit(C_RET_NG); } if (sigaction(SIGINT, &fin_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGINT\n"); exit(C_RET_NG); } if (sigaction(SIGQUIT, &fin_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGQUIT\n"); exit(C_RET_NG); } if (sigaction(SIGILL, &fin_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGILL\n"); exit(C_RET_NG); } if (sigaction(SIGABRT, &fin_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGABRT\n"); exit(C_RET_NG); } if (sigaction(SIGFPE, &fin_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGFPE\n"); exit(C_RET_NG); } if (sigaction(SIGSEGV, &fin_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGSEGV\n"); exit(C_RET_NG); } /* sleep を使うので SIGALRM は放置 * if (sigaction(SIGALRM, &ign_sigaction, NULL) != 0) { * printf("failed to set signal handler. SIGALRM\n"); * exit(C_RET_NG); * } */ if (sigaction(SIGUSR1, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGUSR1\n"); exit(C_RET_NG); } if (sigaction(SIGUSR2, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGUSR2\n"); exit(C_RET_NG); } if (sigaction(SIGCHLD, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGCHLD\n"); exit(C_RET_NG); } if (sigaction(SIGCONT, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGCONT\n"); exit(C_RET_NG); } if (sigaction(SIGTSTP, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGTSTP\n"); exit(C_RET_NG); } if (sigaction(SIGTTIN, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGTTIN\n"); exit(C_RET_NG); } if (sigaction(SIGTTOU, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGTTOU\n"); exit(C_RET_NG); } if (sigaction(SIGPOLL, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGPOLL\n"); exit(C_RET_NG); } if (sigaction(SIGIO, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGIO\n"); exit(C_RET_NG); } if (sigaction(SIGPROF, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGPROF\n"); exit(C_RET_NG); } if (sigaction(SIGSYS, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGSYS\n"); exit(C_RET_NG); } if (sigaction(SIGTRAP, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGTRAP\n"); exit(C_RET_NG); } if (sigaction(SIGURG, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGURG\n"); exit(C_RET_NG); } if (sigaction(SIGVTALRM, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGVTALRM\n"); exit(C_RET_NG); } if (sigaction(SIGXCPU, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGXCPU\n"); exit(C_RET_NG); } if (sigaction(SIGXFSZ, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGXFSZ\n"); exit(C_RET_NG); } /* ないって * if (sigaction(SIGEMT, &ign_sigaction, NULL) != 0) { * printf("failed to set signal handler. SIGEMT\n"); * exit(C_RET_NG); * } */ if (sigaction(SIGSTKFLT, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGSTKFLT\n"); exit(C_RET_NG); } if (sigaction(SIGIO, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGIO\n"); exit(C_RET_NG); } if (sigaction(SIGCLD, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGCLD\n"); exit(C_RET_NG); } if (sigaction(SIGPWR, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGPWR\n"); exit(C_RET_NG); } /* ないって * if (sigaction(SIGINFO, &ign_sigaction, NULL) != 0) { * printf("failed to set signal handler. SIGINFO\n"); * exit(C_RET_NG); * } */ /* ないって * if (sigaction(SIGLOST, &ign_sigaction, NULL) != 0) { * printf("failed to set signal handler. SIGLOST\n"); * exit(C_RET_NG); * } */ if (sigaction(SIGWINCH, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGWINCH\n"); exit(C_RET_NG); } if (sigaction(SIGUNUSED, &ign_sigaction, NULL) != 0) { printf("failed to set signal handler. SIGUNUSED\n"); exit(C_RET_NG); } /* ファイルチェック処理 */ if ((lstat(file_name, &orig_st) != 0) || (!S_ISREG(orig_st.st_mode))) { /* ファイル無しの場合は前回正常終了 */ i_ret = C_RET_OK; } else { /* PIDファイルが存在する場合には、現在の状態を確認する。 * ・二重起動状態(pidファイルのpid値を持つプロセスが存在する) * ・前回pidファイルを消さずに死んでしまった */ i_ret = C_RET_NG; } /* ここに TOCTOU 競合状態の問題があるが、 * /var/run はセキュアなディレクトリなので問題は無い */ if (i_ret != C_RET_OK) { fd = open(file_name, (OPEN_FLAGS | O_RDWR)); if (fd == -1) { /* エラー処理 */ printf("open error. file:[%s].\n", file_name); exit(C_RET_NG); } if (fstat(fd, &open_st) != 0) { /* エラー処理 */ printf("stat error. file:[%s].\n", file_name); exit(C_RET_NG); } if ((orig_st.st_mode != open_st.st_mode) || (orig_st.st_ino != open_st.st_ino) || (orig_st.st_dev != open_st.st_dev)) { /* ファイルはすでにすり替えられている */ printf("file switch has occurred. file:[%s].\n", file_name); close(fd); exit(C_RET_NG); } /* 問題ないファイルであることが確認できたので O_NONBLOCK * を無効にする (省略可能) */ if ((flags = fcntl(fd, F_GETFL)) == -1) { /* エラー処理 */ printf("fcntl error. file:[%s].\n", file_name); close(fd); exit(C_RET_NG); } if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) != 0) { /* エラー処理 */ printf("fcntl error. file:[%s].\n", file_name); close(fd); exit(C_RET_NG); } /* ファイルサイズが0以外である場合にはPID値のチェック */ if(open_st.st_size != 0) { /* ファイルを読みPID値を取得する */ if((fp = fdopen(fd, "w+")) == NULL) { /* fdopen()失敗 */ printf("fdopen error. fd:[%d].\n", fd); close(fd); exit(C_RET_NG); } if ( fgets(buf, sizeof(buf), fp) == NULL ) { /* fgetsエラー */ printf("fgets error. fd:[%d].\n", fd); fclose(fp); exit(C_RET_NG); } buf[sizeof(buf)-1] = '\0'; p = strchr(buf, (int)'\n'); if(p != NULL) { *p = '\0'; } string_length = strlen(buf); number_length = strspn(buf, NUMBER); if ( string_length != number_length ) { /* PIDファイル異常 */ printf("invalid pid file[%s] buf[%s].\n", file_name, buf); fclose(fp); exit(C_RET_NG); } i_pid = atoi(buf); /* PIDファイルのPIDと同じPIDを持つプロセスが存在するか? */ i_ret = kill(i_pid, 0); if ( i_ret == 0 ) { /* 存在する場合には二重起動とみなして処理終了 */ printf("process already exists. pid[%d]\n", i_pid); exit(C_RET_NG); } else { /* 存在しない場合は前回異常終了なのでfpを先頭に戻して処理続行 */ rewind(fp); } } } if ( i_ret == C_RET_OK ) { /* PIDファイルが存在しない場合はPIDファイルの新規作成を行う */ fd = open(file_name, O_CREAT|O_EXCL|O_RDWR, 00644); if ( fd == -1 ){ /* open 失敗 */ printf("file open error. file_name[%s].\n", file_name); exit(C_RET_NG); } if((fp = fdopen(fd, "w+")) == NULL) { /* fdopen()失敗 */ printf("fdopen error. fd:[%d].\n", fd); close(fd); exit(C_RET_NG); } } /* fpのPIDファイルが書き込める状態なので、PIDを書き込む */ mypid = getpid(); snprintf(buf, sizeof(buf), "%d\n", mypid); i_ret = fputs(buf, fp); if(i_ret == EOF) { /* fputs エラー */ printf("fputs error. file_name[%s].\n", file_name); fclose(fp); exit(C_RET_NG); } fclose(fp); /* PID関係処理終了*/ /* fd に pt1 デバイスを open */ pt1_fd = open(device, O_RDONLY); if(pt1_fd == -1) { /* open エラー */ printf("open error. file_name[%s].\n", device); exit(C_RET_NG); } /* fcntl で LNB 電源を有効化する */ if(ioctl(pt1_fd, LNB_ENABLE, 0) < 0) { printf("Power on LNB failed. device:[%s].\n", device); exit(C_RET_NG); } close(pt1_fd); /* 無限待ち(終了は終了するsignalを受けたらとする) */ while(1){ sleep(UINT_MAX); } return C_RET_OK; } /* 終了処理実行関数 */ /* プロセスを終了させるべきsignalを受けたときに動作する */ void fin_action(int sig) { int pt1_fd; char file_name[] = PIDFILENAME; /* fd に pt1 デバイスをopen */ pt1_fd = open(device, O_RDONLY); if(pt1_fd == -1) { /* open エラー */ printf("open error. file_name[%s].\n", device); exit(C_RET_NG); } /* fcntl で LNB 電源断する */ if(ioctl(pt1_fd, LNB_DISABLE, 0) < 0) { printf("Power on LNB failed. device:[%s].\n", device); close(pt1_fd); exit(C_RET_NG); } /* fd close */ close(pt1_fd); /* pidファイルを削除する */ if ( unlink(file_name) != 0 ) { /* pid file unlink エラー */ printf("unlink error. file_name[%s].\n", device); exit(C_RET_NG); } /* おしまい */ exit(C_RET_OK); }