Linux系统启动及定制过程

Linux系统启动及定制过程,第1张

CentOS的启动流程总体顺序如下:

POST --> Boot Sequence --> bootloader(MBR) --> Kernel --> 加载rootfs --> switchroot --> /sbin /init --> (配置文件:/etc/inittab, /etc/init/conf) --> 根据init配置文件设置默认运行级别 --> 运行系统初始化脚本/etc/rcd/rcsysinit,完成系统初始化 --> 开启或关闭用户选定的对应运行级别下所对应的服务 --> 启动终端,打印登录提示符。

注:前面加粗部分代表内核空间的系统启动流程,后面未加粗部分代表用户空间的系统启动流程。

第一步:硬件启动过程

POST加电自检

主要实现的功能是检测各个外围硬件设备是否存在而且能够正常运行起来,实现这一自检功能的是固化在主板上的ROM(主要代表为CMOS)芯片上的BIOS(Basic Input/Output System)程序;例如BIOS会检测CPU、Memory以及I/O设备是否能够正常运行,如果是个人计算机的话可能还会检测一下显示器。只要一通电,CPU就会自动去加载ROM芯片上的BIOS程序,是这样来实现的。而检测完成之后就进行硬件设备的初始化。

选择启动设备以加载MBR

主要实现的功能是选择要启动的硬件设备,选择了之后就可以读取这个设备上位于MBR里头的bootloader了。这一步的实现是这样的:根据BIOS中对启动顺序的设定,BIOS自己会依次扫描各个引导设备,然后第一个被扫描到具有引导程序(bootloader)的设备就被作为要启动的引导设备。

MBR(Main Boot Record),是硬盘的0柱面,0磁道、1扇区(第一个扇区),称为主引导扇区,也称为主引导记录。它由三部分组 成:主引导程序(BootLoader)、硬盘分区表DPT(Disk Partition table)和硬盘有效标志(55AA)。

注:硬盘默认一个扇区大小为512字节。

第一部分,主引导程序(BootLoader)占446个字节,负责从活动分区中装载,并运行系统引导程序。

第二部分,硬盘分区表DPT占64个字节,有4个分区表项,每个分区表项占16个字节,硬盘中分区有多少以及每一个分区的大小都记 录在其中。

第三部分,硬盘有效标志,占2个字节,固定为55AA。如果这个标志位0xAA55,就认为这个是MB

第二步:GRUB引导阶段

不同的系统有不同的主引导程序(BootLoader)。Windows使用的是NTLDR(NT Loader,Windows NT系列 *** 作系统)、Bootmgr(Boot Manager,Windows Vista,7,8,10),Linux一般使用的是grub(也叫grub legacy)和grub2。GRUB程序加载执行并引导kernel(内核)程序,其中有三个阶段,Grub引导阶段的文件都在/boot/grub/目录下。

stage1: 这一阶段执行的就是系统安装时预先写入到MBR的Bootloader程序,即是存放在MBR的前446字节里的程序。它的任务仅是读取(加载)硬盘的0柱面,0磁道,2扇区的内容(/boot/grub/stage1)并执行。

stage15: 这一阶段是Stage1阶段和Stage2阶段的桥梁,功能是加载stage2所在分区的文件系统驱动,让stage1中的bootloader能识别stage2所在分区的文件系统,此后grub程序便有能力去访问/boot/grub/stage2。

stage2: 这一阶段读取并解析grub的配置文件/boot/grub/grubcnf,根据配置文件加载内核镜像到内存中,通过initrd程序建立虚拟根文件系统,最后调用(转交)内核。

第三步:内部引导阶段

加载内核,核心开始解压,启动一些最核心的程序。为了让内核足够的轻小,硬件驱动并没放在内核文件里面。系统仅探测可识别到的所有硬件设备,加载硬件驱动程序,即加载真正的根文件系统所在设备的驱动程序(有可能会借助于ramdisk加载驱动),以只读方式挂载根文件系统,运行用户空间的第一个应用程序:/sbin/init。

第四步:init初始化阶段(系统初始化阶段)

虽然CentOS 5、CentOS 6以及CentOS 7的/etc/init配置文件内容各不相同,但总体的启动流程相同:/sbin/init --> 根据/etc/inittab配置文件设置默认运行级别 --> 运行系统初始化脚本/etc/rcd/rcsysinit,完成系统初始化 --> 关闭或启动用户选定的默认运行级别所对应的服务 。

对于CentOS 5来说,初始化程序init是SysV init,其配置文件为:/etc/inittab; 对于CentOS 6来说,初始化程序init是upstart,其配置文件为:/etc/inittab, /etc/init/ conf,也就是upstart将配置文件拆分成多个,在/etc/init/目录下以conf结尾的都是upstart风格的配置文件,而/etc/inittab仅用于设置默认运行级别; 对于CentOS 7来说,初始化程序init是systemd,其配置文件:/usr/lib/system/systemd/, /etc/systemd/system/ ;

具体执行过程:/sbin/init程序会读取/etc/inittab文件确认运行级别,然后执行/etc/rcd/rc脚本,根据确认的运行级别启动对应/etc/rcd/rc#d/目录下的服务(#为0~6),与此同时执行系统初始化脚本/etc/rcsysinit(软链接,指向/etc/rcd/rcsysinit),还会加载/etc/rclocal(软链接,指向/etc/rcd/rclocal文件)用户自定义服务(脚本)。

CentOS7中初始化进程变为了systemd,systemd即为system daemon,是Linux下的一种init软件,开发目标是提供更优秀的框架以表示系统服务间的依赖关系,并依此实现系统初始化时服务的并行启动,同时达到降低Shell系统开销的效果,最终代替现在常用的System V与BSD风格的init程序。与多数发行版使用的System V风格的init相比,systemd采用了以下的新技术:A采用Socket激活式与总线激活式服务,以提高相互依赖的各服务的并行运行性能;B用Cgroup代替PID来追踪进程,即使是两次fork之后生成的守护进程也不会脱离systemd的控制。

第五步:启动终端

根据前面获取的运行级别来启动终端,mingetty程序是用于启动终端的,它会调用登录程序login,这样就能显示出登录提示符了,类似mingetty这种用于打开终端的程序还有getty等。而如果默认运行级别为5,则会打开图形界面。

第一步:硬件启动过程

这一步和CentOS6差不多,详细请看11内容。

第二步:GRUB引导阶段

从这一步开始,CentOS6和CentOS7的启动流程区别开始展现出来了。CentOS7的主引导程序使用的是grub2,执行过程是先加载bootimg、coreimg两个镜像,再加载MOD模块文件,把grub2程序加载执行,接着解析配置文件/boot/grub/grubcfg,根据配置文件加载内核镜像到内存,之后构建虚拟根文件系统,最后转到内核。

CentOS7中使用命令进行配置,而不直接去修改配置文件了。grubcfg配置文件开头注释部分说明了由/etc/grubd/目录下文件和/etc/default/grub文件组成。改好配置后都需要使用命令grub2-mkconfig -o /boot/grub2/grubcfg,将配置文件重新生成。

第三步:内部引导阶段

这一步与CentOS6也差不多,加载驱动,切换到真正的根文件系统,唯一不同的是执行的初始化程序变成了/usr/lib/systemd/systemd。

第四步:init初始化阶段(系统初始化阶段)

CentOS7中我们的初始化进程变为了systemd。执行默认target配置文件/etc/systemd/system/defaulttarget(这是一个软链接,与默认运行级别有关)。然后执行sysinittarget来初始化系统和basictarget来准备 *** 作系统。接着启动multi-usertarget下的本机与服务器服务,并检查/etc/rcd/rclocal文件是否有用户自定义脚本需要启动。最后执行multi-user下的gettytarget及登录服务,检查defaulttarget是否有其他的服务需要启动。

注意:/etc/systemd/system/defaulttarget指向了/lib/systemd/system/目录下的graphicaltarget或multiusertarget。而graphicaltarget依赖multiusertarget,multiusertarget依赖basictarget,basictarget依赖sysinittarget,所以倒过来执行。

unit对象:unit表示不同类型的systemd对象,通过配置文件进行标识和配置;文件中主要包含了系统服务、监听socket、保存的系统快照以及其他与init相关的信息。(也就是CentOS6中的服务器启动脚本)

第五步:启动终端

systemd执行sysinittarget

systemd启动multi-usertarget下的本机与服务器服务

systemd执行multi-usertarget下面的/etc/rcd/rclocal

Systemd执行multi-usertarget下的gettytarget及登录服务

gettytarget是启动终端的systemd对象。如果到此步骤,系统没有指定启动图形桌面,到此就可以结束了,如果需要启动图形界面,要在此基础上启动桌面程序。

从 CentOS 7 版本之后,系统开始用 systemd 实现init进程,系统启动和服务器守护进程管理器功能,负责在系统启动或运行时,激活系统资源,服务器进程和其它进程。

unit表示不同类型的systemd对象,通过配置文件进行标识和配置;文件中主要包含了系统服务、监听socket、保存的系统快照以及其它与init相关的信息。

32 system unit文件格式

/usr/lib/systemd/system:发行版打包者使用,每个服务最主要的启动脚本设置,类似于之前的/etc/initd/

/etc/systemd/system:系统管理员和用户使用,管理员建立的执行脚本,类似于/etc/rcNd/Sxx的功能,比上面目录优先运行

/lib/systemd/system::ubutun的对应目录

/run/systemd/system:系统执行过程中所产生的服务脚本,比上面目录优先运行

unit 格式说明:

service unit file文件通常由三部分组成:

Unit段的常用选项:

Service段的常用选项:

Install段的常用选项:

注意:对于新创建的unit文件,或者修改了的unit文件,要通知systemd重载此配置文件,而后可以选择重启。

首先在启动界面按e编辑启动参数,

将ro参数更改为rw init=/sysroot/bin/sh,按ctr + x启动系统

按下图执行命令更改root密码

当开机从OS光盘启动,会先加载isolinux下可执行的内核映像vmlinuz,在内存中建立一个虚拟的根文件系统(rootfs),然后内核加载初始RAM磁盘initrdimg,建立一个安装Linux所需要的系统环境,这就是所谓的第一阶段。内核最后会运行initrdimg中的/init程序,由它来启动第二阶段的安装过程,即加载系统安装程序anaconda,执行具体的安装过程。注意如果通过网络方式安装(如NFS方式),则会根据安装树的NFS路径,通过mount把vmlinuz和initrdimg挂载到本地,像访问本地文件一样访问远程文件,以建立安装环境(在具体运行某个文件时会从网络下载到本地)。

initrdimg通常是一个用gzip压缩的cpio归档文件,需要加上gz后缀并用gunzip解压成新的initrdimg,然后用cpio -i --make-directories < initrdimg释放其内容,生成一个小型的根文件系统。可以看到/init程序指向的是/sbin/init程序,里面还有loader程序,这就是编译anaconda源码时生成的两个程序。可见这个initrdimg中的/sbin/init程序是专门为anaconda定制的,常被称为installer类型的init。/sbin/loader程序可以看作是真正的anaconda自己的"init"程序,它由/init程序调用。

sub init ()的意思就是一个sub过程名叫init,init是程序员自定义的

可以是sub a(x), sub b(x,y)这样

sub这句写好后,按回车,vb会在下面自动加一个end sub,你可以在这两句之间写代码,sub过程只可以传入参数不可以返回。

调用就用call,比如call init,call a(xx),call b(xx,yy)

function定义的过程有返回值,

Private Sub Command1_Click()

Text1Text = a(1)'调用a过程

End Sub

Function a(s As Integer)

a = s + 2'直接为过程名赋值就是返回了

End Function

Commands:命令

Actions: 动作

Triggers: 触发条件

Services: 服务

Options: 选项

Propertise: 属性

(1) Commands是一些基本的 *** 作,例如:

mkdir /sdcard 0000 system system mkdir /system

mkdir /data 0771 system system

mkdir /cache 0770 system cache

mkdir /config 0500 root root

mkdir /sqlite_stmt_journals 01777 root root

mount tmpfs tmpfs /sqlite_stmt_journals size=4m

这些命令在init可执行程序中被解析,然后调用相关的函数来实现。

(2) Actions(动作)表示一系列的命令,通常在Triggers(触发条件)中调用,动作和触发条件的形式为:

on

动作的使用示例如下:

on init

export PATH /sbin:/system/sbin:/system/bin:/system/xbin

mkdir /system

init表示一个触发条件,这个触发事件发生后,进行设置环境变量和建立目录的 *** 作称为一个“动作”

(3) Services(服务)通常表示启动一个可执行程序,Options(选项)是服务的附加内容,用于配合服务使用。

service vold /system/bin/vold

socket vold stream 0660 root mount

service bootsound /system/bin/playmp3

user media

group audio

oneshot

vold和bootsound分别是两个服务的名称,/system/bin/vold和/system /bin/playmp3分别是他们所对应的可执行程序。

socket、user、group、oneshot就是配合服务使用的选项。其中oneshot选项表示该服务只启动一次,而如果没有oneshot选项,

这个可执行程序会一直存在--如果可执行程序被杀死,则会重新启动。

(4) Properties(属性)是系统中使用的一些值,可以进行设置和读取。

setprop roFOREGROUND_APP_MEM 1536

setprop roVISIBLE_APP_MEM 2048

on property:rokernelqemu=1

start adbd

setprop 用于设置属性,on property可以用于判断属性,这里的属性在整个Android系统运行中都是一致的。

init脚本的关键字可以参考init进程的system/core/init/keywordh文件。

initrc的使用方法,可以参考说明文件system/core/init/readmetxt

如果想要修改启动过程只需要修改initc(system/core/init)或者initrc里的内容即可

如何去写

Android initrc (Android init language)

Android 初始化语言由四大类声明组成 : 行为类 (Actions), 命令类 (Commands) ,服务类 (Services), 选项类 (Options)

初始化语言以行为单位,由以空格间隔的语言符号组成。 C 风格的反斜杠转义符可以用来插入空白到语言符号。双引号也可以用来防止文本被空格分成多个语言符号。当反斜杠在行末时,作为折行符。

以 # 开始 ( 前面允许有空格 ) 的行为注释行。

Actions 和 Services 隐含声明一个新的段落。所有该段落下 Commands 或 Options 的声明属于该段落。第一段落前的 Commands 或Options 被忽略。

Actions 和 Services 拥有独一无二的命名。在它们之后声明相同命名的类将被当作错误并忽略。

Actions

-------

Actions 是一系列命令的命名。 Actions 拥有一个触发器 (trigger) 用来决定 action 何时执行。当一个 action 在符合触发条件被执行时,如果它还没被加入到待执行队列中的话,则加入到队列最后。

队列中的 action 依次执行, action 中的命令也依次执行。 Init 在执行命令的中间处理其它活动 ( 设备创建 / 销毁 ,property 设置,进程重启) 。

Actions 表现形式为:

on

Services

--------

Services 是由 init 启动,在它们退出时重启 ( 可选 ) 。 Service 表现形式为 :

service [ ]

Options

-------

Options 是 Services 的修饰,它们影响 init 何时、如何运行 service

critical

这是一个设备关键服务 (device-critical service) 如果它在 4 分钟内退出超过 4 次,设备将重启并进入恢复模式。

disabled

这个服务的级别将不会自动启动,它必须被依照服务名指定启动才可以启动。

setenv

设置已启动的进程的环境变量 的值

socket [ [ ] ]

创建一个名为 /dev/socket/ 的 unix domin socket ,并传送它的 fd 到已启动的进程。 必须为 "dgram" 或 "stream" 用户和组默认为 0

user

在执行服务前改变用户名。当前默认为 root 如果你的进程需要 linux 能力,你不能使用这个命令。你必须在还是 root 时请求能力,并下降到你需要的 uid

group [ ]

在执行服务前改变组。在第一个组后的组将设为进程附加组 ( 通过 setgroups()) 当前默认为 root

oneshot

在服务退出后不重启。

class

为 service 指定一个类别名。同样类名的所有的服务可以一起启动或停止。如果没有指定类别的服务默认为 "default" 类。

onrestart

当服务重启时执行一个命令。

Triggers

--------

Triggers( 触发器 ) 是一个字符串,可以用来匹配某种类型的事件并执行一个 action 。

boot

这是当 init 开始后执行的第一个触发器 ( 当 /initconf 被加载 )

=

当 property 被设为指定的值 时触发。

device-added-

device-removed-

当设备节点被添加或移除时触发。

service-exited-

当指定的服务存在时触发

Commands

--------

exec [ ]

Fork 并执行一个程序 () 这将被 block 直到程序执行完毕。最好避免执行例如内建命令以外的程序,它可能会导致 init 被阻塞不动。

export

设定全局环境变量 的值 ,当这个命令执行后所有的进程都可以取得。

ifup

使网络接口 联机。

import

解析一个 init 配置文件,扩展当前配置文件。

hostname

设置主机名

chmod

改变文件访问权限

chown

改变文件所属和组

class_start

当指定类别的服务没有运行,启动该类别所有的服务。

class_stop

当指定类别的服务正在运行,停止该类别所有的服务。

domainname

设置域名。

insmod

加载该路径 的模块

mkdir [mode] [owner] [group]

在 创建一个目录 , 可选选项 :mod,owner,group 如果没有指定,目录以 755 权限, owner 为 root,group 为 root 创建

mount

[ ]

尝试 mount 到目录

可以用 mtd@name 格式以命名指定一个 mtd 块设备。 包含"ro","rw","remount","noatime"

例如:

mount -t vfat -o fmask=0000,dmask=0000,rw,flush,noatime,nodiratime /dev/block/mmcblk1p1 /SD1

chown system system /SD1

chmod 0777 /SD1

mount -t vfat -o fmask=0000,dmask=0000,rw,flush,noatime,nodiratime /dev/block/mmcblk1p6 /SD3

chown system system /SD3

chmod 0777 /SD3

setkey

暂时没有

setprop

设置系统 property 的值

setrlimit

设置 resource 的 rlimit

start

启动一个没有运行的服务。

stop

停止一个正在运行的服务。

symlink

创建一个 的符号链接到

sysclktz

设置系统时区 (GMT 为 0)

trigger

触发一个事件。用于调用其它 action 。

write [ ]

打开 的文件并写入一个或多个字符串。

Properties

----------

Init 会更新一些系统 property 以提供查看它正在干嘛。

initaction

当前正在执行的 action, 如果没有则为 ""

initcommand

被执行的命令,如果没有则为 ""

initsvc

命名为 的服务的状态 ("stopped", "running", "restarting")

initrc 示例 :

-----------------

# not complete -- just providing some examples of usage

#

on boot

export PATH /sbin:/system/sbin:/system/bin

export LD_LIBRARY_PATH /system/lib

mkdir /dev

mkdir /proc

mkdir /sys

mount tmpfs tmpfs /dev

mkdir /dev/pts

mkdir /dev/socket

mount devpts devpts /dev/pts

mount proc proc /proc

mount sysfs sysfs /sys

write /proc/cpu/alignment 4

ifup lo

hostname localhost

domainname localhost

mount yaffs2 mtd@system /system

mount yaffs2 mtd@userdata /data

import /system/etc/initconf

class_start default

service adbd /sbin/adbd

user adb

group adb

service usbd /system/bin/usbd -r

user usbd

group usbd

socket usbd 666

service zygote /system/bin/app_process -Xzygote /system/bin --zygote

socket zygote 666

service runtime /system/bin/runtime

user system

group system

on device-added-/dev/compass

start akmd

on device-removed-/dev/compass

stop akmd

service akmd /sbin/akmd

disabled

user akmd

group akmd

调试

---------------

默认情况下, init 执行的程序输出的信息和错误到 /dev/null 为了 debug ,你可以通过 Android 程序 logwrapper 执行你的程序。这将复位向输出 / 错误输出到 Android logging 系统 ( 通过 logcat 访问 ) 。

===============================================================

Android——initrc脚本

在Android中使用启动脚本initrc,可以在系统的初始化中进行简单的 *** 作。

initrc启动脚本路径:system/core/rootdir/initrc

内容:

Commands:命令

Actions:动作

Triggers:触发条件

Services:服务

Options:选项

Properties:属性

Commands是一些基本 *** 作。如:

mkdir /system

mkdir /data 0771 system system

mkdir /persist 0771 system system

devwait /dev/block/mmcblk0p12

mount ext3 /dev/block/mmcblk0p

Action表示一系列命令,通常在Triggers中调用,如:

on init //表示一个触发条件

sysclktz 0

loglevel 3

# setup the global environment

export PATH /sbin:/system/sbin:/system/bin:/system/xbin

export LD_LIBRARY_PATH /system/lib

export ANDROID_BOOTLOGO 1

Services通常表示启动一个可执行程序,Options是服务的附加内容,用于配合服务使用。

service vold /system/bin/vold //vold是服务名称,/system/bin/vold是所对应的可执行程序。

socket vold stream 0660 root mount //socket是配合服务使用的选项

ioprio be 2

service netd /system/bin/netd

socket netd stream 0660 root system

配合服务使用的选项有socket,user,group,oneshot。

oneshot表示该服务只启动一次,而如果没有oneshot选项,这个可执行程序将一直存在——如果可执行程序被杀死,则会重新启动。

Properties是系统中使用的一些值,可以进行设置和读写。

setprop roHIDDEN_APP_MEM 5120 //setprop用于设置属性

setprop roCONTENT_PROVIDER_MEM 5632

setprop roEMPTY_APP_MEM 6144

on property:rokernelqemu=1 //on property用于判断属性

start adbd

这里的属性在整个android系统运行中都是一致的。

init脚本的关键字可以参考init进程中的system/core/init/keywordh文件。如:

KEYWORD(chroot, COMMAND, 1, do_chroot) //chroot是命令,do_chroot()是调用的函数,这个函数在init进程中的system/core/init/builtinsc文件中定义。

例如:

service akmd /system/bin/logwrapper /sbin/akmd

高精度算法

一个快速入门的秘诀就是“背”,这个“背”字可以大做文章,想当年我就靠这种方法迅速建立起初步信息学知识体系的。

这是《信息学初学者之家》站长、曾多次参加AcM竞赛并获优异成绩的tenshi所发的切身体会。因此,我们要求,下面的算法不仅要读得懂,而且要熟记于心,这样,你才能在程序设计中灵活地运用……

1、高精度加法

高精度加法程序如下:

Program HighPrecision1_Plus;

const

fn_inp='hp1inp';

fn_out='hp1out';

maxlen=100; { 数的最大长度 }

type

hp=record

len:integer; { 数的长度 }

s:array[1maxlen] of integer

{ s[1]为最低位,s[len]为最高位 }

end;

var

x:array[12] of hp;

y:hp; { x:输入 ; y:输出 }

procedure PrintHP(const p:hp);

var i:integer;

begin

for i:=plen downto 1 do write(ps[i]);

end;

procedure init; {初始化}

var

st:string;

j,i:integer;

begin

assign(input,fn_inp);

reset(input);

for j:=1 to 2 do

begin

readln(st);

x[j]len:=length(st);

for i:=1 to x[j]len do { 将字符串转换到HP }

x[j]s[i]:=ord(st[x[j]len+1-i])-ord('0');

end;

close(input);

end;

procedure Plus(a,b:hp;var c:hp); { c:=a+b }

var i,len:integer;

begin

fillchar(c,sizeof(c),0);

if alen>blen then len:=alen { 从a,b中取较大长度 }

else len:=blen;

for i:=1 to len do { 从低到高相加 }

begin

inc(cs[i],as[i]+bs[i]);

if cs[i]>=10 then

begin

dec(cs[i],10);

inc(cs[i+1]); { 加1到高位 }

end;

end;

if cs[len+1]>0 then inc(len);

clen:=len;

end;

procedure out; {打印输出}

begin

assign(output,fn_out);

rewrite(output);

PrintHP(y);

writeln;

close(output);

end;

begin

init;

Plus(x[1],x[2],y);

out;

end

2、 高精度减法

高精度减法程序如下:

Program HighPrecision2_Subtract;

const

fn_inp='hp2inp';

fn_out='hp2out';

maxlen=100; { 数的最大长度 }

type

hp=record

len:integer; { 数的长度 }

s:array[1maxlen] of integer

{ s[1]为最低位,s[len]为最高位 }

end;

var

x:array[12] of hp;

y:hp; { x:输入 ; y:输出 }

positive:boolean;

procedure PrintHP(const p:hp);

var i:integer;

begin

for i:=plen downto 1 do write(ps[i]);

end;

procedure init;

var

st:string;

j,i:integer;

begin

assign(input,fn_inp);

reset(input);

for j:=1 to 2 do

begin

readln(st);

x[j]len:=length(st);

for i:=1 to x[j]len do { change string to HP }

x[j]s[i]:=ord(st[x[j]len+1-i])-ord('0');

end;

close(input);

end;

procedure Subtract(a,b:hp;var c:hp); { c:=a-b, suppose a>=b }

var i,len:integer;

begin

fillchar(c,sizeof(c),0);

if alen>blen then len:=alen { get the bigger length of a,b }

else len:=blen;

for i:=1 to len do { subtract from low to high }

begin

inc(cs[i],as[i]-bs[i]);

if cs[i]<0 then

begin

inc(cs[i],10);

dec(cs[i+1]); { add 1 to a higher position }

end;

end;

while(len>1) and (cs[len]=0) do dec(len);

clen:=len;

end;

function Compare(const a,b:hp):integer;

{

1 if a>b

0 if a=b

-1 if a < b

}

var len:integer;

begin

if alen>blen then len:=alen { get the bigger length of a,b }

else len:=blen;

while(len>0) and (as[len]=bs[len]) do dec(len);

{ find a position which have a different digit }

if len=0 then compare:=0 { no difference }

else compare:=as[len]-bs[len];

end;

procedure main;

begin

if compare(x[1],x[2])<0 then positive:=false

else positive:=true;

if positive then Subtract(x[1],x[2],y)

else Subtract(x[2],x[1],y);

end;

procedure out;

begin

assign(output,fn_out);

rewrite(output);

if not positive then write('-');

PrintHP(y);

writeln;

close

(output);

end;

begin

init;

main;

out;

end

3、高精度乘法

1)高精度乘单精度(1位数)

程序如下:

Program HighPrecision3_Multiply1;

const

fn_inp='hp3inp';

fn_out='hp3out';

maxlen=100; { 数的最大长度 }

type

hp=record

len:integer; { 数的长度 }

s:array[1maxlen] of integer

{ s[1]为最低位,s[len]为最高位 }

end;

var

x:array[12] of hp;

y:hp; { x:输入 ; y:输出 }

procedure PrintHP(const p:hp);

var i:integer;

begin

for i:=plen downto 1 do write(ps[i]);

end;

procedure init;

var

st:string;

i:integer;

begin

assign(input,fn_inp);

reset(input);

readln(st);

xlen:=length(st);

for i:=1 to xlen do { change string to HP }

xs[i]:=ord(st[xlen+1-i])-ord('0');

readln(z);

close(input);

end;

procedure Multiply(a:hp;b:integer;var c:hp); { c:=ab }

var i,len:integer;

begin

fillchar(c,sizeof(c),0);

len:=alen;

for i:=1 to len do

begin

inc(cs[i],as[i]b);

inc(cs[i+1],cs[i] div 10);

cs[i]:=cs[i] mod 10;

end;

inc(len);

while(cs[len]>=10) do

begin

inc(cs[len+1],cs[len] div 10);

cs[len]=cs[len] mod 10;

inc(len);

end;

while(len>1) and (cs[len]=0) do dec(len);

clen:=len;

end;

procedure main;

begin

Multiply(x,z,y);

end;

procedure out;

begin

assign(output,fn_out);

rewrite(output);

PrintHP(y);

writeln;

close(output);

end;

begin

init;

main;

out;

end

2)高精度乘一个整型数据(integer)

只需要将上述程序的hp类型定义如下即可:

type

hp=record

len:integer { length of the number }

s:array[1maxlen] of longint

{ s[1] is the lowest position

s[len] is the highest position }

end;

3)高精度乘高精度

程序如下:

Program HighPrecision4_Multiply2;

const

fn_inp='hp4inp';

fn_out='hp4out';

maxlen=100; { max length of the number }

type

hp=record

len:integer; { length of the number }

s:array[1maxlen] of integer

{ s[1] is the lowest position

s[len] is the highest position }

end;

var

x:array[12] of hp;

y:hp; { x:input ; y:output }

procedure PrintHP(const p:hp);

var i:integer;

begin

for i:=plen downto 1 do write(ps[i]);

end;

procedure init;

var

st:string;

j,i:integer;

begin

assign(input,fn_inp);

reset(input);

for j:=1 to 2 do

begin

readln(st);

x[j]len:=length(st);

for i:=1 to x[j]len do { change string to HP }

x[j]s[i]:=ord(st[x[j]len+1-i])-ord('0');

end;

close(input);

end;

procedure Multiply(a,b:hp;var c:hp); { c:=a+b }

var i,j,len:integer;

begin

fillchar(c,sizeof(c),0);

for i:=1 to alen do

for j:=1 to blen do

begin

inc(cs[i+j-1],as[i]bs[j]);

inc(cs[i+j],cs[i+j-1] div 10);

cs[i+j-1]:=cs[i+j-1] mod 10;

end;

len:=alen+blen+1;

{

the product of a number with i digits and a number with j digits

can only have at most i+j+1 digits

}

while(len>1)and(cs[len]=0) do dec(len);

clen:=len;

end;

procedure main;

begin

Multiply(x[1],x[2],y);

end;

procedure out;

begin

assign(output,fn_out);

rewrite(output);

PrintHP(y);

writeln;

close(output);

end;

begin

init;

main;

out;

end

4、 高精度除法

1)高精度除以整型数据(integer);

程序如下:

Program HighPrecision3_Multiply1;

const

fn_inp='hp5inp';

fn_out='hp5out';

maxlen=100; { max length of the number }

type

hp=record

len:integer; { length of the number }

s:array[1maxlen] of integer

{ s[1] is the lowest position

s[len] is the highest position }

end;

var

x,y:hp;

z,w:integer;

procedure PrintHP(const p:hp);

var i:integer;

begin

for i:=plen downto 1 do write(ps[i]);

end;

procedure init;

var

st:string;

i:integer;

begin

assign(input,fn_inp);

reset(input);

readln(st);

xlen:=length(st);

for i:=1 to xlen do { change string to HP }

xs[i]:=ord(st[xlen+1-i])-ord('0');

readln(z);

close(input);

end;

procedure Divide(a:hp;b:integer;var c:hp;var d:integer);

{ c:=a div b ; d:=a mod b }

var i,len:integer;

begin

fillchar(c,sizeof(c),0);

len:=alen;

d:=0;

for i:=len downto 1 do { from high to low }

begin

d:=d10+as[i];

cs[i]:=d div b;

d:=d mod b;

end;

while(len>1) and (cs[len]=0) do dec(len);

clen:=len;

end;

procedure main;

begin

Divide(x,z,y,w);

end;

procedure out;

begin

assign(output,fn_out);

rewrite(output);

PrintHP(y);

writeln;

writeln(w);

close(output);

end;

begin

init;

main;

out;

end

2)高精度除以高精度

程序如下:

Program HighPrecision4_Multiply2;

const

fn_inp='hp6inp';

fn_out='hp6out';

maxlen=100; { max length of the number }

type

hp=record

len:integer; { length of the number }

s:array[1maxlen] of integer

{ s[1] is the lowest position

s[len] is the highest position }

end;

var

x:array[12] of hp;

y,w:hp; { x:input ; y:output }

procedure PrintHP(const p:hp);

var i:integer;

begin

for i:=plen downto 1 do write(ps[i]);

end;

procedure init;

var

st:string;

j,i:integer;

begin

assign(input,fn_inp);

reset(input);

for j:=1 to 2 do

begin

readln(st);

x[j]len:=length(st);

for i:=1 to x[j]len do { change string to HP }

x[j]s[i]:=ord(st[x[j]len+1-i])-ord('0');

end;

close(input);

end;

procedure Subtract(a,b:hp;var c:hp); { c:=a-b, suppose a>=b }

var i,len:integer;

begin

fillchar(c,sizeof(c),0);

if alen>blen then len:=alen { get the bigger length of a,b }

else len:=blen;

for i:=1 to len do { subtract from low to high }

begin

inc(cs[i],as[i]-bs[i]);

if cs[i]<0 then

begin

inc(cs[i],10);

dec(cs[i+1]); { add 1 to a higher position }

end;

end;

while(len>1) and (cs[len]=0) do dec(len);

clen:=len;

end;

function Compare(const a,b:hp):integer;

{

1 if a>b

0 if a=b

-1 if a < b

}

var len:integer;

begin

if alen>blen then len:=alen { get the bigger length of a,b }

else len:=blen;

while(len>0) and (as[len]=bs[len]) do dec(len);

{ find a position which have a different digit }

if len=0 then compare:=0 { no difference }

else compare:=as[len]-bs[len];

end;

procedure Multiply10(var a:hp); { a:=a10 }

var i:Integer;

begin

for i:=alen downto 1 do

as[i+1]:=as[i];

as[1]:=0;

inc(alen);

while(alen>1) and (as[alen]=0) do dec(alen);

end;

procedure Divide(a,b:hp;var c,d:hp); { c:=a div b ; d:=a mod b }

var i,j,len:integer;

begin

fillchar(c,sizeof(c),0);

len:=alen;

fillchar(d,sizeof(d),0);

dlen:=1;

for i:=len downto 1 do

begin

Multiply10(d);

ds[1]:=as[i]; { d:=d10+as[i] }

{ cs[i]:=d div b ; d:=d mod b; }

{ while(d>=b) do begin d:=d-b;inc(cs[i]) end }

while(compare(d,b)>=0) do

begin

Subtract(d,b,d);

inc(cs[i]);

end;

end;

while(len>1)and(cs[len]=0) do dec(len);

clen:=len;

end;

procedure main;

begin

Divide(x[1],x[2],y,w);

end;

procedure out;

begin

assign(output,fn_out);

rewrite(output);

PrintHP(y);

writeln;

PrintHP(w);

writeln;

close(output);

end;

begin

init;

main;

out;

end

比如编写了简单的HELLO WORLD!程序 怎么才能让这个程序在Linux下开机自启动?

一、启动内核

首先介绍启动内核部分。电脑启动时,BIOS装载MBR,然后从当前活动分区启动,LILO获得引

导过程的控制权后,会显示LILO提示符。此时如果用户不进行任何 *** 作,LILO将在等待制定

时间后自动引导默认的 *** 作系统,而如果在此期间按下TAB键,则可以看到一个可引导的 *** 作

系统列表,选择相应的 *** 作系统名称就能进入相应的 *** 作系统。

当用户选择启动LINUX *** 作系统时,LILO就会根据事先设置好的信息从ROOT文件系统所在的分

区读取LINUX映象,然后装入内核映象并将控制权交给LINUX内核。LINUX内核获得控制权后,

以如下步骤继续引导系统:

1 LINUX内核一般是压缩保存的,因此,它首先要进行自身的解压缩。内核映象前面的一些

代码完成解压缩。

2 如果系统中安装有可支持特殊文本模式的、且LINUX可识别的SVGA卡,LINUX会提示用户

选择适当的文本显示模式。但如果在内核的编译过程中预先设置了文本模式,则不会提示选

择显示模式。该显示模式可通过LILO或RDEV工具程序设置。

3 内核接下来检测其他的硬件设备,例如硬盘、软盘和网卡等,并对相应的设备驱动程序

进行配置。这时,显示器上出现内核运行输出的一些硬件信息。

4 接下来,内核装载ROOT文件系统。ROOT文件系统的位置可在编译内核时指定,也可通过

LILO或RDEV指定。文件系统的类型可自动检测。如果由于某些原因装载失败,则内核启动

失败,最终会终止系统。

二、执行init程序

其次介绍init程序,利用init程序可以方便地定制启动其间装入哪些程序。init的任务是

启动新进程和退出时重新启动其它进程。例如,在大多数Linux系统中,启动时最初装入

六个虚拟的控制台进程,退出控制台窗口时,进程死亡,然后init启动新的虚拟登录控制台,

因而总是提供六个虚拟登陆控控制台进程。

控制init程序 *** 作的规则存放在文件/etc/inittab中。Red Hat Linux缺省的inittab文

件如下:

#

#inittab This file describes how the INIT process should set up the system in a certain

#run-level

#

#

#Default runlevelThe runlevels used by RHS are:

#0-halt(Do NOT set initdefault to this)

#1-Single user mode

#2-Multiuser,without NFS(the same as 3,if you do not have networking)

#3-Full multiuser mode

#4-unused

#5-X11

#6-reboot(Do NOT set initdefault to this)

#

id:3:initdefault:

#system initialization

si::sysinit:/etc/rcd/rcsysinit

10:0:wait:/etc/rcd/rc 0

11:1:wait:/etc/rcd/rc 1

12:2:wait:/etc/rcd/rc 2

13:3:wait:/etc/rcd/rc 3

14:4:wait:/etc/rcd/rc 4

15:5:wait:/etc/rcd/rc 5

16:6:wait:/etc/rcd/rc 6

#Things to run in every runlevel

ud:once:/sbin/update

#Trap CTRL-ALT-DELETE

ca::ctrlaltdel:/sbin/shutdown -t3 -r now

#When our UPS tells us power has failed,assume we have a few minutes of

power leftSchedule a

#shutdown for 2 minutes from now

#This does,of course,assume you have powered installed and your UPS

connected and working

#correctly

pf::powerfail:/sbin/shutdown -f -h +2 "Power Restored;Shutdown Cancelled"

#Run gettys in standard runlevels

1:12345:respawn:/sbin/minggetty tty1

2:2345:respawn:/sbin/minggetty tty2

3:2345:respawn:/sbin/minggetty tty3

4:2345:respawn:/sbin/minggetty tty4

5:2345:respawn:/sbin/minggetty tty5

6:2345:respawn:/sbin/minggetty tty6

#Run xdm in runlevel 5

x:5:respawn:/usr/bin/X11/xdm -nodaemon

Linux有个运行级系统,运行级是表示系统当前状态和init应运行哪个进程并保持在这种

系统状态中运行的数字。在inittab文件中,第一个项目指定启动时装入的缺省运行级。

上例中是个多用户控制台方式,运行级为3。然后,inittab文件中每个项目指定第二个

字段的项目用哪种运行级(每个字段用冒号分开)。因此,对运行级3,下列行是相关的:

13:3:wait:/etc/rcd/rc 3

1:12345:respawn:/sbin/minggetty tty1

2:2345:respawn:/sbin/minggetty tty2

3:2345:respawn:/sbin/minggetty tty3

4:2345:respawn:/sbin/minggetty tty4

5:2345:respawn:/sbin/minggetty tty5

6:2345:respawn:/sbin/minggetty tty6

最后六行建立Linux提供的六个虚拟控制台。第一行运行启动脚本/etc/rcd/ rc 3;

这将运行目录/etc/

rcd/rc3d中包含的所有脚本,这些脚本表示系统初始化时要启动的程序。一般来说,

这些脚本不需要编辑或改变,是系统缺省的。

以上就是关于Linux系统启动及定制过程全部的内容,包括:Linux系统启动及定制过程、linux 安装anaconda后怎样打开、VB程序中 sub init ()意思等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/10172721.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-06
下一篇 2023-05-06

发表评论

登录后才能评论

评论列表(0条)

保存