Mercurial > pt1.oyama
diff src/pt1_lnbd.c @ 124:9c7bc6c0327e
Add DLNA server function test. (from uShare project)
author | naoyan@johnstown.minaminoshima.org |
---|---|
date | Wed, 29 Sep 2010 23:18:55 +0900 |
parents | recpt1/pt1_lnbd.c@215a51fa3df3 |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/pt1_lnbd.c Wed Sep 29 23:18:55 2010 +0900 @@ -0,0 +1,400 @@ +#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); +}