#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//由于嵌入式linux貌似没有对ethtool_value这个结*构体的定义,但在非嵌入式的版本里是有的,所以直接抄过来= =...
struct ethtool_value {
int cmd;
int data;
};
//以下两个宏和ioctl有关,从网卡里获取网线的状态的关键就在这里
#define ETHTOOL_GLINK 0x0000000a
#define SIOCETHTOOL 0x8946
#define UNCONNECT 0
#define CONNECT 1
int main(int argc, char **argv)
{
int i, fd, fd2, fdtablesize, sock, last, ret;
pid_t pid;
struct sigaction sa;
struct ifreq ifr;
struct ethtool_value edata;
edata.cmd = ETHTOOL_GLINK;
edata.data = 0;
//以下是产生一个守*护进程的方法,具体注解就不再赘述,之前的博文里有详解
umask(0);
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
//shutdown some signal
if(sigaction(SIGTTOU, &sa, NULL) < 0)
{
printf("can't ignore SIGTTOU\n");
return -1;
}
if(sigaction(SIGTTIN, &sa, NULL) < 0)
{
printf("can't ignore SIGTTIN\n");
return -1;
}
if(sigaction(SIGTSTP, &sa, NULL) < 0)
{
printf("can't ignore SIGTSTP\n");
return -1;
}
if(sigaction(SIGHUP, &sa, NULL) < 0)
{
printf("can't ignore SIGHUP\n");
return -1;
}
//terminate the father thread first
if(fork() != 0)
{
exit(1);
}
if(setsid() < 0)
{
exit(1);
}
//terminate the father thread second
if(fork() != 0)
{
exit(1);
}
//change work dir to root
if(chdir("/") == -1)
{
exit(1);
}
//shutdown some fds
for(fd = 0, fdtablesize = getdtablesize(); fd < fdtablesize; fd++)
{
close(fd);
}
if(sigaction(SIGCHLD, &sa, NULL))
{
printf("can't ignore SIGCHLD\n");
return -1;
}
//access a socket
sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock == -1)
{
return -1;
}
//这里是将要查询的端口名拷贝到指定位置
strcpy(ifr.ifr_name, "eth0");
ifr.ifr_data = (char *)&edata;
//获取状态
ioctl(sock, SIOCETHTOOL, &ifr);
last = edata.data;
//不断的读取网卡的状态
while(1)
{
//偶尔也让它休息一下^_^
sleep(1);
ioctl(sock, SIOCETHTOOL, &ifr);
//如果状态没有改变,就跳过,直接执行下一次查询
if(edata.data == last)
{
continue;
}
else
{
if(last == UNCONNECT) //如果网线被插上了
{
//打开一个子进程,在里面调用一个脚本
if(fork() == 0)
{
// pid = getpid();
ret = execl("/data/work/ma_to_mt.sh", "master", NULL);
if(ret < 0)
{
exit(1);
}
// return 0; //这里没有必要使用return 因为execl执行了就不会返回了
}
last = CONNECT; //把状态改为已连接
}
else if(last == CONNECT) //如果断开了网线
{
if(fork() == 0) //开一个子进程,运行另一个脚本
{
// pid = getpid();
ret = execl("/data/work/mt_to_ma.sh", "managed", NULL);
if(ret < 0)
{
exit(1);
}
}
last = UNCONNECT; //状态改为已断开
}
}
waitpid(-1, NULL ,0); //这个回收子进程的动作貌似也是没必要的= =....
}
return 0;
}
注:第一种方法适用于2.6内核以后的版本,第二中方法适用于2.4及以前的版本,2.4及之前的版本没有/sys/class/net/%s/carrier这个目录