标签:
在《远程触发SYSRQ获取最新的dmesg信息-一个几乎没有什么用的方案》中,我认为远程触发SYSRQ并没有什么实际的用处,系统没有挂起时,用SSH等标准方式会好很多,系统挂起时,远程触发在多数情况下均无法得到响应。那么有什么方法在系统panic的时候通知外部呢?代码如下:
#include <linux/module.h>
#include <linux/skbuff.h>
#include <net/ip.h>
struct sk_buff * skb = NULL;
struct net_device * dev = NULL;
u8 ethhdr [ETH_HLEN] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x0c, 0x29, 0xdd, 0xaa, 0xfd,
0x00, 0x00
};
u8 iphdr [20] = {
0x45,
0x00,
0x00, 0x00, //total length
0x00, 0x00, //ID
0x40, 0x00, //Don‘t fragment
0x40, //TTL
0xff, // UDP?
0x00, 0x00, //checksum
0x02, 0x02, 0x02, 0x02,
0xff, 0xff, 0xff, 0xff
};
u8 data[1024] = {0};
void do_nothing (struct sk_buff *skb)
{
/* 不再进行任何内存操作 */
//dev_put(skb->dev);
}
static int send_last_msg(struct notifier_block *self,
unsigned long event, void *unused)
{
int ret;
struct ethhdr *eth;
struct iphdr *ip;
char *p;
/* 获取内核缓冲区中的数据 */
kernel_log_buffer(data, sizeof(data));
skb->dev = dev;
skb->pkt_type = PACKET_OTHERHOST;
skb->protocol = htons(ETH_P_IP);
skb->ip_summed = CHECKSUM_NONE;
skb->destructor = do_nothing;
skb->priority = 0;
/* 保留skb区域 */
skb_reserve (skb, 2 + ETH_HLEN + sizeof(struct iphdr) + sizeof(data));
/* 构造数据区(使用UDP会比较好,但是懒的封装了) */
p = skb_push(skb, sizeof(data));
memcpy(p, &data[0], sizeof(data));
skb_reset_transport_header(skb);
/* 构造IP头 */
p = skb_push(skb, sizeof(struct iphdr));
memcpy(p, &iphdr, sizeof(struct iphdr));
ip = (struct iphdr*)p;
ip->tot_len = htons(sizeof(data) + sizeof(struct iphdr));
skb_reset_network_header(skb);
/* 构造以太头 */
p = skb_push(skb, sizeof(struct ethhdr));
eth = (struct ethhdr*)p;
eth->h_proto = htons(ETH_P_IP);
memcpy(p, ehdr, sizeof(struct ethhdr));
skb_reset_mac_header(skb);
/* 发射 */
ret = dev_queue_xmit(skb);
if (ret < 0) {
/* 由于panic了,不再处理内存,不处理异常流 */
//kfree_skb (skb);
//dev_put(dev);
goto out;
}
out:
return ret;
}
static struct notifier_block on_panic_send = {
.notifier_call = send_last_msg,
};
static int __init
panic_sendmsg_init(void)
{
int ret = -1;
dev = dev_get_by_name (&init_net, "eth2");
if (!dev) {
printk("Can‘t get device\n");
goto out;
}
/* 不在通知链中分配,因为那时已经panic,故预先分配 */
skb = alloc_skb(1500, GFP_ATOMIC);
if (!skb) {
dev_put(dev);
printk("Alloc skb failed\n");
goto out;
}
/* 注册 */
ret = atomic_notifier_chain_register(&panic_notifier_list, &on_panic_send);
if (ret) {
dev_put(dev);
kfree_skb (skb);
printk("Register notifier chain failed\n");
goto out;
}
return 0;
out:
return ret;
}
static void __exit
panic_sendmsg_exit(void)
{
atomic_notifier_chain_unregister(&panic_notifier_list, &on_panic_send);
if (dev) {
dev_put(dev);
}
if (skb) {
kfree_skb (skb);
}
}
module_init(panic_sendmsg_init);
module_exit(panic_sendmsg_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("marywangran <marywangran@126.com>");不管怎么样,不管是磁盘操作还是网络操作,都需要将内核log缓冲区中的内存dump下来才好,然而内核log缓冲区本身并没有被EXPORT,它只能通过不多的几个系统调用接口来获取,而这些接口很难在内核里面调用,因此我自己添加了一个:
int kernel_log_buffer(char *buf, int max_len);
系统panic后主动广播最后内核dmesg信息-一个几乎可以使用的方案
标签:
原文地址:http://blog.csdn.net/dog250/article/details/43370659