搜索

Google
 

星期四, 六月 21, 2007

关于inotify

inotify是什么?用它能干些什么?这个问题我们还是首先从内核的文档开始吧--Documentation/filesystems/inotify.txt(说点题外话,内核文档虽然是没有任何格式的txt文档,给人的感觉却非常好,而且作者总是以最精炼的语言清楚地描述了相关的内容): a powerful yet simple file change notification system,通俗点说它是一个内核用于通知用户空间客户程序文件系统变化的系统,并且它是powerful yet simple的。

inotify的用户接口原型主要有以下3个:
初始化:int inotify_init(void);
添加监视对象:int inotify_add_watch(int fd, const char *path, uint32_t mask);
删除监视对象:int inotify_rm_watch(int fd, uint32_t wd);

内核文档里对于inotify_rm_watch的用户接口原型描述似乎有点问题,第2个参数写成了mask,实际上它应该是inotify_add_watch返回的watch descriptor。

根据文档描述可以看出,inotify使用大概分为以下几个步骤:
1、int fd = inotify_init(); 初始化inotify实例。
2、int wd = inotify_add_watch(fd, path, mask); 添加监视对象,这里的mask是一个或多个事件的位标记集合,具体的事件定义可参考(linux/inotify.h)或者(sys/inotify.h),前者为linux内核头文件,后者为glibc提供的头文件。
3、size_t len = read(fd, buf, BUF_LEN); 读取事件数据,buf应是一个指向inotify_event结构数组的指针。不过要注意的是inotify_event的name成员长度是可变的,这个问题后面再解释。
4、已经存在的监视对象可通过int ret = inotify_rm_watch(fd, wd);来删除。

下面我们来看一个示例:

#include <stdio.h>
#include <unistd.h>
#include <sys/select.h>
#include <errno.h>
#include <sys/inotify.h>

static void
_inotify_event_handler(struct inotify_event *event)
{
printf("event->mask: 0x%08x\n", event->mask);
printf("event->name: %s\n", event->name);
}

int
main(int argc, char **argv)
{
if (argc != 2) {
printf("Usage: %s <file/dir>\n", argv[0]);
return -1;
}

unsigned char buf[1024] = {0};
struct inotify_event *event = {0};
int fd = inotify_init();
int wd = inotify_add_watch(fd, argv[1], IN_ALL_EVENTS);

for (;;) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
if (select(fd + 1, &fds, NULL, NULL, NULL) > 0) {
int len, index = 0;
while (((len = read(fd, &buf, sizeof(buf))) < 0) && (errno == EINTR));
while (index < len) {
event = (struct inotify_event *)(buf + index);
_inotify_event_handler(event);
index += sizeof(struct inotify_event) + event->len;
}
}
}

inotify_rm_watch(fd, wd);

return 0;
}


由以上代码可以看出inotify_init返回的file descriptor是可以用select或者poll进行I/O复用的。由于inotify_event长度是可变的,因此在读取inotify_event数组内容的时候需要动态计算下一个事件数据的偏移量(index += sizeof(struct inotify_event) + event->len),len成员即name成员的长度。

在实际测试过程中,通过运行以上的测试程序监视一个文件,还遇到过两个奇怪的现象:用vim编辑那个被监视的文件,修改并保存,触发的是IN_DELETE_SELF和IN_MOVE_SELF事件而不是我们所期望的IN_MODIFY事件;再次修改并保存的时候不再有任何事件发生。希望能给看官一个教训,其实这是由于vim的工作机制引起的,vim会先将源文件复制为另一个文件,然后在另一文件基础上编辑(一般后缀名为swp),保存的时候再将这个文件覆盖源文件,因此会出现上述的第一个现象,第二个现象是因为原来的文件已经被后来的新文件代替,因此监视对象所监视的文件已经不存在了,所以自然不会产生任何事件。

另外,内核文档第四部分介绍了inotify的背景以及设计思路,不可不看:

Q: What is the design decision behind not tying the watch to the open fd of
the watched object?

A: Watches are associated with an open inotify device, not an open file.
This solves the primary problem with dnotify: keeping the file open pins
the file and thus, worse, pins the mount. Dnotify is therefore infeasible
for use on a desktop system with removable media as the media cannot be
unmounted. Watching a file should not require that it be open.

Q: What is the design decision behind using an-fd-per-instance as opposed to
an fd-per-watch?

A: An fd-per-watch quickly consumes more file descriptors than are allowed,
more fd's than are feasible to manage, and more fd's than are optimally
select()-able. Yes, root can bump the per-process fd limit and yes, users
can use epoll, but requiring both is a silly and extraneous requirement.
A watch consumes less memory than an open file, separating the number
spaces is thus sensible. The current design is what user-space developers
want: Users initialize inotify, once, and add n watches, requiring but one
fd and no twiddling with fd limits. Initializing an inotify instance two
thousand times is silly. If we can implement user-space's preferences
cleanly--and we can, the idr layer makes stuff like this trivial--then we
should.

There are other good arguments. With a single fd, there is a single
item to block on, which is mapped to a single queue of events. The single
fd returns all watch events and also any potential out-of-band data. If
every fd was a separate watch,

- There would be no way to get event ordering. Events on file foo and
file bar would pop poll() on both fd's, but there would be no way to tell
which happened first. A single queue trivially gives you ordering. Such
ordering is crucial to existing applications such as Beagle. Imagine
"mv a b ; mv b a" events without ordering.

- We'd have to maintain n fd's and n internal queues with state,
versus just one. It is a lot messier in the kernel. A single, linear
queue is the data structure that makes sense.

- User-space developers prefer the current API. The Beagle guys, for
example, love it. Trust me, I asked. It is not a surprise: Who'd want
to manage and block on 1000 fd's via select?

- No way to get out of band data.

- 1024 is still too low. ;-)

When you talk about designing a file change notification system that
scales to 1000s of directories, juggling 1000s of fd's just does not seem
the right interface. It is too heavy.

Additionally, it _is_ possible to more than one instance and
juggle more than one queue and thus more than one associated fd. There
need not be a one-fd-per-process mapping; it is one-fd-per-queue and a
process can easily want more than one queue.

Q: Why the system call approach?

A: The poor user-space interface is the second biggest problem with dnotify.
Signals are a terrible, terrible interface for file notification. Or for
anything, for that matter. The ideal solution, from all perspectives, is a
file descriptor-based one that allows basic file I/O and poll/select.
Obtaining the fd and managing the watches could have been done either via a
device file or a family of new system calls. We decided to implement a
family of system calls because that is the preferred approach for new kernel
interfaces. The only real difference was whether we wanted to use open(2)
and ioctl(2) or a couple of new system calls. System calls beat ioctls.

星期日, 六月 10, 2007

rs422在linux跟我开了个玩笑

很久没有更新blog了,就跟抽烟一样,如果长时间不抽的话也就不想抽了,看来这是一个不好的现象,不过长时间的沉默也说明了自己这段时间在技术没有什么积累。罢了,今天的blog就记录这段时间来比较郁闷的事情。

这个项目的开发就像当年初中的长跑一样,前几圈劲头十足信心满怀,接下来的情况我想大部分人跟我一样,慢慢地感觉有点累,再后来压力越来越大,越来越感觉大脑缺氧呼吸困难,到后来已经身心疲累。人这一生从出生开始就背负了责任,要么为责任活着要么超越责任为理想活着,所以有人活得辛苦而无趣,有人轻松而超然。有点跑题了,还是说一下前几天遇到的技术问题。

客户方有一外部设备是N年前购买的,一直用于原来的系统中,这次需要在本项目中使用此外设,关于这个外设的文档早已缺失,唯一可以参考的就是一个windows下的动态链接库源代码(不过这也是最重要的参考资料,候大侠一本书上不是也说“源码面前了无秘密”嘛),于是参考此代码写了一个windows下的测试程序很顺利地测试通过,测试代码如下:

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int
main(int argc, char **argv)
{
HANDLE h_com;
unsigned char addr = 0x01;
unsigned char buf[10];
int i;
DCB dcb;
COMMTIMEOUTS timeouts;
DWORD n;

if (argc != 2) {
printf("%s <comdev>\n", argv[0]);
return -1;
}

h_com = CreateFile(argv[1], GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, NULL);
if (h_com == INVALID_HANDLE_VALUE) {
printf("Initialize COM device failed\n");
return -1;
}

GetCommState(h_com, &dcb);
dcb.BaudRate = 9600;
dcb.ByteSize = 8;
dcb.Parity = MARKPARITY;
dcb.StopBits = ONESTOPBIT;
SetCommState(h_com, &dcb);

GetCommTimeouts(h_com, &timeouts);
timeouts.ReadTotalTimeoutConstant = 10;
SetCommTimeouts(h_com, &timeouts);

WriteFile(h_com, &addr, sizeof(addr), &n, NULL);

Sleep(1);
dcb.Parity = SPACEPARITY;
SetCommState(h_com, &dcb);
memcpy(buf, "\x02\x85\x83\04", 4);
WriteFile(h_com, buf, 4, &n, NULL);

Sleep(2);
ReadFile(h_com, buf, sizeof(buf), &n, NULL);
printf("read %d bytes\n", n);

for (i = 0; i < n; ++i)
printf("%02x ", buf[i]);
printf("\n");

return 0;
}

由此代码可以看出通信过程大概是这样的:将串口设置为8M1发送地址,然后将串口设置更改为8S1发送请求数据,再然后接收数据,看起来还是很简单的。接下来很快地写好了linux下的测试程序,源代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>

int
main(int argc, char **argv)
{
if (argc != 2) {
printf("Usage: %s <comdev>\n", argv[0]);
return -1;
}

int fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
printf("Initialize COM device failed.\n");
return -1;
}

struct termios options;
if (tcgetattr(fd, &options) == -1)
return -1;

cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);

options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8 | CLOCAL | CREAD | CMSPAR | PARODD;
options.c_cflag &= CSTOPB;
options.c_iflag |= INPCK;
options.c_iflag &= ~(IXON | IXOFF | IXANY);
options.c_oflag &= ~OPOST;
options.c_lflag &= ~(ECHO | ECHOE | ICANON | ISIG);
tcflush(fd, TCIFLUSH);
printf("tcsetattr result: %d\n", tcsetattr(fd, TCSANOW, &options));

char addr = 0x01;
if (write(fd, &addr, 1) == -1)
goto failed;

usleep(1000);

options.c_cflag &= ~PARODD;
printf("tcsetattr result: %d\n", tcsetattr(fd, TCSADRAIN, &options));

usleep(1000);

unsigned char buf[10];
memcpy(buf, "\x02\x85\x83\x04", 4);

if (write(fd, buf, 4) == -1)
goto failed;

usleep(10000);

ssize_t read_n;
int i;
read_n = read(fd, buf, sizeof(buf));
printf("result: %d\n", read_n);
for (i = 0; i < read_n; ++i)
printf("%02X ", buf[i]);
printf("\n");

close(fd);
return 0;

failed:
close(fd);
return -1;
}

虽然Mark Parity和Space Parity在Posix中并未定义,但是在linux下通过CMSPAR仍然可以实现,tcsetattr的man pages可以看到对CMSPAR的描述(),可是反复尝试仍然有问题,后来一个完全不懂linux开发的同事问了我设置串口各行代码的意思,并通过tcsetattr的man pages,一个一个地组合这些标记,居然成功了!结果出人意料,且看如下代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <termios.h>

int
main(int argc, char **argv)
{
if (argc != 2) {
printf("Usage: %s <comdev>\n", argv[0]);
return -1;
}

int fd = open(argv[1], O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
printf("Initialize COM device failed.\n");
return -1;
}

struct termios options;

memset(&options, 0, sizeof(options));

cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);

options.c_cflag = CS8 | CLOCAL | CREAD | CSTOPB | CMSPAR;
options.c_iflag = INPCK;
options.c_oflag = 0;
options.c_lflag = 0;
tcflush(fd, TCIFLUSH);
printf("tcsetattr result: %d\n", tcsetattr(fd, TCSANOW, &options));

char addr = 0x01;
if (write(fd, &addr, 1) == -1)
goto failed;

usleep(1000);

options.c_cflag |= PARENB | PARODD;
printf("tcsetattr result: %d\n", tcsetattr(fd, TCSADRAIN, &options));

usleep(1000);

unsigned char buf[10];
memcpy(buf, "\x02\x85\x83\x04", 4);

if (write(fd, buf, 4) == -1)
goto failed;

usleep(10000);

ssize_t read_n;
int i;
read_n = read(fd, buf, sizeof(buf));
printf("result: %d\n", read_n);
for (i = 0; i < read_n; ++i)
printf("%02X ", buf[i]);
printf("\n");

close(fd);
return 0;

failed:
close(fd);
return -1;
}

想不到抛开CMSPAR不算8M1看起来是8N2,而8S1则看起来是8O2。。。

星期日, 四月 15, 2007

C代码中如何得到python脚本异常时的traceback信息

在软件项目的开发过程中,我们总是试图让程序能够适应更多的应用环境以及业务流程,不管你对于需求的了解如何准确,也不管你做了有多么充分的估计,但有很多情况仍然让你无法应付,比如:需求是会变化的;维护项目的人不一定都能用C/C++写出没有内存问题的代码等等。

让软件系统能够适应更多变化的方法有很多种,高度的抽象、动态链接技术等等都是一直以来被大家采用较广的方法,那么今天我们要讨论的是脚本引擎的嵌入问题。通常我更喜欢c代码加上python脚本引擎的结构,python的好处就不多说了。不过在C中嵌入python脚本引擎调用之后也有一些非常麻烦的地方,比如不便于调试,因为我们的宿主应用程序必然会为python脚本wrap一些module、class、function等等,因此这带来了调试的难度,有时候仅仅依赖print是一件非常低效的事,那么我们如何得到python脚本在异常时的traceback情况呢?比如代码出现异常到底是在哪个脚本文件中,到底是哪行代码出了问题?错误又是什么呢?我们先来看看下面的函数:

#include 
#include
#include
#include

void
process_python_exception(void)
{
char buf[512], *buf_p = buf;
PyObject *type_obj, *value_obj, *traceback_obj;
PyErr_Fetch(&type_obj, &value_obj, &traceback_obj);
if (value_obj == NULL)
return;

if (!PyString_Check(value_obj))
return;

char *value = PyString_AsString(value_obj);
size_t szbuf = sizeof(buf);
int l;
PyCodeObject *codeobj;

l = snprintf(buf_p, szbuf, _("Error Message:\n%s"), value);
buf_p += l;
szbuf -= l;

if (traceback_obj != NULL) {
l = snprintf(buf_p, szbuf, _("\n\nTraceback:\n"));
buf_p += l;
szbuf -= l;

PyTracebackObject *traceback = (PyTracebackObject *)traceback_obj;
for (;traceback && szbuf > 0; traceback = traceback->tb_next) {
codeobj = traceback->tb_frame->f_code;
l = snprintf(buf_p, szbuf, "%s: %s(# %d)\n",
PyString_AsString(codeobj->co_name),
PyString_AsString(codeobj->co_filename),
traceback->tb_lineno);
buf_p += l;
szbuf -= l;
}
}

message_error_dialog_show(buf);

Py_XDECREF(type_obj);
Py_XDECREF(value_obj);
Py_XDECREF(traceback_obj);
}

PyErr_Fetch用来获取异常对象,并且同时可以得到traceback对象,traceback其实是一个PyTracebackObject结构体,可以在python的头文件traceback.h中找到,PyTracebackObject其实也是一个单向链表,可以通过其tb_next成员来枚举,其tb_frame则是一个_frame结构体,在frameobject.h头文件中可以看到,其中f_code就是我们需要的PyCodeObject结构体,PyCodeObject中就可以得到co_name和co_filename这两个关键的描述,一个是错误信息另一个是文件名称,PyTracebackObject的tb_lineno就是出错的行号,有了这些数据我们调试还有困难吗?

星期五, 三月 30, 2007

星期四, 三月 29, 2007

生死边缘的轮回 - reiserfs文件系统的数据恢复

昨天晚上给客户一个应用定制裁减linux系统的时候,发生了一件非常不幸的事,我的data目录被我无意给rm -rf删除掉了,那里面存放着我的所有项目的代码和文档,还有很多其它重要的东西。看见那个目录突然什么都没有的时候那种感觉简直无法形容,由于长期出差一直没有机会给公司保留备份,还好今天恢复了大部分重要的文档和代码。希望跟我一样倒霉的朋友能以此为鉴,删除文件时一定要小心,并且经常备份重要的代码和文档。

网上有两篇文章对reiserfs文件系统的数据恢复做了详细的介绍,ReiserFS undelete/data recovery HOWTO和Reiserfs filesystem recovery,另外提供几点建议:
  1. 在误删除之后切记不要再进行任何操作,立即关机,做好准备再来做数据恢复!
  2. 准备好一块大硬盘或移动硬盘(最好使用usb 2.0的硬盘盒子),第一时间用dd把误删除数据的分区完整备份一份。恢复也最好针对这个image文件,直到重要的数据完全找到再处理该分区,如果失败了还可以借助专业数据恢复公司来进行数据恢复。
  3. 您在恢复时一定记得给reiserfsck加上-l参数,生成日志文件是非常重要的,如果文件太多reiserfsck并不能100%地恢复您的数据,日志文件里会告诉您哪些文件没有被正确地恢复。再次提醒您经常备份自己重要的数据!!!
顺便赞叹一下reiserfs作者,reiserfs确实是一个非常优秀的文件系统,我54G容量的分区dd到移动硬盘时间不超过1小时,数据恢复时间不超过30分钟,并且最终重要的数据基本上都得以恢复!

星期六, 三月 17, 2007

beryl/compiz的ontop补丁

用beryl/compiz的时候有个比较遗憾的地方,那就是窗口没有了ontop功能,也就是窗口置顶,不过给libwnck打上补丁就可以解决这个问题了。

补丁地址:libwnck补丁

星期一, 三月 12, 2007

GtkScrolledWindow滚动条问题

在使用GtkTreeView时,用GtkScrolledWindow来添加滚动条,但列表(或树)中的数据行在不断得更新(增加),而垂直滚动条默认情况下不能自动往下滚动,以显示最新的数据行,而是始终停在top的位置,针对此问题有什么方法可以解决呢?

每次增加数据行之后,得到最后一行的path,需要手动调用gtk_tree_view_scroll_to_cell,滚动到最后的地方。如果不想手动 调用,可以监听 model 的 row-inserted,在该signal callback中gtk_tree_view_scroll_to_cell,如果大量迅速的增加新行的话,速度会受影响,可以跟延时结合减少scroll的频率。

星期日, 三月 11, 2007

强悍的回复帖

从CSDN主页上偶尔看到了一篇帖子,于是进去看了一下,十年MFC经历认识的Microsoft技术,楼主的行文风格不错,于是耐心地看了下去,一来觉得楼主知识系统全面值得学习,二来楼主的文字功底也颇为深厚,这种散文式的技术帖即使用来消遣也不错。不过没想到的是后来的一个回复帖真的让我捧腹大笑久久不能平静^_^。。。

逐句地看完这个帖子以后,我的心久久不能平静,震撼啊!为什么会有如此好的帖子!我纵横网络bbs多年,自以为再也不会有任何帖子能打动我,没想到今天看到了如此精妙绝伦的这样一篇帖子。楼主,是你让我深深地理解了‘人外有人,天外有天’这句话。谢谢侬!在看完这帖子以后,我没有立即回复,因为我生怕我庸俗不堪的回复会玷污了这网上少有的帖子。但是我还是回复了,因为觉得如果不能在如此精彩的帖子后面留下自己的网名,那我死也不会瞑目的!能够在如此精彩的帖子后面留下自己的网名是多么骄傲的一件事啊!

楼主,请原谅我的自私!我知道无论用多么华丽的辞藻来形容楼主您帖子的精彩程度都是不够的,都是虚伪的,所以我只想说一句:您的帖子太好看了!我愿意一辈子的看下去!这篇帖子构思新颖,题材独具匠心,段落清晰,情节诡异,跌宕起伏,主线分明,引人入胜,平淡中显示出不凡的文学功底,可谓是字字珠玑,句句经典,是我辈应当学习之典范。就小说艺术的角度而言,这篇帖子不算太成功,但它的实验意义却远远大于成功本身。正所谓:“一马奔腾,射雕引弓,天地都在我心中!”楼主真不愧为无厘界新一代的开山怪!

星期五, 三月 09, 2007

如何方便控制笔记本触摸板

笔记本的鼠标触摸板我基本上很少用,比起外接鼠标还是没那么方便灵活,何况写程序的时候基本上很少用鼠标,但是笔记本的触摸板却在写程序的时候经常搞得鼠标指针胡乱飘移,非常影响键盘输入的准确性。

在linux下控制触摸板必须得使用2.6.x内核,大致有几件事要做:正确配置内核、安装synaptics驱动、正确配置xorg.conf。

1、配置内核




Linux Kernel Configuration: Enable synaptics support
Device Drivers --->
   Input Device Support --->
<*> Event Interface
[*] Mouse --->

<*> PS/2 mouse


2、安装synaptics,在gentoo下直接emerge synaptics即可。

3、配置xorg.conf,首先看看你的输入设备信息,我机器上的输出信息如下:

/home/debianl $ cat /proc/bus/input/devices
I: Bus=0011 Vendor=0001 Product=0001 Version=ab41
N: Name="AT Translated Set 2 keyboard"
P: Phys=isa0060/serio0/input0
S: Sysfs=/class/input/input0
H: Handlers=kbd event0
B: EV=120013
B: KEY=4 2000000 3802078 f840d001 feffffdf ffefffff ffffffff fffffffe
B: MSC=10
B: LED=7

I: Bus=0011 Vendor=0002 Product=0007 Version=0000
N: Name="SynPS/2 Synaptics TouchPad"
P: Phys=isa0060/serio4/input0
S: Sysfs=/class/input/input1
H: Handlers=mouse0 event1
B: EV=b
B: KEY=6420 0 70000 0 0 0 0 0 0 0 0
B: ABS=11000003

I: Bus=0003 Vendor=046d Product=c016 Version=0340
N: Name="Logitech Optical USB Mouse"
P: Phys=usb-0000:00:1d.1-1/input0
S: Sysfs=/class/input/input2
H: Handlers=mouse1 event2
B: EV=7
B: KEY=70000 0 0 0 0 0 0 0 0
B: REL=103

然后配置xorg.conf,加入TouchPad的Section内容,并在ServerLayout中加入InputDevice "TouchPad" "AlwaysCore",以下是我的xorg.conf配置:

Section "ServerLayout"
Identifier "X.org Configured"
Screen 0 "Screen0" 0 0
InputDevice "Mouse0" "CorePointer"
InputDevice "Keyboard0" "CoreKeyboard"
InputDevice "TouchPad" "AlwaysCore"
EndSection

Section "Files"
RgbPath "/usr/share/X11/rgb"
ModulePath "/usr/lib/xorg/modules"
FontPath "/data/fonts/"
FontPath "/usr/share/fonts/misc/"
FontPath "/usr/share/fonts/TTF/"
FontPath "/usr/share/fonts/OTF"
FontPath "/usr/share/fonts/Type1/"
FontPath "/usr/share/fonts/CID/"
FontPath "/usr/share/fonts/100dpi/"
FontPath "/usr/share/fonts/75dpi/"
EndSection

Section "Module"
Load "glx"
Load "extmod"
Load "xtrap"
Load "record"
Load "dbe"
Load "dri"
Load "freetype"
Load "type1"
EndSection

Section "InputDevice"
Identifier "Keyboard0"
Driver "kbd"
EndSection

Section "InputDevice"
Identifier "Mouse0"
Driver "mouse"
Option "Protocol" "auto"
Option "Device" "/dev/input/mice"
Option "ZAxisMapping" "4 5 6 7"
EndSection

Section "InputDevice"
Identifier "TouchPad"
Driver "synaptics"
Option "Device" "/dev/input/mouse0"
Option "Protocol" "auto"
Option "SHMConfig" "on"
EndSection

Section "Monitor"
Identifier "Monitor0"
VendorName "Monitor Vendor"
ModelName "Monitor Model"
EndSection

Section "Device"
Identifier "Card0"
Driver "nvidia"
VendorName "nVidia Corporation"
BoardName "Unknown Board"
BusID "PCI:1:0:0"
Option "Accel" "True"
Option "RenderAccel" "True"
EndSection

Section "Screen"
Identifier "Screen0"
Device "Card0"
Monitor "Monitor0"
Option "AddARGBGLXVisuals" "true"
SubSection "Display"
Viewport 0 0
Depth 1
EndSubSection
SubSection "Display"
Viewport 0 0
Depth 4
EndSubSection
SubSection "Display"
Viewport 0 0
Depth 8
EndSubSection
SubSection "Display"
Viewport 0 0
Depth 15
EndSubSection
SubSection "Display"
Viewport 0 0
Depth 16
EndSubSection
SubSection "Display"
Viewport 0 0
Depth 24
EndSubSection
EndSection

Section "Extensions"
Option "Composite" "enable"
EndSection

现在你应该就可以使用synclient来配置各项参数了,也可以禁用触摸板,如果你用gnome的话可以安装一个gsynaptics,图形化的配置界面更易用点。

linux视频转换: mencoder

在网上发现一篇讲解利用mplayer的mencoder转换视频的文章,刚好适用我简陋的mp4转贴一下^_^,原文网址:Linux下的视频转换

制作适合在智能手机和PDA上观看的mpeg4视频。
Linux上有一个很强大的视频音频转换软件,就是Mplayer自带的mencoder (MPlayer's Movie Encoder)。mencoder就象是一台全手动的照相机,可调整的选项非常多,不过这儿只是把最常见的情况说一下。

转换avi文件,并把字幕内嵌到视频中。首先假设一下下列的条件:
文件名:video.avi
字幕文件名:video.srt
目标文件:new.avi
目标文件格式:mpeg4
目标文件视频码率:200
目标文件音频码率:64
目标文件分辨率: 320:240
制作内嵌字幕所需的字体:simsun.ttf
(上面各项都可以根据实际情况进行调整)
转换命令如下:

mencoder -oac mp3lame -lameopts vbr=3:br=64 -ovc lavc -lavcopts vcodec=mpeg4:mbd=1:vbitrate=200 -sub video.srt -o new.avi -font simsun.ttf video.avi -subcp cp936 -subfont-text-scale 4 -vf scale=320:240
各选项的含义:
-oac 编码文件的音频部分。这儿是用lame将音频encode成mp3,即mp3lame。其他可用的选项可以调用mencoder的man page查看。
-lameopts 顾名思义,即lame选项,这儿只需定义一下码率就可以了。
vbr 设定音频码率的方法,格式为vbr=<0-4>

0 cbr average bitrate
1 mt
2 rh constant bitrate Also forces CBR mode encoding on subsequent ABR presets modes.
3 abr
4 mtrh

在这儿用的是3,abr。
br 就是设定我们所需要的码率值,格式为br=<0-1024>,只能在vbr为0和3的情况下才能使用该选项。
-ovc 编码文件的视频部分。主要有以下几个选项

-ovc copy
不进行编码,只是复制视频流
-ovc divx4
编码成DivX4/DivX5
-ovc raw
编码成任意不压缩的格式(用‘-vf format’设定具体的格式)
-ovc lavc
使用libavcodec进行编码

-lavcopts 就是libavcodec的选项。
vcodec=使用指定的视频编码,下面列一下几个主要的值

h264
H.264
h263
H.263
h263p
H.263+
mpeg4
MPEG-4 (DivX 4/5)
msmpeg4
DivX 3
msmpeg4v2
MS MPEG4v2
wmv1
Windows Media Video, version 1 (又称 WMV7)
wmv2
Windows Media Video, version 2 (又称 WMV8)
rv10
旧的RealVideo格式
mpeg1video
MPEG-1 video
mpeg2video
MPEG-2 video

mbd 决定视频宏块的算法,这儿只需要mbd=1即可。其余的可以查看man page。
vbitrate 设定视频的码率(默认为800)。
-sub 设定字幕文件
-o 目标视频文件
-font 制作内嵌字幕所需字体的路径
-subcp 字幕的编码,简体中文就是cp936
-subfont-text-scale 字幕字体的大小
-vf scale 视频的分辨率
如果不需要将字幕内嵌入视频文件,只需要去掉-sub、-font、-subcp、-subfont-text-scale这几个选项。将rmvb转换成mpeg4也是如此。