changeset 123:215a51fa3df3

add lnb daemon.
author Naoya OYAMA <naoya.oyama@gmail.com>
date Sun, 25 Jul 2010 16:40:42 +0900
parents 4009737ea899
children 9c7bc6c0327e
files recpt1/pt1_lnbd.c
diffstat 1 files changed, 400 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/recpt1/pt1_lnbd.c	Sun Jul 25 16:40:42 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);
+}