搜档网
当前位置:搜档网 › LINUX系统中断服务下半部之tasklet详解

LINUX系统中断服务下半部之tasklet详解

LINUX系统中断服务下半部之tasklet详解
LINUX系统中断服务下半部之tasklet详解

【摘要】本文详解了中断服务下半部之tasklet实现机制。介绍了tasklet链表的组织形式tasklet_vec,在此基础之上分析了tasklet执行流程。最后介绍了t asklet相关的API,如何编写自己的tasklet处理程序及定义一个tasklet对象并向内核提交等待调度运行。

【关键字】中断下半部,tasklet,tasklet_vec,tasklet_schedule,TASKLET_ SOFTIRQ

1tasklet概述

tasklet是利用软中断实现的一种下半部机制。tasklet和软中断在本质上很相似,行为表现也相近,选择到底是用软中断还是tasklet其实很简单:tasklet内部对软中断进行了封装,外部接口更简单,锁保护也要求较低。

下半部和推后执行的工作,软中断的使用者屈指可数。它只在那些执行频率很高和连续性要求很高的情况下才需要。

因为tasklet是通过软中断实现的,所以它们本身也是软中断。Tasklet有两类软中断代表:HI_SOFTIRQ和TASKLET_SOFTIRQ。这两者之间惟一的实际区别在于HI_SOFTIRQ类型的软中断先于TASKLET_SOFTIRQ类型的软中断执行。

2Tasklet的组织形式

2.1tasklet_struct定义

tasklet由tasklet_struct结构表示。每个结构体单独代表一个tasklet,它在< include/linux/interrupt.h>中定义:

260/* Tasklets --- multithreaded analogue of BHs.

262Main feature differing them of generic softirqs: tasklet is running only on one CPU simultaneously.

265Main feature differing them of BHs: different tasklets may be run simultaneously on different CPUs.

268Properties:

269* If tasklet_schedule() is called, then tasklet is guaranteed to be e xecuted on some cpu at least once after this.

271* If the tasklet is already scheduled, but its excecution is still not 272 started, it will be executed only once.

273* If this tasklet is already running on another CPU (or schedule i s called

274from tasklet itself), it is rescheduled for later.

275* Tasklet is strictly serialized wrt itself, but not wrt another taskle ts.If client needs some intertask synchronization, he makes it with spinlocks.

278*/

280struct tasklet_struct

281{

282struct tasklet_struct *next;

283unsigned long state;

284atomic_t count;

285void (*func)(unsigned long);

286unsigned long data;

287};

next:链表中的下一个tasklet;

state:tasklet的状态;

count:引用计数器;

func:tasklet处理函数;

data:给tasklet处理函数的参数

state成员只能在0、TASKLET_STATE_SCHED和TASKLET_STATE_RUN 之间取值。

TASKLET_STATE_SCHED表明tasklet已被调度,正准备投入运行,TASK LET_STATE_RUN表明该tasklet正在某CPU上运行。TASKLET_STATE_RUN 只有在多处理器的系统上才会作为一种优化来使用,单处理器系统任何时候都清楚单个tasklet是不是正在运行。

count成员是tasklet的引用计数器。如果它不为0,则tasklet被禁止,不允许执行;只有当它为0时,tasklet才被激活,并且在被设置为TASKLET_STAT E_SCHED状态时,该tasklet才能够执行。

2.2Tasklet队列tasklet_vec

已调度的tasklet(等同于被触发的软中断))a存放在两个单处理器数据结构:t asklet_vec (普通tasklet)和tasklet_hi_vec(高优先级的tasklet)中。这两个数据结构都是由tasklet_struct结构体构成的链表。链表中的每个tasklet_struct代表一个不同的tasklet。

333struct tasklet_head

334{

335 struct tasklet_struct *list;

336};

337

340static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec) = { NULL };

341static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec) = { NUL L };

tasklet由tasklet_schedule()和tasklet_hi_schedule()函数进行调度,它们接受一个指向tasklet_struct结构的指针作为参数。tasklet_schedule()将此tasklet添加到当前CPU的tasklet_vec链表的头部,并置上TASKLET_STATE_SCHED标识,

然后置软中断触发表示,等待调度软中断时再执行tasklet_vec中所有注册的tas klet。

3检查当前tasklet的运行状态

在SMP机器上,tasklet机制可以保证同一个tasklet不会同时在多个CPU上同时运行,其是通过state域实现的。当其为TASKLET_STATE_RUN时表示其他CPU正在运行当前tasklet,则本CPU上的相关工作推后进行。

这些机制已经封装好了,用户程序不用管。这样相当于为用户提供了更简单可靠的接口。

302#ifdef CONFIG_SMP

303static inline int tasklet_trylock(struct tasklet_struct *t)

304{

305 return !test_and_set_bit(TASKLET_STATE_RUN, &(t)->state);

306}

若不是TASKLET_STATE_RUN状态,则设置为TASKLET_STATE_RUN,防止其他CPU调度,返回成功;否则返回失败。

307

308static inline void tasklet_unlock(struct tasklet_struct *t)

309{

310 smp_mb__before_clear_bit();

311 clear_bit(TASKLET_STATE_RUN, &(t)->state);

312}

当前CPU上的处理工作完成后,清除TASKLET_STATE_RUN。

313

314static inline void tasklet_unlock_wait(struct tasklet_struct *t)

315{

316 while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barri er(); }

317}

等待其他处理器上处理完毕,否则barrier。

318#else 单CPU上,一切为空。

319#define tasklet_trylock(t) 1

320#define tasklet_unlock_wait(t) do { } while (0)

321#define tasklet_unlock(t) do { } while (0)

322#endif

4执行tasklet

当tasklet挂起等待运行后,do_softirq()会尽可能早地在下一个合适的时机执行。由于大部分tasklet和软中断都是在中断处理程序中被设置成待处理状态,所以最近一个中断返回的时候看起来就是执行do_softirq()的最佳时机。因为TA SKLET_SOFTIRQ和HI_SOFTIRQ已经被触发,所以do_softirq()会执行相应的软中断处理程序。

tasklet_action为注册的对应tasklet软中断执行函数,传递的参数为softirq_a ction,符合softirq的API接口。

369static void tasklet_action(struct softirq_action *a)

370{

371 struct tasklet_struct *list;

372

373 local_irq_disable();

374 list = __get_cpu_var(tasklet_vec).list;

375 __get_cpu_var(tasklet_vec).list = NULL;

376 local_irq_enable();

377

378 while (list) {

379 struct tasklet_struct *t = list;

380

381 list = list->next;

382

383 if (tasklet_trylock(t)) {

384 if (!atomic_read(&t->count)) {

385 if (!test_and_clear_bit(TASKLET_ STATE_SCHED, &t->state))

386 BUG();

387 t->func(t->data);

388 tasklet_unlock(t);

389 continue;

390 }

391 tasklet_unlock(t);

392 }

393

394 local_irq_disable();

395 t->next = __get_cpu_var(tasklet_vec).list;

396 __get_cpu_var(tasklet_vec).list = t;

397 __raise_softirq_irqoff(TASKLET_SOFTIRQ);

398 local_irq_enable();

399 }

400}

tasklet_action和tasklet_hi_action是tasklet处理的核心。其流程如下:

1)373行,禁止中断。没有必要首先保存其状态,因为这里的代码总是作为

软中断被调用,而且中断总是被激活的。

2)374行,得到注册在当前处理器上的tasklet链表tasklet_vec或tasklet_hi_v

ec。

3)375行,将当前处理器上的该链表设置为NULL,达到清空的效果。

4)376行,允许响应中断。

5)378行,循环遍历获得链表上的每一个待处理的tasklet。

6)379行,得到当前的链表头。

7)381行,保存后续链表。

8)383行,如果是多处理器系统,通过检查TASKLET_STATE_RUN状态标

志来判断这个tasklet是否注册到其他CPU上并且目前正在其他处理器上运行。如果没有运行,将其状态标志设置为TASKLET_STATE_RUN,这样别的处理器就不会再去执行它了,转384,否则转394行。这就保证了同一时间里,相同类型的tasklet只能有一个执行。

9)384行,检查count值是否为0,确保tasklet没有被禁止。如果没有被禁止,

则执行其注册的函数,tasklet运行完毕,清除tasklet的state域的TASKLE T_STATE_RUN状态标志。然后回378行。如果tasklet被禁止了,则跳到391行。

10)394行,将当前禁止的或者其他CPU正在处理的tasklet保存在tasklet_vec

链表头部,重设TASKLET_SOFTIRQ标识,等待下次调度。回378行,重复执行下一个tasklet,直至没有剩余的等待处理的tasklet。

Tasklet的实现很简单,但非常巧妙。我们可以看到,所有的tasklet都通过重复运用TASKLET_SOFTIRQ和HI_SOFTIRQ这两个软中断来实现。当一个t asklet被调度时,内核就会唤起这两个软中断中的一个。随后,该软中断会被特定的函数处理,执行所有已调度的tasklet。这个函数保证同一时间里某tasklet

只能在一个CPU上运行,但其他不同类型的tasklet可以同时执行。

5Tasklet的API

5.1自定义tasklet处理程序

tasklet处理程序必须符合规定的函数类型:

void tasklet_handler(unsigned long data)

因为是靠软中断实现,这意味着tasklet处理程序应注意如下几点:

?tasklet不能睡眠。这意味着你不能在tasklet中使用信号量或者其他什么阻

塞式的函数。

?由于tasklet运行时允许响应中断,如果你的tasklet和中断处理程序之间共

享了某些数据的话,所以你必须做好预防工作(比如屏蔽中断然后获取一个锁)。

?两个相同的tasklet决不会在不同CPU上同时执行,这点和软中断不同,ta

sklet自身无需实现SMP的互斥。

但两个不同的tasklet可以在两个处理器上同时执行。如果你的tasklet和其他的tasklet或者是软中断共享了数据,你必须进行适当地锁保护。

5.2Tasklet的初始化

大多数情况下,为了控制一个寻常的硬件设备,tasklet机制都是实现你自己的下半部的最佳选择。tasklet可以静态地创建或者动态创建,使用方便,执行起来也还算快。你既可以全局静态地创建tasklet,也可以动态地创建它。选择哪种方式取决于你到底是有一个对tasklet的直接引用还是间接引用。最好使用系统提供的初始化API,避免直接操作tasklet的成员,这样可以提高可移植性。

5.2.1全局静态创建并初始化tasklet

静态创建一个tasklet可使用下面include/linux/interrupt.h中定义的两个宏中的一个:

289#define DECLARE_TASKLET(name, func, data) \

290struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }

291

292#define DECLARE_TASKLET_DISABLED(name, func, data) \

293struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(1), func, data }

这两个宏都能根据给定的名称静态地创建一个tasklet_struct结构。当该task let被调度以后,给定的函数func会被执行,它的参数由data给出。这两个宏之间的区别在于引用计数器的初始值设置不同。前面一个宏把创建的tasklet的引用计数器设置为0,该tasklet处于激活状态。另一个把引用计数器设置为1,所以该tasklet处于禁止状态。

下面是一个例子:

DECLARE_TASKLET(my_tasklet, my_tasklet_handler, dev);

这样就创建了一个名为my_tasklet,处理程序为tasklet_handler并且已被激活的tasklet。当处理程序被调用的时候,dev就会被传递给它。

5.2.2动态初始化tasklet

还可以通过将一个间接引用(一个指针)赋给一个动态创建的tasklet_struct结构的方式来初始化一个tasklet。该函数可以在运行过程中动态初始化未初始化或者已经使用过的tasklet。

436void tasklet_init(struct tasklet_struct *t,

437 void (*func)(unsigned long), unsigned long data) 438{

439 t->next = NULL;

440 t->state = 0;

441 atomic_set(&t->count, 0);

442 t->func = func;

443 t->data = data;

444}

5.3调度tasklet

通过调用tasklet_schedule()函数并传递给它相应的tasklet_struct的指针,该tasklet就会被调度以便执行:

tasklet_schedule(&my_tasklet);/*把my_tasklet标记为挂起*/

在tasklet被调度以后,只要有机会它就会尽可能早地运行。在它还没有得到运行机会之前,

如果有一个相同的tasklet又被调度了,那么它仍然只会运行一次。而如果这时它已经开始运行了,比如说在另外一个处理器上,那么这个新的tasklet会被重新调度并再次运行。作为一种优化措施,一个tasklet总在调度它的处理器上执行—这是希望能更好地利用处理器的高速缓存。

include/linux/interrupt.h

326static inline void tasklet_schedule(struct tasklet_struct *t)

327{

328 if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))

329 __tasklet_schedule(t);

/////////////////////

kernel/softirq.c

343void fastcall __tasklet_schedule(struct tasklet_struct *t)

344{

345 unsigned long flags;

346

347 local_irq_save(flags);

348 t->next = __get_cpu_var(tasklet_vec).list;

349 __get_cpu_var(tasklet_vec).list = t;

350 raise_softirq_irqoff(TASKLET_SOFTIRQ);

351 local_irq_restore(flags);

352}

/////////////////////

330}

tasklet_schedule()流程如下:

1)检查tasklet的状态是否为TASKLET_STATE_SCHED。如果是,说明taskl

et已经被调度过(有可能是一个tasklet已经被调度过但还没来得及执行,而该tasklet又被唤起了一次),函数立即返回。

2)保存中断状态,然后禁止本地中断。

3)把需要调度的tasklet加到每个处理器一个的tasklet_vec链表或tasklet_hi_v

ec链表的表头上去。

4)唤起TASKLET_SOFTIRQ或HI_SOFTIRQ软中断,这样在下一次调用do

_softirq()时就会执行该tasklet。

5)恢复中断到原状态并返回。

5.4禁止或者使能tasklet

341static inline void tasklet_disable_nosync(struct tasklet_struct *t)

342{

343 atomic_inc(&t->count);

344 smp_mb__after_atomic_inc();

345}

可用来禁止指定的tasklet,不过它无须在返回前等待tasklet执行完毕。这么做往往不太安全,因为你无法估计该tasklet是否仍在执行。

347static inline void tasklet_disable(struct tasklet_struct *t)

348{

349 tasklet_disable_nosync(t);

350 tasklet_unlock_wait(t);

351 smp_mb();

352}

你可以调用tasklet_disable()函数来禁止某个指定的tasklet。如果该tasklet当前正在执行,这个函数会等到它执行完毕再返回。

354static inline void tasklet_enable(struct tasklet_struct *t)

355{

356 smp_mb__before_atomic_dec();

357 atomic_dec(&t->count);

358}

调用tasklet_enable()函数可以激活一个tasklet,如果希望激活DECLARE_T ASKLET_DISABLED ()创建的tasklet,你也得调用这个函数,如: tasklet_enable(&my_tasklet):/*tasklet现在被激活*/

5.5删除tasklet

你可以通过调用tasklet_kill()函数从挂起的队列中去掉一个tasklet。该函数的参数是一个指向某个tasklet的tasklet_struct的长指针。在处理一个经常重新调度它自身的tasklet的时候,从挂起的队列中移去已调度的tasklet会很有用。这个函数首先等待该tasklet执行完毕,然后再将它移去。由于该函数可能会引起休眠,所以禁止在中断上下文中使用它。

448void tasklet_kill(struct tasklet_struct *t)

449{

450 if (in_interrupt())

451 printk("Attempt to kill tasklet from interrupt\n");

452

453 while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {

454 do

455 yield();

456 while (test_bit(TASKLET_STATE_SCHED, &t->stat e));

457 }

458 tasklet_unlock_wait(t);

459 clear_bit(TASKLET_STATE_SCHED, &t->state);

460}

centos操作系统简介

centos操作系统简介 CentOS(Community ENTerprise Operating System)是Linux发行版之一,它是来自于Red Hat Enterprise Linux依照开放源代码规定释出的源代码所编译而成。由于出自同样的源代码,因此有些要求高度稳定性的服务器以CentOS替代商业版的Red Hat Enterprise Linux使用。两者的不同,在于CentOS并不包含封闭源代码软件。CentOS,我们有很多人叫它社区企业操作系统,不管你怎么叫它,它都是linux的一个发行版本。CentOS并不是全新的linux发行版,倘若一说到RedHat这个大名,大家似乎都听过,在RedHat家族中有企业版的产品,它是Red Hat Enterprise Linux(以下称之为RHEL),CentOS正是这个RHEL的克隆版本,RHEL是很多企业采用的linux发行版本,需要向RedHat付费才可以使用,并能得到付过费用的服务和技术支持和版本升级。这个CentOS可以像REHL一样的构筑linux系统环境,但不需要向RedHat付任何的费用,同样也得不到任何有偿技术支持和升级服务。 CentOS计划是在2003年红帽决定不再提供免费的技术支持及产品认证之后的部份"红帽重建者"(Red Hat rebuilders)之一。 CentOS和Linueox、组装Linux (White box Linux)、Tao Linux 、X/OS Linux,及科学Linux (Scientific Linux)等都以红帽所发布的源代码原件重建Red Hat Enterprise Linux的翻版,并修正了已经发现了的redhat的bug。 CentOS是"Caos Linux"独立计划的一个分枝,在Lawrence Berkeley 国家实验室担任管理员与程序设计师的Kurtzer表示。但后来Caos基金会最受欢迎的计划变成是RHEL 的重建。 历史 Red Hat公司的产品中,有RedHat Linux(如Redhat8,9)和针对企业发行的版本Red Hat Enterprise Linux,都能够通过网络FTP免费的获得并使用,但是在2003年的

linux下种定时执行任务方法

(1)at命令 假如我们只是想要让特定任务运行一次,那么,这时候就要用到at监控程序了。 设置at命令很简单,指示定运行的时间,那么就会在哪个时候运行。at类似打印进程,会把任务放到/var/spool/at目录中,到指定时间运行它。at命令相当于另一个shell,运行at time命令时,它发送一个个命令,可以输入任意命令或者程序。at now + time命令可以在指示任务。 假设处理一个大型数据库,要在别人不用系统时去处理数据,比如凌晨3点10分。那么我们就应该先建立/home/kyle/do_job脚本管理数据库,计划处理/home/kyle/do_job文件中的结果。正常方式是这样启动下列命令: # at 2:05 tomorrow at>/home/kyle/do_job at> Ctrl+D AT Time中的时间表示方法 ----------------------------------------------------------------------- 时间例子说明 ----------------------------------------------------------------------- Minute at now + 5 minutes任务在5分钟后运行 Hour at now + 1 hour任务在1小时后运行 Days at now + 3 days任务在3天后运行 Weeks at now + 2 weeks任务在两周后运行 Fixed at midnight任务在午夜运行 Fixed at 10:30pm任务在晚上10点30分 注意:一定要检查一下atq的服务是否启动,有些操作系统未必是默认启动的,linux 默认为不启动,而ubuntu默认为启动的。检查是否启动,用service atd检查语法,用service atd status检查atd的状态,用service atd start启动atd服务。 查看at执行的具体内容:一般位于/var/spool/at目录下面,用vi打开,在最后一部分

linux网络操作系统和实训课后习题答案解析(1)

练习题 一、选择题 1. Linux 最早是由计算机爱好者 B 开发的。 A. Richard Petersen B. Linus Torvalds C. Rob Pick D. Linux Sarwar 2. 下列 C 是自由软件。 A. Windows XP B. UNIX C. Linux D. Windows 2000 3. 下列 B 不是Linux 的特点。 A. 多任务 B. 单用户 C. 设备独立性 D. 开放性 4. Linux 的内核版本2.3.20 是 A 的版本。 A. 不稳定 B. 稳定的 C. 第三次修订 D. 第二次修订 二、填空题 1. GUN 的含义是:GNU's Not UNIX。 2. Linux 一般有 3 个主要部分:内核(kernel)、命令解释层(Shell 或其他操作环境)、 实用工具。 三、简答题(略) 1. 简述Red Hat Linux 系统的特点。 2. 简述一些较为知名的Linux 发行版本。 练习题 一、选择题 1. Linux 安装过程中的硬盘分区工具是 D 。 A. PQmagic B. FDISK C. FIPS D. Disk Druid 2. Linux 的根分区系统类型是 C 。 A. FATl6 B. FAT32 C. ext3 D. NTFS 二、填空题 1. 安装Linux 最少需要两个分区,分别是 swap 交换分区和/(根)分区。 2. Linux 默认的系统管理员账号是 root 。 3. X-Window System 由三部分构成:X Server、X Client 和通信通道。 三、简答题(略) 1. Linux 有哪些安装方式 2. 安装Red Hat Linux 系统要做哪些准备工作 3. 安装Red Hat Linux 系统的基本磁盘分区有哪些 4. Red Hat Linux 系统支持的文件类型有哪些 练习题 一、选择题 1. C 命令能用来查找在文件TESTFILE 中包含四个字符的行 A. grep’’TESTFILE B. grep’….’TESTFILE C. grep’^$’TESTFILE D. grep’^….$’TESTFILE 2. B 命令用来显示/home 及其子目录下的文件名。 A. ls -a /home B. ls -R /home C. ls -l /home D. ls -d /home 3. 如果忘记了ls 命令的用法,可以采用 C 命令获得帮助 A. ls B. help ls C. man ls D. get ls 4. 查看系统当中所有进程的命令是 D 。 A. ps all B. ps aix C. ps auf D. ps aux

linux中设置tomcat为系统服务并自启动

Linu下设置tomcat自启动 一、以root用户登录系统: 二、进入init.d文件夹 cd /etc/init.d/ 三、创建并打开tomcat文件 vi tomcat 四、tomcat文件如下: #!/bin/sh # tomcat: Start/Stop/Restart tomcat # chkconfig: 2345 80 20 # description: Tomcat is a Java Servlet Container # match these values to your environment: export CATALINA_BASE=/root/apache-tomcat-5.5.34 export CATALINA_HOME=/root/apache-tomcat-5.5.34 export CATALINA_TMPDIR=/root/apache-tomcat-5.5.34/temp export JRE_HOME=/root/jdk1.6.0_21 ./etc/init.d/functions TOMCAT=/root/apache-tomcat-5.5.34 start() { echo -n "Starting Tomcat: " /root/apache-tomcat-5.5.34/bin/catalina.sh start }

stop() { echo -n "Stopping Tomcat: " /root/apache-tomcat-5.5.34/bin/catalina.sh stop } case "$1" in start) start ;; stop) stop ;; status) ;; restart) stop start ;; *) echo "Usage: $0 {start stop restart}";; esac exit $RETVAL 五、保存退出

linux实验_添加系统调用-完整版

实验一添加一个新的系统调用 一、实验目的 理解操作系统内核与应用程序的接口关系;加深对内核空间和用户空间的理解;学会增加新的系统调用。 二、实验内容与要求 首先增加一个系统调用函数,然后连接新的系统调用,重建新的Linux内核,用新的内核启动系统,使用新的系统调用(2.4内核和2.6内核任选一个) 三、实验指导(2.6版本) ⑴获得源代码(本次实验的内核版本是2.6.22.5,必须是root用户) 1.从教育在线上下载内核源代码到本地磁盘;保存在/usr/src目录下 2.进入终端,输入命令cd /usr/src 进入/usr/src目录(可以输入ls命令会发现目录下有一个名为LINUX_2_6_22_5.TAR.BZ2的压缩文件) 3.当前目录下(/usr/src)输入命令tar –xjvf LINUX_2_6_22_5.TAR.BZ2 解压缩源代码,命令执行完毕后,会出现/usr/src/linux-2.6.22.5文件夹 4.修改文件夹下的3个文件 第一,编辑/usr/src/linux-版本号/kernel/sys.c文件,添加函数: asmlinkage long sys_mycall(long number) { printk(“call number is %d\n”,number); return number; } 第二,修改/usr/src/linux-版本/include/asm-i386/unistd.h 添加一行#define __NR_mycall 324 到当前的最大系统调用号之后,比如原来最大的是323,在323的这一行之后加上一行#define __NR_mycall 324 修改#define NR_systemcalls 的值,改成原来的值+1,比如原来是324 改成325 第三,编辑/usr/src/linux-版本/arch/i386/kernel/syscall_table.S,在文件最后加上一行:.long sys_mycall 5.重新编译内核 在终端输入命令,进入源代码文件夹,cd /usr/src/linux-2.6.22.5 依次执行如下命令:make mrproper make clean make xconfig (自己配置内核,出现图形对话框后,直接点保存,关闭) make (耗时最长,大约20分钟) make modules_install (安装模块) 以上命令执行完毕后,会在当前目录下生成一个名为System.map的文件,会在/usr/src/linux-版本号/arch/i386/boot/下生成一个bzImage文件。

Linux下定时执行脚本

Linux下定时执行脚本 今天做了个数据库的备份脚本,顺便系统得学习一下Linux下定时执行脚本的设置。Linux下的定时执行主要是使用crontab文件中加入定制计划来执行,设置比Windows稍微复杂一些(因为没有图形界面嘛),但是也不是非常复杂,基本上用过一遍就能记住了,关键是要记住/var/spool/cron这个目录。下面看一下具体的用法: 首先查看一下/etc/crontab文件: $ cat /etc/crontab SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root HOME=/ # run-parts 01 * * * * root run-parts /etc/cron.hourly 02 4 * * * root run-parts /etc/cron.daily 22 4 * * 0 root run-parts /etc/cron.weekly 42 4 1 * * root run-parts /etc/cron.monthly 前四行是有关设置cron任务运行的环境变量。SHELL变量的值指定系统使用的SHELL环境(该样例为bash shell),PATH变量定义了执行命令的路径。Cron的输出以电子邮件的形式发给MAILTO变量定义的用户名。如果MAILTO变量定义为空字符串(MAILTO=""),电子邮件不会被发送。执行命令或脚本时HOME变量可用来设置基目录。 文件/etc/crontab中每行任务的描述格式如下: minute hour day month dayofweek command minute - 从0到59的整数 hour - 从0到23的整数 day - 从1到31的整数 (必须是指定月份的有效日期) month - 从1到12的整数 (或如Jan或Feb简写的月份)

Linux系统中将应用服务设置为随系统启动

Linux系统中将应用服务设置为随系统启动 一、将runmyservice.sh复制到linux /etc/init.d下 二、# chmod 557 runmyservice.sh 三、#chkconfig --add runmyservice.sh //查看是否添加自动启动成功 #chkconfig --list runmyservice.sh脚本内容如下: #! /bin/sh #chkconfig:2345 85 15 #description:mule4bridge # Mule Start/Stop/Restart //将所需的环境变量全部引入 LC_ALL=zh_CN.gbk; export LC_ALL LANG=zh_CN.gbk; export LANG export JA VA_HOME=/usr/java/jdk1.6.0_21 export CLASSPA TH=.:$JA V A_HOME/lib/tools.jar:$JA V A_HOME/lib/dt.jar export PATH=$JA V A_HOME/bin:$JA V A_HOME/jre/bin:$PATH export MULE_HOME=/home/mule-2.1.2 export PATH=$PATH:$MA VEN_HOME/bin:$MULE_HOME/bin PATH=$PATH:$HOME/bin export PATH prog=$MULE_HOME/bin/mule case "$1" in start) echo -n $"Starting $prog: " su cicro -c "nohup /home//start_all_service &" echo exit 0 ;; stop) echo -n $"Shutting down $prog: " # killproc $prog stop echo ;; restart) echo -n $"Restart $prog daemon configuration: " $0 stop sleep 5

linux定时执行crontab

linux定时执行crontab 2009-11-18 作者:编辑:闫蕊点击进入论坛 关键词:linux crontab -e 进入一个vi 编辑界面 在最后一行加上 */30 * * * * netstat > /tmp/net.log 表示每隔30分就执行netstat命令,并把执行结果存入net.log中。 Crontab是一个很方便的在unix/linux系统上定时(循环)执行某个任务的程序 使用cron服务,用service crond status 查看cron服务状态,如果没有启动则service crond start启动它, cron服务是一个定时执行的服务,可以通过crontab 命令添加或者编辑需要定时执行的任务: crontab -u //设定某个用户的cron服务,一般root用户在执行这个命令的时候需要此参数 crontab -l //列出某个用户cron服务的详细内容 crontab -r //删除没个用户的cron服务 crontab -e //编辑某个用户的cron服务 比如说root查看自己的cron设置:crontab -u root -l 再例如,root想删除fred的cron设置:crontab -u fred -r 在编辑cron服务时,编辑的内容有一些格式和约定,输入:crontab -u root -e 进入vi编辑模式,编辑的内容一定要符合下面的格式:*/1 * * * * ls >> /tmp/ls.txt 编辑/etc/crontab文件,在末尾加上一行:30 5 * * * root init 6 这样就将系统配置为了每天早上5点30自动重新启动。

linux操作系统

以下哪些是Linux操作系统的特点? A. 广泛性 B. 低廉性 C. 灵活性 D. 健壮性 回答正确 解析: 略 2 单选以下哪个不属于操作系统? A. Windows B. Linux C. Oracle D. MacOS 回答正确 解析: 略 3 单选以下描述正确的是? A. 批处理系统出现早于分时系统 B. Linux就是批处理系统 C. 批处理系统可以同时执行多个任务 D. Windows是批处理操作系统 回答正确 解析: 略 4 单选以下哪个是移动操作系统? A. Linux B. Android C. WindowsXP D. Windows2003 回答正确 解析: 略 5 单选Linux最早发布于哪一年? A. 1990 B. 1991 C. 1992 D. 1993 回答正确 解析: 略 6 单选第一个企业版的Linux是哪一个? A. CentOS B. Ubuntu C. Debian D. RedHat 回答正确 解析: 略 7 单选以下哪个不是内核的组成部分? A. 系统调用接口

B. 进程管理 C. C语言编译器 D. 驱动程序 回答正确 解析: 略 8 单选Linux下常用文本编辑工具是? A. Notepad B. EditPlus C. DreamWeaver D. VIM 回答正确 解析: 略 9 单选Linux的终端软件英文名称是什么? A. background B. terminal C. console D. cmd 回答正确 解析: 略 10 单选下载安装软件的命令是什么? A. apt-getinstall B. vim-version C. sudo D. setup 回答正确 修改密码的命令是? A. change B. passwd C. password D. update 回答正确 解析: 略 2 单选进入某一文件夹的命令是? A. ls B. cd C. ll D. help 回答正确 解析: 略 3 单选列表显示所有文件的命令是? A. ls B. cd C. pwd

LINUX系统实验内容——几个常用服务的配置

实验目录 LINUX-Shell编程 (1) LINUX shell命令(一) (6) LINUX shell命令(二) (15) LINUX网络管理 (30) 配置DHCP服务器 (40) LINUX启动设置验证和SAMBA服务器与客户配置 (48) LINUX软件安装实验(JA VA和GCC) (58) Apache 服务器的配置(1) (63) 内容 LINUX-Shell编程 一.简单SHELL实验:请在vi中逐一编辑并执行以下6个shell脚本程序 1.编写一个简单的回显用户名的shell程序。 #vi dat #!/bin/bash #filename:dat echo "Mr.$USER,Today is:" echo `date` echo Wish you a lucky day! #chmod +x dat #./dat 2.使用if-then语句创建简单的shell程序。 #vi bbbb #!/bin/bash #filename:bbbb echo -n "Do you want to continue: Y or N" read ANSWER if [ $ANSWER = N -o $ANSWER = n ] then exit fi #chmod +x bbbb #./bbbb 3.使用if-then-else语句创建一个根据输入的分数判断是否及格的shell程序。 #vi ak #!/bin/bash #filename:ak echo -n "please input a score:" read SCORE

echo "You input Score is $SCORE" if [ $SCORE -ge 60 ]; then echo -n "Congratulation!You Pass the examination." else echo -n "Sorry!You Fail the examination!" fi echo -n "press any key to continue!" read $GOOUT #chmod +x ak #./ak 4.使用for语句创建简单的shell程序。 #vi mm #!/bin/bash #filename:mm for ab in 1 2 3 4 do echo $ab done #chmod +x mm #./mm 5.使用while语句创建一个计算1-5的平方的shell程序。 #vi zx #!/bin/bash #filename:zx int=1 while [ $int -le 5 ] do sq=`expr $int \* $int` echo $sq int=`expr $int + 1` done echo "Job completed" #chmod +x zx #./zx 6.使用while语句创建一个根据输入的数值求累加和(1+2+3+4+…+n)的shell程序。#vi sum #!/bin/bash #filename:sum echo -n "Please Input Number:" read NUM number=0 sum=0 while [ $number -le $NUM ]

linux添加系统调用实验步骤

首先,进入到内核源码目录/usr/src/linux-2.6.34中,添加自己的系统调用号。 lyh@lyh:~$ cd /usr/src/linux-2.6.34/ 系统调用号在unistd_32.h文件中定义。内核中每个系统调用号都是 以“__NR_"开头的,在该文件中添加自己的系统调用号 lyh@lyh:/usr/src/linux-2.6.34$ sudo vim arch/x86/include/asm/unistd_32.h #define __NR_pwritev 334 #define __NR_rt_tgsigqueueinfo 335 #define __NR_perf_event_open 336 #define __NR_recvmmsg 337 #define __NR_mycall 338 #ifdef __KERNEL__ #define NR_syscalls 339 在内核源文件中该行为#define NR_syscalls 338,在系统调用执行的过程中,system_call()函数会根据该值来对用户态进程的有效性进行检查。如果这个号大于或等于NR_syscalls,系统调用处理程序终止。所以应该将原来的#define NR_syscalls 338修改为#define NR_syscalls 339 其次,在系统调用表中添加相应的表项 (1)lyh@lyh:/usr/src/linux-2.6.34$ sudo vim arch/x86/kernel/syscall_table_32.S ENTRY(sys_call_table) .long sys_restart_syscall .long sys_exit ………………(这里省略了部分) .long sys_rt_tgsigqueueinfo .long sys_perf_event_open .long sys_recvmmsg .long sys_mycall (2)lyh@lyh:/usr/src/linux-2.6.34$ sudo vim arch/h8300/kernel/syscalls.S #include #include

linux下自动化任务的例子——定时播放音乐

linux下自动化任务的例子 在linux系统中实现作业的自动化是非常便利的。 比较常用的是Cron服务的crontab这个命令。 ?一个具体的任务列表 这个是学校室外广播的自动程序,只用了?一台被废弃的塞羊800的学生机,安装的系统是红旗linux,其他的linux、FreeBSD、unix或者是MacOS都可以。 将Cron设为自动运行。 chkcon?g –level 35 crond on 进入系统终端 键入: crontab -u caizhongyi -e (crontab为命令,“-u cai”是指定执行作业的系统用户为cai,“-e”使用crontab自己的vi编辑器,防止出现编码或系统环境问题造成的错误)然后在编辑器(vi编辑器)中输入如下命令: 0 7 * * 1 mpg123 -q /home/cai/guangbo/001.mp3 21 8 * * 1 mpg123 -q /home/cai/guangbo/11.mp3 21 8 * * 2 mpg123 -q /home/cai/guangbo/21.mp3 21 8 * * 3 mpg123 -q /home/cai/guangbo/31.mp3 21 8 * * 4 mpg123 -q /home/cai/guangbo/41.mp3 21 8 * * 5 mpg123 -q /home/cai/guangbo/51.mp3 16 9 * * 2 mpg123 -q /home/cai/guangbo/212.mp3 16 9 * * 3 mpg123 -q /home/cai/guangbo/312.mp3 16 9 * * 4 mpg123 -q /home/cai/guangbo/412.mp3 16 9 * * 5 mpg123 -q /home/cai/guangbo/512.mp3 25 10 * * 1 mpg123 -q /home/cai/guangbo/12.mp3 25 10 * * 2 mpg123 -q /home/cai/guangbo/22.mp3 25 10 * * 3 mpg123 -q /home/cai/guangbo/32.mp3 25 10 * * 4 mpg123 -q /home/cai/guangbo/42.mp3

linux服务详解

Linux AS4下系统服务详解刚整理的 Linux, 详解, 系统, 服务 Linux AS4下系统服务详解 nfs 0:off 1:off 2:off 3:off 4:off 5:off 6:off nfs网络文件共享 NetworkManager 0:off 1:off 2:off 3:off 4:off 5:off 6:off 网络管理network 0:off 1:off 2:on 3:on 4:on 5:on 6:off 网络 gpm 0:off 1:off 2:on 3:off 4:on 5:on 6:off 鼠标mdmonitor 0:off 1:off 2:on 3:off 4:on 5:on 6:off 与RAID设备相关的守护程序 cups 0:off 1:off 2:on 3:off 4:on 5:on 6:off 公共UNIX打印支持,为Linux提供打印功能。是否需要启动如果不安装打印机,就不需要启动。 ypbind 0:off 1:off 2:off 3:off 4:off 5:off 6:off SUN的YP服务器名称服务器 haldaemon 0:off 1:off 2:off 3:off 4:on 5:on 6:off 硬件监控服务,监控硬件的改变,为你改变新的或更改过硬件,可以检测即插即用设备readahead 0:off 1:off 2:off 3:off 4:off 5:on 6:off 其作用是在启动系统期间,将启动系统所要用到的文件首先读取到内存中,然后在内存中进行执行,以加快系统的启动速度。而上面两个配置文件就保存着将要读取到内存的文件列表。 ipmi 0:off 1:off 2:off 3:off 4:off 5:off 6:off IPMI (Intelligent Platform Management Interface)即智能平台管理接口是使硬件管理具备“智能化”的新一代通用接口标准。用户可以利用IPMI 监视服务器的物理特征,如温度、电压、电扇工作状态、电源供应以及机箱入侵等。Ipmi 最大的优势在于它是独立于CPU BIOS 和OS 的,所以用户无论在开机还是关机的状态下,只要接通电源就可以实现对服务器的监控。Ipmi 是一种规范的标准,其中最重要的物理部件就是BMC(Baseboard Management Controller 如图1),一种嵌入式管理微控制器,它相当于整个平台管理的“大脑”,通过它ipmi 可以监控各个传感器的数据并记录各种事件的日志。 mdmpd 0:off 1:off 2:off 3:off 4:off 5:off 6:off 软RAID监控服务 smartd 0:off 1:off 2:on 3:on 4:on 5:on 6:off Self Monitor Analysis and Reporting Technology System,监控你的硬盘是否出现故障。ibmasm 0:off 1:off 2:off 3:off 4:off 5:off 6:off ibmasm 套件用來與IBM Advance System Management PCI Adapter(亦稱RSA I)進行通訊。auditd 0:off 1:off 2:off 3:off 4:off 5:off 6:off 审核守护进程atd 0:off 1:off 2:off 3:on 4:on 5:on 6:off 用于at和batch的服务atd类似cron,提供在指定的时间做指定的事的服务,就象计划任务iptables 0:off 1:off 2:on 3:on 4:on 5:on 6:off 防火墙snmptrapd 0:off 1:off 2:off 3:off 4:off 5:off 6:off SNMP的捕获服务syslog 0:off 1:off 2:on 3:on 4:on 5:on 6:off 系统日志服务pcmcia 0:off 1:off 2:on 3:off 4:on 5:on 6:off 安装pcmcia卡(一般用于笔记本电脑)

Linux内核中增加一个系统调用

选题要求:在Linux内核中增加一个系统调用,并编写对应的linux应用程序。利用该系统调用能够遍历系统当前所有进程的任务描述符,并按进程父子关系将这些描述符所对应的进程id(PID)组织成树形结构显示。

目录 一.程序的主要设计思路,实现方式 (1) 1.1 添加系统调用的两种方法 (1) 1.1.1编译内核法 (1) 1.1.2内核模块法 (1) 1.2 程序的主要设计思路 (1) 1.3 环境 (2) 二.程序的模块划分,及对每个模块的说明 (2) 2.1 通过内核模块实现添加系统调用 (2) 2.1.1修改系统调用的模块 (2) 2.1.2获取sys_call_table的地址 (2) 2.1.3清除内存区域的写保护 (3) 2.2 编写系统调用指定自己的系统调用 (4) 2.2.1内核的初始化函数 (4) 2.2.2自己的系统调用服务例程 (4) 2.2.3移除内核模块时,将原有的系统调用进行还原 (6) 2.2.4模块注册相关 (6) 2.3 编写用户态的测试程序 (6) 2.4 编写Makefile文件 (7) 三.所遇到的问题及解决的方法 (8) 3.1 进程个数确定 (8) 3.2 被更改的系统调用号的选择 (8) 3.3 获取系统调用表的地址 (8) 3.4 内核和用户态数据交换 (8) 四.程序运行结果及使用说明 (8) 4.1 将编译出来的内核模块hello.ko加载到内核中 (8)

4.2通过dmesg查看输出信息是否正确 (9) 4.3运行测试程序,输出树状打印结果(部分结果截图) (9) 4.4卸载自定义模块 (10) 五.附录 (11) 5.1 内核模块程序hello.c (11) 5.2 测试程序hello_test.c (14) 5.3Makefile文件 (14)

Linux操作系统部分复习题答案

第一章 Linux系统简介 一、思考题 1.UNIX的大部分代码是用一种流行的程序设计语言编写的,该语言是什么? C语言 2.UNIX系统的特点有哪些? ·多任务 ·多用户 ·并行处理能力 ·设备无关性 ·工具 ·错误处理 ·强大的网络功能 ·开放性 3.什么是Linux?其创始人是谁? Linux是一个功能强大的操作系统,同时它也是一个自由软件,是免费的、源代码开放的、可以自由使用的UNIX兼容产品。其创始人是Linus 4.Linux操作系统的诞生、发展和成长过程始终依赖者的重要支柱都有哪些? ·UNIX操作系统 ·MINIX操作系统 ·GNU计划 ·POSIX标准 ·Internet 5.简述Linux系统的特点。 ·自由软件 ·良好的兼容性 ·多用户、多任务 ·良好的界面 ·丰富的网络功能 ·可靠地安全性、稳定性 ·支持多种平台 6.常见的Linux的发行版本有哪些? ·Red Hat Linux ·Caldera OpenLinux ·SuSE Linux ·TurboLinux ·红旗Linux ·中软Linux 二、选择题 1.Linux最初是以MINIX 操作系统为模板而开发出来的。 2.关于Linux内核版本的说法,下列选项中错误的是(C)。 A.表示为主版本号.次版本号.修正号B.1.2.3表示稳定的发行版 C.1.3.3表示稳定的发行版D.2.2.5表示对内核2.2的第5次修正(补充:次版本号为偶数的是稳定版本;为奇数的则是测试版本。)

3.Linux属于自由软件。 4.自由软件的含义是软件可以自由修改和发布。 5.一下不具有多任务性的操作系统是DOS 第二章 Linux系统入门 一、思考题 1.Linux系统有哪些运行级别?其含义是什么? 可用级别为0~6,其中0:关闭系统;6:重新启动,其他略。 2.Linux系统下经常使用的两种桌面环境是什么? GNOME和KDE 3.什么是X-Window系统?它有什么特点? 图形界面(X-Window)是在Linux操作系统中提供的图形化用户界面(GUI),其支持的视窗系统也称为X,它的特点有:它采用了“客户端-服务器”模式;它是一个跨平台的操作环境。 7.默认情况下,超级用户和普通用户的登录提示符分别是什么? # 和 $ 二、选择题 1.系统引导的过程一般包括如下的几步:①MBR中的引导装载程序启动。②用户登录。③Linux内核运行。④BIOS自检。正确的顺序是④①③②。 2.Linux中使用Ctrl+Alt+BackSpace 组合键可以关闭X-Window图形用户界面。 3.字符界面下使用init命令关机所用的参数是0 。(参数6是重新启动) 4.字符界面下使用shutdown命令重启计算机时所用的参数是–r 。 5.使用man命令调阅相关的帮助信息时,用于逐页地下翻的功能键是Space 。 第三章 shell与shell命令 一、思考题 1.shell的基本功能有哪些? 命令解释执行、文件名替换、输入/输出重定向、连同管道建立、系统环境设置和shell编程。 2.Linux系统中的主要目录有哪些? /:系统的根目录 /dev:系统的设备目录 /home:用户主目录 /root:root用户主目录 /boot:Linux的启动目录 /usr:用户级目录 3.工作目录及其父目录课分别用什么表示? . 和 .. 5.常用的shell环境变量有哪些? ·HOME:用户家目录的完全路径名 ·LOGNAME:登录用户名 ·IFS:命令行内部域分割符 ·PATH:由冒号分隔的目录路径名

Linux定时任务设置

Linux 下定时任务设置 文章分类:操作系统 为当前用户创建cron服务 1. 键入crontab -e 编辑crontab服务文件 例如文件内容如下: */2 * * * * /bin/sh /home/admin/jiaoben/buy/deleteFile.sh 保存文件并并退出 */2 * * * * /bin/sh /home/admin/jiaoben/buy/deleteFile.sh */2 * * * * 通过这段字段可以设定什么时候执行脚本 /bin/sh /home/admin/jiaoben/buy/deleteFile.sh 这一字段可以设定你要执行的脚本,这里要注意一下bin/sh 是指运行脚本的命令后面一段时指脚本存放的路径 2. 查看该用户下的crontab服务是否创建成功,用crontab -l命令 3. 启动crontab服务 一般启动服务用/sbin/service crond start 若是根用户的cron服务可以用sudo service crond start,这里还是要注意下不同版本linux系统启动的服务的命令也不同,像我的虚拟机里只需用sudo service cron restart 即可,若是在根用下直接键入service cron start 就能启动服务

4. 查看服务是否已经运行用ps -ax | grep cron 5. crontab命令 cron服务提供crontab命令来设定cron服务的,以下是这个命令的一些参数与说明: crontab -u //设定某个用户的cron服务,一般root用户在执行这个命令的时候需要此参数 crontab -l //列出某个用户cron服务的详细内容 crontab -r //删除没个用户的cron服务 crontab -e //编辑某个用户的cron服务 比如说root查看自己的cron设置:crontab -u root -l 再例如,root想删除fred的cron设置:crontab -u fred -r 在编辑cron服务时,编辑的内容有一些格式和约定,输入:crontab -u root -e 进入vi编辑模式,编辑的内容一定要符合下面的格式:*/1 * * * * ls >> /tmp/ls.txt 任务调度的crond常驻命令 crond 是linux用来定期执行程序的命令。当安装完成操作系统之后,默认便会启动此 任务调度命令。crond命令每分锺会定期检查是否有要执行的工作,如果有要执行的工 作便会自动执行该工作。

最小的Linux操作系统制作过程详解

最小的Linux操作系统制作过程详解 一,什么是BabyLinux BabyLinux不是一个完整的发行版,他是利用原有的一套完整的linux系统的内核原代码和编译工具,利用busybox内建的强大功能,在一张软盘上做的一个很小的linux系统。他具备一个linux系统的基本特征,支持linux系统最常用的一百多个命令,支持多种文件系统,支持网络等等,你可以把他当做一张linux 起动盘和修复盘来用,你也可以把他当做一个静态路由的路由器软件,当然,你也可以把他当做一个linux玩具,向你的朋友炫耀linux可以做的多么小。我把他叫做BabyLinux因为他很小巧,小的很可爱,像一个刚刚出生的小baby。 二.为什么要作这样一个linux 先说说我一开始的想法,当我一开始接触linux的时候,看到书上说,linux 通常安装只需要60M左右的空间,但是我发现装在我硬盘上的Redhat 6.0确要占据好几百M的空间。为什么我的linux这么大呢? 后来我发现,装在我机器上的那么多东西只有不到30%是我平时常用的,还有30%是我极少用到的,另外的40%基本上是不用的。于是,我和大多数初学者一样,开始抱怨,为什么linux 不能做的精简一点呢?于是,我萌发了自己裁减系统的想法。可惜那个时候我还没有听说过有LFS和Debain。等到我积累了足够的linux知识后,我开始制作这样一个小系统。 制作这样一个小系统最大的意义在于,你可以通过制作系统了解linux的启动过程,学会ramdisk的使用,让你在短时间内学到更多的linux知识。当然,你会得到很大的乐趣。这个项目只是做一个具有基本特征的linux系统,如果你想自己做一个具有完整功能的linux,请阅读Linux From Scratch (LFS)文档。 三,什么人适合读这篇文档 如果你是一个linux爱好者,并且很想了解linux的启动过程和系统的基本结构,而且是一个喜欢动手研究小玩意的人,那么这个文档可以满足你的需求。如果你仅仅是用linux来做一些普通的日常工作,而不在乎你的linux到底怎么工作,那么这份文档也许不太适合你。另外,如果你是linux爱好者,但是目前还是一个刚刚入门的newbi,我建议你先把linux命令学好。不过我想我会尽可能的把这份文档写详细一些,如果你有足够的毅力,或许一个newbi也能成功做一个babylinux。或者,你遇到一件很不巧的事情,比如你的老婆来例假了,你的这个周末就泡汤了,那么阅读这篇文档并做一个linux小玩具可以打发你的时间。 四,应该具备的知识 在做一个babylinux之前,你应当已经会应用linux最常用的命令。并且至少有一次成功编译并安装系统内核的经历,会通过编译源代码来安装软件。如果你具备了这些条件,那么做这样一个小系统会很顺利,如果你还没有掌握这些知识,你可能会遇到一些困难。但是只要有毅力,也可以成功。你不需要具备编程的知识,因为我的目标是:让具有中等以上linux水平的爱好者可以通过阅读文档轻松完成这个项目。关于一张软盘上的linux还有一个很著名的linux叫LOAP

相关主题