Linux-Tag Archive:
分类: Python, Unix/Linux 发布日期: 2010.03.05 星期五
Python 2.6新增的multiprocessing,即多进程,给子进程代码调试有点困难,比如python自带的pdb如果直接在子进程代码里面启动会抛出一堆异常,原因是子进程的stdin/out/err等文件都已关闭,pdb无法调用。据闻winpdb、Wing IDE的调试器能够支持这样的远程调试,但似乎过于重量级(好吧前者比后者要轻多了,但一样要wxPython的环境,再说pdb的灵活可靠它们难以比拟)。
其实只需稍作改动即可用pdb继续调试子进程的代码,思路来自这个博客:子进程的stdin/out/err关闭了,那可以自己重新按/dev/stdout的名称打开来用。当然这指*nix下,win下要麻烦一些,后面再说。
pdb支持自定义输出输入的文件,我再稍作改动,使用fifo管道(Named Pipe)来完成pdb的输出输入的重定向,这样的好处是,可以同时对父子进程调试!
multiproces_debug.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| #!/usr/bin/python
import multiprocessing
import pdb
def child_process():
print "Child-Process"
pdb.Pdb(stdin=open('p_in', 'r+'), stdout=open('p_out', 'w+')).set_trace()
var = "debug me!"
def main_process():
print "Parent-Process"
p = multiprocessing.Process(target = child_process)
p.start()
pdb.set_trace()
var = "debug me!"
p.join()
if __name__ == "__main__":
main_process() |
只需要给pdb的构造参数传入stdin/stdout的文件对象,调试过程的输出输入就自然以传入的文件为方向了。这里需要两个管道文件p_in、p_out,运行脚本之前,使用命令mkfifo p_in p_out同时建立。这还未完成,还需要个外部程序来跟管道交互:
debug_cmd.sh
1
2
3
4
5
6
7
| #!/bin/bash
cat p_out &
while [[ 1 ]]; do
read -e cmd
echo $cmd>p_in
done |
很简单的bash。因为fifo管道在写入端未传入数据时,读取端是阻塞的(反之亦然),所以cat的显示挂在后台,当调试的程序结束后,管道传出EOF,cat就自动退出了。
实验开始:先在一个终端运行debug_cmd.sh(其实顺序无关),其光标停在新的一行,再在另外一个终端运行multiproces_debug.py,可见到两个终端同时出现了(Pdb)的指示符,可以同时对父子进程调试了!

在Windows下使用管道就没这么方便了,因为没有实体的管道文件支持,可以考虑使用socket的类文件对象传给pdb。但这样要写的python代码就多一点,以及要另外用做个交互程序;不过依然用不了多少代码,可以写成一个模块专门用做远程调试,import即用。暂未实现,以后有空弄好放代码出来。
Tags: debug, Linux, pdb, pipe, process, Python, 多进程, 远程调试
分类: Programming, Unix/Linux 发布日期: 2009.10.09 星期五
Insion同学之前发来一段可以在MacOS/BSD编译运行获取网卡MAC地址的代码,于是整理了一下,让几个802.1x Client都能支持MacOS/BSD了。
下载了个FreeBSD 7.2在vbox虚拟机里面装了下,发现FreeBSD比Linux好像原始多了[呃,我说安装程序],分区的时候他不叫Create Partition,叫Create Slice,我对着界面看了半天才猜到,囧;退出那里写着:Q = Finish,Quit就Quit嘛,什么Finish,纠结……但还好,其他的配置跟Linux还是很相像的,调试了一下就有了全可编译的代码了。
代码部分修改倒没多少,就添加了一个专门给BSD系系统获取MAC的函数,再用maroc判断一下,以及几个头文件,就完事了,有点麻烦的是makefile,发现freebsd默认那个make好像是很古老很古老的版本,我程序里面那个Makefile是用了vim里面c-support插件里面带的Makefile模板,有点复杂,但是freebsd居然不支持!所以整理了个简单的版本,专门给MacOS/BSD编译,也方便别人的修改;另外一个原因是,程序里面转换服务器消息时候用了iconv库,linux里面iconv是系统内嵌库来的,用不着链接的时候给出参数,但MacOS/BSD偏偏就要-liconv……
需要编译MacOS/BSD版本的同学,可以check出项目里面trunk的代码,运行make -f Makefile.bsd来编译。Insion同学已经编译成功,而且在他的主页上有二进制版下载了。
相对的说,可能在MacOS里面编译是最麻烦的,我大概说说流程(实际上我没试过,我可没Mac机器[T.T])
1.安装gcc,参考这里从http://connect.apple.com/的Dev Tools里面下载Xcode Tools,安装。
2.编译安装libpcap,从http://www.tcpdump.org/release/libpcap-1.0.0.tar.gz下载源码,tar xvfz libpcap-1.0.0.tar.gz解压,进去该目录,./configure、make、make install安装完成;
3.编译802.1x客户端,从所用项目内签出源码,在目录内make,没出什么差错的话,已经完成了。然后按Readme.txt的方法安装运行,即可!
项目主页
锐捷:http://code.google.com/p/zruijie4gzhu/
联想:http://code.google.com/p/zlevoclient/
神州数码:http://code.google.com/p/zdcclient/
Tags: 802.1x, BSD, Linux, MacOS, 神州数码, 联想, 锐捷
分类: Unix/Linux 发布日期: 2009.09.27 星期天
早天在新蛋上入手了Acer Aspire 4736ZG本本一台,T4200、1G、NV105M、250G,带蓝牙摄像头等,3600,还送了一台水星无线路由。低端本本为了降低成本,很多都是不装Windows的,这款也是,本来以为原装系统都是Linux,应该对Linux兼容不错的啦,那天到提货点验本本时候,运行一看,傻了,那个什么Linpus,2.6.15的内核,没带X,lshw没有,lspci没有,hwinfo更没有,总之就没什么东西好看的,除了黑漆漆的画面告诉我屏幕没坏点,就匆匆打上包回来了。
第一件事就是用Arch 09.08的Live CD启动重新分区,顺便装好core,但是启动后又傻了,连不上有线网卡……这款机器的网卡是Atheros AR8132的千兆卡,不知道是太新还是太罕见。几经折腾后发现规律:完全关机重开后,Arch就能认到网卡,ipconfig -a能看到eth0,但是ifconfig eth0 up了之后,是这个样子的:
eth0 Link encap:Ethernet HWaddr 00:26:18:80:C5:AB
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:4294967293 errors:4294967278 dropped:4294967290 overruns:4294967293 frame:4294967281
TX packets:4294967293 errors:4294967284 dropped:0 overruns:4294967293 carrier:4294967291
collisions:4294967281 txqueuelen:1000
RX bytes:4294967293 (4095.9 Mb) TX bytes:4294967293 (4095.9 Mb)
Interrupt:28
大堆奇怪的数字,这时候不管dhcp还是手动指定IP,都没法正常工作的,如果这时重启,好,完全认不了网卡了,又要完全关机再开一次。
这个问题在Arch论坛上面也有人碰到,他的是华硕eeePC 1005HA,也是上个月的帖子。[详细情况帖子里面比较完备,但是,未解决]
于是我就转战Ubuntu。Ubuntu 9.04的Live CD版本也是没能驱动好这块网卡的,但是这里找到解决方法,总之就是到Atheros官网下载网卡的驱动,编译,挂载驱动模块,幸好Ubuntu的Live CD跟初始系统都带了GCC和Make utils,编译安装过程倒没什么波折,很快就折腾好连上网了。呃,怎么这么简单?于是试试在台式机的Arch上面编译了这个atl1c.ko,哇,一开始就一屏幕的错误……后来发现这个是这个驱动跟内核兼容问题,Ubuntu好像专门有补丁搞定的,Ubuntu 9.04把内核升级到2.6.28.15-generic网卡就完全正常了,也顺便下载了9.10的Live CD,直接iso启动,发现虽然是31内核,但是网卡工作也正常……好吧……看来要么等kernel彻底搞定这块网卡的驱动,不然只能自己找Ubuntu的patch来编译才能跑Arch了……
Ubuntu很是省心,挂上受限驱动什么3D特效全都出来了,跑了下glxgears,大概2600fps,比台式机的集显好一点吧……7025只有1300左右的fps;更新了一下系统,用Ubuntu Tweak添加了一堆三方源后拉好一大堆软件,基本可用了,另外的问题是,声卡的耳机输出没声音!
本本的耳机问题好像从来都是老大难的,因为音频接口的硬件随意性很大,Linux驱动的很难做到通用;本本里面的是ALC888 HD声卡,装了最新的alsa-driver 1.0.21,情况依旧,喇叭有声音,但是耳机就是没反应,也没那个选项有效;后来查看了一些帖子才知道,虽然是同一款驱动,但是有不同的挂载模式的参数,通常就是用来指定这类变化很大的接口等,有些帖子给出一大堆参数列表,说,在/etc/modprbe.d/alsa-base.conf里面更换不同的参数,然后重启测试……天啊,起码上百条的参数,要重启到哪个年月阿……稍微看了下,所谓的挂载参数就是传给modprobe的参数嘛,比如modprobe snd_hda_intel model=ooxx,只需要用不同的参数重新挂载snd_hda_intel,完全没必要重启阿……在Linlap找到一个AudioTester脚本,专门用来测试不同的模块挂载参数的,但是在Ubuntu下用也挺麻烦,正常模式下不让删除snd_hda_intel模块,只好启动到recover mode,手动挂载后运行这个脚本;终于测试到"lenovo-sky"这个参数能让耳机出声,证明还不是残废……但是进入alsamixer里面看,使用这个参数之后,只有寥寥几个选项,连录音都不见了……而且耳机跟喇叭是同时发声的,不能关闭喇叭……
后来想到,这个参数列表应该不是固定的,新的alsa里面应该会有新的参数,不知道有没有专用Acer的参数呢?因为看到原来的列表里面有acer跟acer-aspire,虽然两个没合适这款机器;grep了一下alsa-driver的源代码目录,发现sound/pci/hda/patch_realtek.c里面有一大堆acer xxxx,试了acer-aspire-4730g跟acer-aspire-4730g,设置成4ch/6ch模式后,终于能通过设置Surround让耳机出声,通过Front调整外放喇叭的声音!
Tags: 4736, Acer, Arch, Atheros, Headphone, Linux, Ubuntu, 内核模块, 耳机, 驱动
分类: IT视角, Programming 发布日期: 2009.09.20 星期天
先来一段他们的广告式简介:
广州技术沙龙,是由珠三角地区的 web、游戏开发人员自发组织的线下交流活动,计划每月举办一期,以主题演讲和松散交流为形式;吸引来自广州、珠海、深圳等珠三角城市的很多位技术人员参加活动,其中不乏来自网易、金山、腾讯、中国移动等公司的开发人员,活动举办后,大家通过 twitter、python-cn maillist 和 blog 持续交流,取得了比较好的线下交流效果。
https://groups.google.com/group/guangzhou-tech-party
第二期活动的两个主要演讲题目:
- 《深入 nginx 源码》 Zhu Zhaoyuan 广州梦境网络
- 《 MMOrpg 副本自动地图生成》 林伟 广州网易
我刚开始看到他们的题目预告时候,第一感觉是,啊,那么高深的东西,我去怎么听得懂阿……不过想到如果都是听自己熟悉的东西,那更不是浪费时间么,而且看了第一期录像,《选好业务与技术,单枪匹马做游戏》 (赖勇浩),感觉虽然不是自己感兴趣的题材,但是收获还是不少的,这是很难得的“基层人员”的信息啊!所以一早就报名参加了此次活动。
《深入 nginx 源码》让我了解到nginx内部代码的实现是如何精益求精,比如说处理HTTP Request时候的指令,GET、PUT等的指令,nginx里面可不是用C库里面的strcmp,而是自己写了比较函数(似乎是一个maroc),具体实现我没看清楚,但我估计是把指令的前两个char放入一个short里面来比较,这样只需在switch之类的处理时候,单比较就完成了!当然这可不是nginx性能的突出点,只是冰山一角的例子罢了。nginx自己实现了一个很巧妙的内存池,使用排序链来管理获得分配的内存(减少内存碎片,这点是lighttpd没有的),跟apahe相比,更加在进程处理上面的洁癖。
虽然我自己在机器上配置过nginx,但很难想象我会花时间去看其代码,但发现这么看确实能学到不少东西……
《游戏自动地图生成》这个题材,自己也没想过做游戏开发或者之类的,但是听小林介绍下去几种地图生成算法时,兴趣大增了;其提到一个“细胞自动机算法”觉得颇为经典,在在自动生成地图的整个过程里面也用的比较多。其实就是一个很现实化的思想,局部性原理;现实世界中,某个坐标跟它相邻坐标对应的物体,很大几率就是相同的;操作系统的磁盘调度、内存调度、缓存快写,通通都用到局部性原理,当请求了A地址的内容,A+1地址的内容很可能将会被访问到。其他如平滑连接随机点算法(集合、概率)、侵蚀算法、次优选择等等一大堆的思想,颇让我大开眼界。
收集一下资料吧:
广州技术沙龙第二期流程笔记
Ayou的nginx、Linux服务器配置笔记(推荐!很多很重要很实用的资料!)
Tags: Linux, nginx, 技术沙龙, 算法
分类: Programming, 单片机 发布日期: 2009.09.06 星期天

暑假之前就注意了LCD4Linux这个Project,简单说,这就是个硬件版conky的驱动服务,用户自己DIY各式各样的硬件屏幕,自己编写驱动、编写各种插件来控制输出到屏幕上的信息,LCD4Linux就是这样一个平台,也是一个geek味道非常浓郁的、可玩性相当高的一个Project。
图片里面是LCD4Linux项目页里面收集的部分人实现的一些屏幕,有像我这样一块小小的1602,也有用块10多寸的液晶屏作成很拉风的监控屏,甚至,挂一个户外广告那样的LED阵列,你也可以转换成VGA信号输出给大屏幕的电视机,或者弄个天线发射出外太空都是可能的……

这个项目的可玩性就在于硬件的多样性,很可能每个人实现的屏幕都不一样,而作为开源项目,geek们只需或多或少地修改一下别人的驱动就可让屏幕跑起来了。
我实现的这块,是用了一块通用AVR单片机,通过USB接口直接取电和传输的数据的架构,硬件和协议参考的是LCD2USB项目。其原来用的是atmega8芯片,而我手边只有atmega48,算是类似吧,但换换IO口还是在所难免的。
实现一个系统,同时也藉此了解一下相关的技术(不然还真的很难做得出来),首先是USB,USB我们天天在用,但是学校的《微机接口》之类的课程可从来不涉及这些“时髦”技术的,虽然USB已经流行了10多年了。通过V-USB库,在AVR单片机上实现USB设备还真没什么难度,只需要填写设备ID设备名称之类的,然后再实现协议处理函数就完了,在Linux下使用是直接支持,一插上运行lsusb就能认出(Win下需要另外装驱动)。我第一个实验USB就是接了几个二极管开关,用libusb的python binding, pyusb,很容易就控制几个灯。(想起The Big Bang Theory S1E9开头那一段,再import个SimpleHTTPServer,然后让单片机连接几个继电器,就能像他们那样让别人用浏览器来开关我的台灯了,哈!)
其实单纯几个LED都能够作为LCD4Linux的一个设备了,比如能够用来做邮件提醒、pidgin消息之类。同样是用V-USB,有个德国人做了个叫USB-LED-Fader的东东,同样是几个LED,人家可实现了每个灯在pwm控制下以独立的方式闪亮,要知道,atmega8只有两个pwm channel,而USB-LED-Fader里面没有用硬件pwm,而是用io口来输出的,为了实现独立波形,还实现了一个message queue,俨然一个操作系统了……所以他的固件编译出来4K多,即使我修改后也刷不进去mega48里面,就没得看看他的效果了。不过赞一下的是,这个项目虽然是玩具级别的,但是人家的电路、电路板、固件代码(注释)、文档、上位机控制(包括win版、win驱动)通通一应俱全,非常规范和详细,俨然一个商业项目。
将USB模块跟显示屏驱动模块合起来并没什么难度,几个月前我自己写过这个1602的驱动程序,虽然当时花了好几天,但实际上都只是很简单的几个函数。不过这次,因为接上USB后这块28针的mega48就没那么多io给我挥霍了,此前的驱动用的都是8位数据线,现在只能用4位,分两次传送。不过还好,这类HD44780的驱动几乎满地都是,一般外国人写的不像国内一些网站上面的,扔几个函数在那里就完事,LCD2USB的代码里面用的是Peter Fleury的LCD Library,封装得很漂亮,不过原来的代码只能讲4位数据线连接在一组io口的高四位上,而接上外置晶振后的mega48仅剩的带高位PortD,刚好又是几个pwm波输出,我打算另外再扩展协议让LCD2USB带有几个漂亮的提示灯,就重写了一下LCD的两个底层函数,当然不是仅仅重写,不然对不起原来那些漂亮的代码,用了宏定义来设置数据线是接在HIGHER_BIT or LOWER_BIT。
其实相比之下,LCD4Linux最精彩的地方在于它的驱动、插件的编写,新版里面其也支持了Python,意味着做个硬件版twitter器不是什么难事了!不过LCD4Linux本身的安装让我困扰了一天,大概作者没有时间吧,这个项目的主代码很几年没更新了,一个版本更新的跨幅有好几年,以致稍旧点的版本在新版本的内核里面编译不了,比如有个rdtscl的宏调用,在新内核里面被移除了……这个问题在LCD4Linux的SVN里面的版本倒是解决了,但是因为autotool的更新,编译过程又出错,折腾了半天,发现原来autoconf检查python的模块ac_python_devel 因为莫名的原因会让configure文件出错,下载一个新版的ax_python_devel.m4覆盖掉就好了。另外发现AUR里面的lcd4linux-svn包是“弃婴”,于是“收养”了回来更新,添加了个编译的patch,现在Archer们直接yaourt lcd4linux就可以编译安装了,O.O .
还是一句,LCD4Linux的可玩性非常高,说技术性嘛,不算高也不算低吧,召唤大家一起玩一起交流哈……
Tags: Arch, atmega, atmega48, AUR, AVR, LCD, LCD4Linux, Linux
分类: Unix/Linux 发布日期: 2009.06.02 星期二
此前的笔记《Linux程序已运行实体的检测以及其PID的获得》通过Linux里面的bash命令来获取正在运行的同名进程的pid,正如网友AzureSky提醒说实际上平常此类程序所用的方法都是文件锁,比如dhclient、apt-get系列、pacman诸如此类,都是通过往/var/run里面写入一个包含自身pid的xx.pid文件,同时加上排他锁,只要当前进程还在,新的进程就不可能再加锁,也就能检测出是否单实例了。(AzureSky博客另外整理出APUE的一个实现)
至于后台运行,都是通过fork来生成新进程,虽然还需要setsid等的调用以确保子进程正常运行,不过这里暂不详细讨论,重点关注文件排他锁和生成的后台进程的“规范方法“(参考《Unix环境高级编程 APUE 第二版》)。
整个过程是这样的:
- 打开文件;
- 获得该文件的锁的状态;
- 如果没有锁,则给该文件加上自己的锁并写入自己的pid*;否则获得锁着该文件的进程的pid
- 如果能够顺利加上锁,则生成子进程;子进程等待父进程退出后马上给文件加上自己的锁;
*其实写不写入pid对整个过程影响不大,只是惯例如此。
过程并不复杂,纠结的地方就是,文件锁是针对进程而言的,在生成后台进程的过程中,父进程和子进程虽然说拥有共同的文件描述字之类的资源,但由于是两个完全不同的进程,文件锁并不会继承过去。只有当父进程完全退出,失去对文件的锁操作后,子进程才能重新获得锁。
文件锁的调用fcntl函数的cmd参数里面有F_SETLK和F_SETLKW两个,后者是阻塞式的调用,就非常适合上述子进程等待父进程退出以获得锁的情形。
PT根据《APUE 2nd》F14.5、F14.6 整理出来的一份示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
| #include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#define LOCKFILE "/tmp/run/test.pid"
#define LOCKMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int lockfile; /* 锁文件的描述字 */
void flock_reg (); /* 注册文件锁 */
int program_running_check(); /* 锁控制函数 */
void daemon_init(); /* 转换到后台进程 */
int main()
{
//打开锁文件
lockfile = open (LOCKFILE, O_RDWR | O_CREAT , LOCKMODE);
if (lockfile < 0){
perror ("Lockfile");
exit(1);
}
// 检测可否获得锁
int mun;
if ( (mun = program_running_check())){
printf("Instance with pid %d running, just exitn", mun);
exit(1);
}
//转换到后台式运行
daemon_init();
printf("sleepingn");
while (1);
return 0;
}
void
flock_reg ()
{
char buf[16];
struct flock fl;
fl.l_start = 0;
fl.l_whence = SEEK_SET;
fl.l_len = 0;
fl.l_type = F_WRLCK;
fl.l_pid = getpid();
//阻塞式的加锁
if (fcntl (lockfile, F_SETLKW, &fl) < 0){
perror ("fcntl_reg");
exit(1);
}
//把pid写入锁文件
ftruncate (lockfile, 0);
sprintf (buf, "%ld", (long)getpid());
write (lockfile, buf, strlen(buf) + 1);
}
void
daemon_init()
{
pid_t pid;
if ( (pid = fork()) < 0) {
perror ("Fork");
exit(1);
}
//父进程,打印该信息后马上退出
if (pid) {
fprintf(stdout, "&&Info: Forked background with PID: [%d]n", pid);
exit(0);
}
//子进程,设置相关环境
setsid(); /* become session leader */
chdir("/"); /* change working directory */
umask(0); /* clear our file mode creation mask */
//子进程重新加锁
flock_reg ();
}
int
program_running_check()
{
struct flock fl;
fl.l_start = 0;
fl.l_whence = SEEK_SET;
fl.l_len = 0;
fl.l_type = F_WRLCK;
//尝试获得文件锁
if (fcntl (lockfile, F_GETLK, &fl) < 0){
perror ("fcntl_get");
exit(1);
}
//没有锁,则给文件加锁,否则返回锁着文件的进程pid
if (fl.l_type == F_UNLCK) {
flock_reg ();
return 0;
}
return fl.l_pid;
} |
Tags: Linux, Unix, 守护进程, 进程
分类: Unix/Linux 发布日期: 2009.06.01 星期一
似乎装了HAL的Arch就能自动挂在U盘了,然而U盘目录里面的中文文件全部是???,很明显是编码问题。我用的是en_US环境,不知道有没有关系。
网上不少说法是修改/etc/udev/rules.d/里面的挂载规则,抄了别人的脚本试了下,很不完善,删掉。
本来就能自动挂载了,只是编码问题而已,应该不用改rules吧!重新以编码问题搜索,终于看到解决方案:
运行gconf-editor(类似Win的注册表编辑器的东东,没有就装上),在System->Storage->vfat的mount_options里面添加一条“iocharset=utf8”,好,大功告成!
Tags: Arch, Linux, U盘
分类: Programming, Unix/Linux 发布日期: 2009.05.25 星期一
程序中经常需要有这么一个功能:只允许本程序的单个实例运行,即不能多次运行一个程序。检测某个进程是否在运行,在shell中可以很轻松的用命令ps -A|grep xxx找出来,但对于程序来说,该怎么检测呢?我参考了aecium程序的方法:同样调用ps -A|grep xxx。也许会存在更先进的方法,比如dbus、系统信号量之类的技术,总之这个不会是最好的方法,不过且看看其技巧。
首先要获得当前进程的名字以便传给grep,一般通过main的argv[0]可得到运行时的程序名,不过要注意的是,通过路径运行的程序如./a.out,argv[0]也是./a.out的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
| #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
void program_unique_check(const char* program)
{
FILE *fd;
pid_t id = 0;
char command[50] = {0};
char pid_num[50] = {0};
const char* program_name;
program_name = strrchr (program, '/');
//过滤得到程序的文件名
if (program_name)
++program_name;
else
program_name = program;
//组成执行的命令ps -Ao pid,comm|grep xxx
sprintf(command, "ps -Ao pid,comm|grep %s", program_name);
printf ("Command to excute: %s\n", command);
//以管道方式执行命令
if ( (fd = popen(command, "r")) == NULL ) {
perror("popen");
exit(EXIT_FAILURE);
}
//从管道读回执行结果,这里只为了取得PID,所以只读取前最多20个字符(PID不可能有那么长吧!)
fgets(pid_num, 20, fd);
printf ("Result :\n%s\n", pid_num);
//转换结果字符为整形数值
id = atoi(pid_num);
printf ("DETECTED PID: %d\n", id);
//判断是否自己
if (getpid() == id)
printf ("This's my self: %d\n", id);
else {
printf ("Here's one already running: %d\nI'll kill him!\n", id);
//SIGKILL信号,当然也可以是其他信号的
if ( kill (id, SIGKILL) == -1 ) {
perror("kill");
exit(EXIT_FAILURE);
}
}
}
int main (int argc, char**argv)
{
program_unique_check(argv[0]);
sleep (10);
return 0;
} |
本来还考虑,字符串传入atoi()要不要过滤,所以一开始还用了|awk '{print $1}'来给命令结尾,不过发现atoi只读取第一段有效数据来进行转换,就简化这点了。
ZDClient和ZLEVOClient都已经加入了运行实例检测的功能,-l参数可通过信号通知原运行程序离线。
Tags: Linux, 检测, 程序实例, 编程