comparison recpt1/pt1_lnbd.c @ 123:215a51fa3df3

add lnb daemon.
author Naoya OYAMA <naoya.oyama@gmail.com>
date Sun, 25 Jul 2010 16:40:42 +0900
parents
children
comparison
equal deleted inserted replaced
122:4009737ea899 123:215a51fa3df3
1 #include <fcntl.h>
2 #include <limits.h>
3 #include <pwd.h>
4 #include <sys/ioctl.h>
5 #include <sys/stat.h>
6 #include <sys/types.h>
7 #include <signal.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include "pt1_ioctl.h"
13
14 #ifdef O_NOFOLLOW
15 #define OPEN_FLAGS O_NOFOLLOW | O_NONBLOCK
16 #else
17 #define OPEN_FLAGS O_NONBLOCK
18 #endif
19
20 /* ヘッダに移動すること */
21 #define C_RET_OK 0
22 #define C_RET_NG -1
23 #define MYNAME "pt1_lnb_enabler"
24 #define PID_DIR "/var/run/"
25 #define PIDFILENAME PID_DIR MYNAME ".pid"
26 #define NUMBER "0123456789"
27 #define device "/dev/pt1video0"
28 #define ROOT "root"
29 /* ヘッダに移動すること */
30
31 mode_t umask_val = 0133;
32
33 void fin_action(int);
34
35 int main() {
36 struct sigaction ign_sigaction;
37 struct sigaction fin_sigaction;
38 FILE *fp;
39 int i;
40 int i_ret;
41 int fd;
42 int pt1_fd;
43 int string_length;
44 int number_length;
45 int i_pid;
46 struct stat orig_st;
47 struct stat open_st;
48 int flags;
49 char file_name[] = PIDFILENAME;
50 char buf[1024] = "";
51 pid_t mypid;
52 char *p;
53 struct passwd *p_st_passwd;
54 uid_t uid_root;
55
56 /* 初期処理 */
57 /* root権限で動作していなければ終了 */
58 p_st_passwd = getpwnam(ROOT);
59 if (p_st_passwd == NULL) {
60 printf("faile to get pwent. id=[%s].\n", ROOT);
61 exit(C_RET_NG);
62 }
63 uid_root = p_st_passwd->pw_uid;
64 if( uid_root != getuid() ) {
65 /* root 意外の実行権限なのでエラー */
66 printf("This process must be run by root. uid=[%d].\n", getuid());
67 exit(C_RET_NG);
68 }
69 /* fork して親は即自殺してターミナルを離す */
70 mypid = fork();
71 if( mypid == -1 ) {
72 /* fork エラー */
73 printf("fork error.\n");
74 exit(C_RET_NG);
75 } else if ( mypid != 0 ) {
76 /* 親プロセスは即終了(プロンプトに戻す) */
77 return(C_RET_OK);
78 }
79 umask(umask_val);
80 ign_sigaction.sa_handler = SIG_IGN;
81 fin_sigaction.sa_handler = fin_action;
82 if (sigaction(SIGHUP, &ign_sigaction, NULL) != 0) {
83 printf("failed to set signal handler. SIGHUP\n");
84 exit(C_RET_NG);
85 }
86 if (sigaction(SIGTERM, &fin_sigaction, NULL) != 0) {
87 printf("failed to set signal handler. SIGTERM\n");
88 exit(C_RET_NG);
89 }
90 if (sigaction(SIGPIPE, &fin_sigaction, NULL) != 0) {
91 printf("failed to set signal handler. SIGPIPE\n");
92 exit(C_RET_NG);
93 }
94 if (sigaction(SIGINT, &fin_sigaction, NULL) != 0) {
95 printf("failed to set signal handler. SIGINT\n");
96 exit(C_RET_NG);
97 }
98 if (sigaction(SIGQUIT, &fin_sigaction, NULL) != 0) {
99 printf("failed to set signal handler. SIGQUIT\n");
100 exit(C_RET_NG);
101 }
102 if (sigaction(SIGILL, &fin_sigaction, NULL) != 0) {
103 printf("failed to set signal handler. SIGILL\n");
104 exit(C_RET_NG);
105 }
106 if (sigaction(SIGABRT, &fin_sigaction, NULL) != 0) {
107 printf("failed to set signal handler. SIGABRT\n");
108 exit(C_RET_NG);
109 }
110 if (sigaction(SIGFPE, &fin_sigaction, NULL) != 0) {
111 printf("failed to set signal handler. SIGFPE\n");
112 exit(C_RET_NG);
113 }
114 if (sigaction(SIGSEGV, &fin_sigaction, NULL) != 0) {
115 printf("failed to set signal handler. SIGSEGV\n");
116 exit(C_RET_NG);
117 }
118 /* sleep を使うので SIGALRM は放置
119 * if (sigaction(SIGALRM, &ign_sigaction, NULL) != 0) {
120 * printf("failed to set signal handler. SIGALRM\n");
121 * exit(C_RET_NG);
122 * }
123 */
124 if (sigaction(SIGUSR1, &ign_sigaction, NULL) != 0) {
125 printf("failed to set signal handler. SIGUSR1\n");
126 exit(C_RET_NG);
127 }
128 if (sigaction(SIGUSR2, &ign_sigaction, NULL) != 0) {
129 printf("failed to set signal handler. SIGUSR2\n");
130 exit(C_RET_NG);
131 }
132 if (sigaction(SIGCHLD, &ign_sigaction, NULL) != 0) {
133 printf("failed to set signal handler. SIGCHLD\n");
134 exit(C_RET_NG);
135 }
136 if (sigaction(SIGCONT, &ign_sigaction, NULL) != 0) {
137 printf("failed to set signal handler. SIGCONT\n");
138 exit(C_RET_NG);
139 }
140 if (sigaction(SIGTSTP, &ign_sigaction, NULL) != 0) {
141 printf("failed to set signal handler. SIGTSTP\n");
142 exit(C_RET_NG);
143 }
144 if (sigaction(SIGTTIN, &ign_sigaction, NULL) != 0) {
145 printf("failed to set signal handler. SIGTTIN\n");
146 exit(C_RET_NG);
147 }
148 if (sigaction(SIGTTOU, &ign_sigaction, NULL) != 0) {
149 printf("failed to set signal handler. SIGTTOU\n");
150 exit(C_RET_NG);
151 }
152 if (sigaction(SIGPOLL, &ign_sigaction, NULL) != 0) {
153 printf("failed to set signal handler. SIGPOLL\n");
154 exit(C_RET_NG);
155 }
156 if (sigaction(SIGIO, &ign_sigaction, NULL) != 0) {
157 printf("failed to set signal handler. SIGIO\n");
158 exit(C_RET_NG);
159 }
160 if (sigaction(SIGPROF, &ign_sigaction, NULL) != 0) {
161 printf("failed to set signal handler. SIGPROF\n");
162 exit(C_RET_NG);
163 }
164 if (sigaction(SIGSYS, &ign_sigaction, NULL) != 0) {
165 printf("failed to set signal handler. SIGSYS\n");
166 exit(C_RET_NG);
167 }
168 if (sigaction(SIGTRAP, &ign_sigaction, NULL) != 0) {
169 printf("failed to set signal handler. SIGTRAP\n");
170 exit(C_RET_NG);
171 }
172 if (sigaction(SIGURG, &ign_sigaction, NULL) != 0) {
173 printf("failed to set signal handler. SIGURG\n");
174 exit(C_RET_NG);
175 }
176 if (sigaction(SIGVTALRM, &ign_sigaction, NULL) != 0) {
177 printf("failed to set signal handler. SIGVTALRM\n");
178 exit(C_RET_NG);
179 }
180 if (sigaction(SIGXCPU, &ign_sigaction, NULL) != 0) {
181 printf("failed to set signal handler. SIGXCPU\n");
182 exit(C_RET_NG);
183 }
184 if (sigaction(SIGXFSZ, &ign_sigaction, NULL) != 0) {
185 printf("failed to set signal handler. SIGXFSZ\n");
186 exit(C_RET_NG);
187 }
188 /* ないって
189 * if (sigaction(SIGEMT, &ign_sigaction, NULL) != 0) {
190 * printf("failed to set signal handler. SIGEMT\n");
191 * exit(C_RET_NG);
192 * }
193 */
194 if (sigaction(SIGSTKFLT, &ign_sigaction, NULL) != 0) {
195 printf("failed to set signal handler. SIGSTKFLT\n");
196 exit(C_RET_NG);
197 }
198 if (sigaction(SIGIO, &ign_sigaction, NULL) != 0) {
199 printf("failed to set signal handler. SIGIO\n");
200 exit(C_RET_NG);
201 }
202 if (sigaction(SIGCLD, &ign_sigaction, NULL) != 0) {
203 printf("failed to set signal handler. SIGCLD\n");
204 exit(C_RET_NG);
205 }
206 if (sigaction(SIGPWR, &ign_sigaction, NULL) != 0) {
207 printf("failed to set signal handler. SIGPWR\n");
208 exit(C_RET_NG);
209 }
210 /* ないって
211 * if (sigaction(SIGINFO, &ign_sigaction, NULL) != 0) {
212 * printf("failed to set signal handler. SIGINFO\n");
213 * exit(C_RET_NG);
214 * }
215 */
216 /* ないって
217 * if (sigaction(SIGLOST, &ign_sigaction, NULL) != 0) {
218 * printf("failed to set signal handler. SIGLOST\n");
219 * exit(C_RET_NG);
220 * }
221 */
222 if (sigaction(SIGWINCH, &ign_sigaction, NULL) != 0) {
223 printf("failed to set signal handler. SIGWINCH\n");
224 exit(C_RET_NG);
225 }
226 if (sigaction(SIGUNUSED, &ign_sigaction, NULL) != 0) {
227 printf("failed to set signal handler. SIGUNUSED\n");
228 exit(C_RET_NG);
229 }
230
231 /* ファイルチェック処理 */
232 if ((lstat(file_name, &orig_st) != 0) ||
233 (!S_ISREG(orig_st.st_mode)))
234 {
235 /* ファイル無しの場合は前回正常終了 */
236 i_ret = C_RET_OK;
237 } else {
238 /* PIDファイルが存在する場合には、現在の状態を確認する。
239 * ・二重起動状態(pidファイルのpid値を持つプロセスが存在する)
240 * ・前回pidファイルを消さずに死んでしまった */
241 i_ret = C_RET_NG;
242 }
243 /* ここに TOCTOU 競合状態の問題があるが、
244 * /var/run はセキュアなディレクトリなので問題は無い */
245 if (i_ret != C_RET_OK) {
246 fd = open(file_name, (OPEN_FLAGS | O_RDWR));
247 if (fd == -1) {
248 /* エラー処理 */
249 printf("open error. file:[%s].\n", file_name);
250 exit(C_RET_NG);
251 }
252
253 if (fstat(fd, &open_st) != 0) {
254 /* エラー処理 */
255 printf("stat error. file:[%s].\n", file_name);
256 exit(C_RET_NG);
257 }
258
259 if ((orig_st.st_mode != open_st.st_mode) ||
260 (orig_st.st_ino != open_st.st_ino) ||
261 (orig_st.st_dev != open_st.st_dev)) {
262 /* ファイルはすでにすり替えられている */
263 printf("file switch has occurred. file:[%s].\n", file_name);
264 close(fd);
265 exit(C_RET_NG);
266 }
267
268 /* 問題ないファイルであることが確認できたので O_NONBLOCK
269 * を無効にする (省略可能) */
270 if ((flags = fcntl(fd, F_GETFL)) == -1) {
271 /* エラー処理 */
272 printf("fcntl error. file:[%s].\n", file_name);
273 close(fd);
274 exit(C_RET_NG);
275 }
276
277 if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) != 0) {
278 /* エラー処理 */
279 printf("fcntl error. file:[%s].\n", file_name);
280 close(fd);
281 exit(C_RET_NG);
282 }
283 /* ファイルサイズが0以外である場合にはPID値のチェック */
284 if(open_st.st_size != 0) {
285 /* ファイルを読みPID値を取得する */
286 if((fp = fdopen(fd, "w+")) == NULL) {
287 /* fdopen()失敗 */
288 printf("fdopen error. fd:[%d].\n", fd);
289 close(fd);
290 exit(C_RET_NG);
291 }
292 if ( fgets(buf, sizeof(buf), fp) == NULL ) {
293 /* fgetsエラー */
294 printf("fgets error. fd:[%d].\n", fd);
295 fclose(fp);
296 exit(C_RET_NG);
297 }
298 buf[sizeof(buf)-1] = '\0';
299 p = strchr(buf, (int)'\n');
300 if(p != NULL) {
301 *p = '\0';
302 }
303 string_length = strlen(buf);
304 number_length = strspn(buf, NUMBER);
305 if ( string_length != number_length ) {
306 /* PIDファイル異常 */
307 printf("invalid pid file[%s] buf[%s].\n", file_name, buf);
308 fclose(fp);
309 exit(C_RET_NG);
310 }
311 i_pid = atoi(buf);
312
313 /* PIDファイルのPIDと同じPIDを持つプロセスが存在するか? */
314 i_ret = kill(i_pid, 0);
315 if ( i_ret == 0 ) {
316 /* 存在する場合には二重起動とみなして処理終了 */
317 printf("process already exists. pid[%d]\n", i_pid);
318 exit(C_RET_NG);
319 } else {
320 /* 存在しない場合は前回異常終了なのでfpを先頭に戻して処理続行 */
321 rewind(fp);
322 }
323 }
324 }
325 if ( i_ret == C_RET_OK ) {
326 /* PIDファイルが存在しない場合はPIDファイルの新規作成を行う */
327 fd = open(file_name, O_CREAT|O_EXCL|O_RDWR, 00644);
328 if ( fd == -1 ){
329 /* open 失敗 */
330 printf("file open error. file_name[%s].\n", file_name);
331 exit(C_RET_NG);
332 }
333 if((fp = fdopen(fd, "w+")) == NULL) {
334 /* fdopen()失敗 */
335 printf("fdopen error. fd:[%d].\n", fd);
336 close(fd);
337 exit(C_RET_NG);
338 }
339 }
340 /* fpのPIDファイルが書き込める状態なので、PIDを書き込む */
341 mypid = getpid();
342 snprintf(buf, sizeof(buf), "%d\n", mypid);
343 i_ret = fputs(buf, fp);
344 if(i_ret == EOF) {
345 /* fputs エラー */
346 printf("fputs error. file_name[%s].\n", file_name);
347 fclose(fp);
348 exit(C_RET_NG);
349 }
350 fclose(fp);
351 /* PID関係処理終了*/
352 /* fd に pt1 デバイスを open */
353 pt1_fd = open(device, O_RDONLY);
354 if(pt1_fd == -1) {
355 /* open エラー */
356 printf("open error. file_name[%s].\n", device);
357 exit(C_RET_NG);
358 }
359 /* fcntl で LNB 電源を有効化する */
360 if(ioctl(pt1_fd, LNB_ENABLE, 0) < 0) {
361 printf("Power on LNB failed. device:[%s].\n", device);
362 exit(C_RET_NG);
363 }
364 close(pt1_fd);
365 /* 無限待ち(終了は終了するsignalを受けたらとする) */
366 while(1){
367 sleep(UINT_MAX);
368 }
369 return C_RET_OK;
370 }
371
372 /* 終了処理実行関数 */
373 /* プロセスを終了させるべきsignalを受けたときに動作する */
374 void fin_action(int sig) {
375 int pt1_fd;
376 char file_name[] = PIDFILENAME;
377 /* fd に pt1 デバイスをopen */
378 pt1_fd = open(device, O_RDONLY);
379 if(pt1_fd == -1) {
380 /* open エラー */
381 printf("open error. file_name[%s].\n", device);
382 exit(C_RET_NG);
383 }
384 /* fcntl で LNB 電源断する */
385 if(ioctl(pt1_fd, LNB_DISABLE, 0) < 0) {
386 printf("Power on LNB failed. device:[%s].\n", device);
387 close(pt1_fd);
388 exit(C_RET_NG);
389 }
390 /* fd close */
391 close(pt1_fd);
392 /* pidファイルを削除する */
393 if ( unlink(file_name) != 0 ) {
394 /* pid file unlink エラー */
395 printf("unlink error. file_name[%s].\n", device);
396 exit(C_RET_NG);
397 }
398 /* おしまい */
399 exit(C_RET_OK);
400 }