Linux电子收款机

发布时间:2024-05-25 19:41:26 作者:汉语成语

Linux电子收款机以使用Linux操作系统、并口打印机的电子收款机为平台,将打印机设备视为文件,通过对该文件的写操作来实现打印功能。通常情况下,对文件系统的监控是通过系统调用劫持来实现的。但是1)Linux2.6版本之后的内核,系统调用表的地址已经不能导出,系统调用劫持的实现难度加大;2)劫持sys_write系统调用后,所有的文件写入操作都会被劫持,对系统的性能有较大影响;3)修改后的打印数据必须存入销售软件进程的用户内存空间,才能调用文件驱动模块write函数将其打印出来。而侵入销售软件进程将大大降低系统的独立性和可靠性。

进程间通信

首先需要解决的就是内核态与用户态的进程间通信(interprocesscommunicatiON,IPC)。而在各种IPC方法中,最适合此处设计需要的就是netlinksocket技术。

Netlinksocket最早出现于Linux2.2版的内核中,并在2.4版以后的版本中作为主要的内核与用户空间的通信方式而被广泛使用。相对于系统调用、ioctl以及proc文件系统等IPC方法而言,它具有简单易用、异步通信(适合大数据传输)、无编译依赖(可模块实现)、支持多播、支持内核发起会话等优点。其中“异步通信、无编译依赖、支持内核发起会话”

这三点正是本系统需要的关键特性,也是选用该技术的最主要原因。

Netlinksocket的通信依据是一个对应于进程的标识,一般定为该进程的ID。当通信的一端处于中断过程时,该标识为0。当使用netlinksocket进行通信,通信的双方都是用户态进程,则使用方法类似于消息队列。但通信双方有一端是中断过程,使用方法则不同。Netlinksocket的特点是对中断过程的支持,它在内核空间接收用户空间数据时不再需要用户自行启动一个内核线程,而是通过另一个软中断调用用户事先指定的接收函数,这样就可以保证数据接收的实时性。

当netlinksocket用于内核空间与用户空间的通信时,在用户空间的创建方法和一般套接字使用类似,但内核空间的创建方法则不同。在内核模块中使用netlink_kernel_create()函数创建socket时需要指明接收函数。之后用户空间进程创建socket,并将通信标识(一般是该进程的ID)发送到内核空间。这样内核空间获得了用户空间进程的通信标识后就可以进行通信了。

打印进程

当收到电子收款机的销售软件向并口打印机发出的打印请求时,内核态的并口打印模块需在将数据发送给用户态的守护进程之后阻塞打印请求进程。并且,当且仅当接收到守护进程的返回数据时,才会唤醒打印请求进程完成打印。

如何实现打印进程的阻塞及唤醒就是一个关键技术点。因为电子收款机只配备一个打印机、不需要复杂的互斥技术,所以只要使用“简单睡眠”就可以达到这个目标。

write操作

Linux操作系统将设备看作文件,每个Linux的设备驱动程序都定义了一个file_operation结构,结构中的各个成员是驱动模块中定义函数的指针,通过这些函数具体实现对文件的open,read,write等操作。因此,只要将并口打印驱动模块的file_operation结构常量——lp_fops的write成员的值由lp_write替换为指向拦截函数的指针就能实时地拦截并口打印机的打印操作。

这里需要实现两个关键函数:

1)lp_write_from_kernellp_write_from_kernel函数实现内核空间的缓冲区数据的打印功能。来自守护进程的修改后打印数据是保存在内核空间的,因此不能调用原有的lp_write函数进行打印。具体的实现可依照lp_write,只要将调用copy_from_user函数的地方改为调用memcpy函数即可。

2)lp_interceptlp_intercept函数函数用于替换lp_write,拦截并口打印驱动的write操作,实现打印数据截取与修改:当电子收款机的销售软件调用并口打印驱动的write函数时,将写缓冲区的打印数据发送给守护进程;待守护进程返回修改后的打印数据(附加了税控码),调用lp_write_from_kernel将其打印出来。