123
|
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 }
|