这里首先假设读者知道守护进程的大概概念,下面我们直接看程序。

//****************

环境,OS = Ubuntu 10.4 编译器 = gcc 4.5.2

******************//

1. int main(int argc, char **argv)  
2.
3. {
4.
5. //因为下面要关掉某些信号,所以需要
6.
7. struct sigaction sa;
8.
9. int i, fd, fdtablesize;
10.
11.
12.
13. //上来第一件事,调用umask将文件模式创建屏蔽字设置为0,为的是防止守护进程可能不具有对文件读写的权限
14.
15. umask(0);
16.
17. //设置信号处理函数,SIG_IGN为忽略信号
18.
19. sa.sa_handler = SIG_IGN;
20.
21. //sa.sa_mask这个成员的清零,一定要使用sigemtpy函数
22.
23. sigemptyset(&sa.sa_mask);
24.
25. sa.sa_flags = 0;
26.
27. //对以下几种信号做忽略处理
28.
29. sigaction(SIGTTOU, &sa, NULL);
30.
31. sigaction(SIGTTIN, &sa, NULL);
32.
33. sigaction(SIGTSTP, &sa, NULL);
34.
35. sigaction(SIGUP, &sa, NULL);
36.
37.
38.
39. //关闭父进程,使子进程成为孤儿进程,从而被init收养
40.
41. if(fork() != 0)
42.
43. {
44.
45. exit(1);
46.
47. }
48.
49. //创建一个新会话
50.
51. if(setsid() < 0)
52.
53. {
54.
55. exit(1);
56.
57. }
58.
59. //第二次退出父进程
60.
61. if(fork() != 0)
62.
63. {
64.
65. exit(1);
66.
67. }
68.
69. //改变工作路径到root,防止出现工作目录被卸载的情况
70.
71. if(chidr("/") == -1)
72.
73. {
74.
75. exit(1);
76.
77. }
78.
79. //关闭打开的文件描述符,包括标准输入输出和标准出错
80.
81. for(fd = 0, fdtablesize = getdtablesize(); fd < fdtablesize; fd++)
82.
83. {
84.
85. close(fd);
86.
87. }
88.
89. //再次关掉信号
90.
91. sigaction(SIGCHLD, &sa, NULL);
92.
93. //进入一个死循环让守护进程常驻内存
94.
95. while(1)
96.
97. {
98.
99. //do somthing
100.
101. sleep(1);
102.
103. }
104.
105. //至此就完成了对一个守护进程的初始化
106.
107. return 0;
108.
109. }

/*

        博主注明:

               编译环境: Ubuntu 10.4    编译器:arm-linux-gcc

               硬件环境:i.mx28  嵌入式linux版本 2.6.15

               介绍:

                             参考ethtool工具源代码,发现在对网卡的ioctl操作中,可以读出网卡的状态

*/

1. #include <stdio.h>  
2. #include <unistd.h>
3. #include <stdlib.h>
4. #include <signal.h>
5. #include <sys/file.h>
6. #include <netinet/in.h>
7. #include <linux/if.h>
8. #include <string.h>
9. #include <sys/types.h>
10. #include <arpa/inet.h>
11. #include <sys/ioctl.h>
12.
13.
14.
15. //由于嵌入式linux貌似没有对ethtool_value这个结*构体的定义,但在非嵌入式的版本里是有的,所以直接抄过来= =...
16. struct ethtool_value {
17. int cmd;
18. int data;
19. };
20.
21.
22.
23. //以下两个宏和ioctl有关,从网卡里获取网线的状态的关键就在这里
24. #define ETHTOOL_GLINK 0x0000000a
25. #define SIOCETHTOOL 0x8946
26. #define UNCONNECT 0
27. #define CONNECT 1
28.
29. int main(int argc, char **argv)
30. {
31. int i, fd, fd2, fdtablesize, sock, last, ret;
32. pid_t pid;
33.
34.
35. struct sigaction sa;
36. struct ifreq ifr;
37. struct ethtool_value edata;
38.
39.
40. edata.cmd = ETHTOOL_GLINK;
41. edata.data = 0;
42.
43. //以下是产生一个守*护进程的方法,具体注解就不再赘述,之前的博文里有详解
44. umask(0);
45. sa.sa_handler = SIG_IGN;
46. sigemptyset(&sa.sa_mask);
47. sa.sa_flags = 0;
48.
49.
50. //shutdown some signal
51. if(sigaction(SIGTTOU, &sa, NULL) < 0)
52. {
53. printf("can't ignore SIGTTOU\n");
54. return -1;
55. }
56.
57. if(sigaction(SIGTTIN, &sa, NULL) < 0)
58. {
59. printf("can't ignore SIGTTIN\n");
60. return -1;
61. }
62.
63. if(sigaction(SIGTSTP, &sa, NULL) < 0)
64. {
65. printf("can't ignore SIGTSTP\n");
66. return -1;
67. }
68.
69. if(sigaction(SIGHUP, &sa, NULL) < 0)
70. {
71. printf("can't ignore SIGHUP\n");
72. return -1;
73. }
74.
75. //terminate the father thread first
76. if(fork() != 0)
77. {
78. exit(1);
79. }
80. if(setsid() < 0)
81. {
82. exit(1);
83. }
84. //terminate the father thread second
85. if(fork() != 0)
86. {
87. exit(1);
88. }
89. //change work dir to root
90. if(chdir("/") == -1)
91. {
92. exit(1);
93. }
94. //shutdown some fds
95. for(fd = 0, fdtablesize = getdtablesize(); fd < fdtablesize; fd++)
96. {
97. close(fd);
98. }
99. if(sigaction(SIGCHLD, &sa, NULL))
100. {
101. printf("can't ignore SIGCHLD\n");
102. return -1;
103. }
104.
105. //access a socket
106. sock = socket(AF_INET, SOCK_DGRAM, 0);
107. if(sock == -1)
108. {
109. return -1;
110. }
111.
112. //这里是将要查询的端口名拷贝到指定位置
113. strcpy(ifr.ifr_name, "eth0");
114. ifr.ifr_data = (char *)&edata;
115.
116. //获取状态
117. ioctl(sock, SIOCETHTOOL, &ifr);
118. last = edata.data;
119.
120. //不断的读取网卡的状态
121. while(1)
122. {
123.
124. //偶尔也让它休息一下^_^
125.
126. sleep(1);
127. ioctl(sock, SIOCETHTOOL, &ifr);
128.
129.
130. //如果状态没有改变,就跳过,直接执行下一次查询
131. if(edata.data == last)
132. {
133. continue;
134. }
135. else
136. {
137. if(last == UNCONNECT) //如果网线被插上了
138. {
139. //打开一个子进程,在里面调用一个脚本
140. if(fork() == 0)
141. {
142. // pid = getpid();
143. ret = execl("/data/work/ma_to_mt.sh", "master", NULL);
144. if(ret < 0)
145. {
146. exit(1);
147. }
148. // return 0; //这里没有必要使用return 因为execl执行了就不会返回了
149. }
150. last = CONNECT; //把状态改为已连接
151. }
152. else if(last == CONNECT) //如果断开了网线
153. {
154. if(fork() == 0) //开一个子进程,运行另一个脚本
155. {
156. // pid = getpid();
157. ret = execl("/data/work/mt_to_ma.sh", "managed", NULL);
158. if(ret < 0)
159. {
160. exit(1);
161. }
162. }
163. last = UNCONNECT; //状态改为已断开
164. }
165.
166. }
167. waitpid(-1, NULL ,0); //这个回收子进程的动作貌似也是没必要的= =....
168. }
169. return 0;
170. }