《鸟哥的Linux私房菜》笔记
提到Linux,就不得不提GNU和GPL授权所产生的自由软件(free software)与开放源码(Open Source)等。
我们将通过Linux操作系统里面的执行文件来理解什么是可执行的程序,以及了解什么是编译程序。另外,与程序息息相关的函数库(library)的信息也需要了解一番!
在这节中,希望你可以了解如何将开放源码的程序设计、加入函数库的原理、通过编译而成为可执行的二进制程序(Binary Program),到最后该执行文件可被我们所使用的一连串过程。
开放源码的软件安装与升级简介
如果我想要在我的Linux主机上面跑web服务(WWW),那我就一定需要安装web服务器软件才行。同理,在Linux主机上进行一些有的没的功能,学会如何安装软件就十分重要了。
在Windows操作系统上,安装软件点击“下一步”就行了。不过也由于此,在Windows系统上面的软件都是一模一样的,因此你无法修改该软件的源代码。万一你想增加或减少该软件的某些功能时,大概就只能求助于软件发行商了。
像目前的病毒、木马等,都可能对你主机上面的某些软件造成影响,导致主机出现问题。如果你能够借由安全信息单位提供的修改方式进行修改,那么你将很快速的自行修补好软件漏洞,而不必等到软件发行商提供的补丁。
要知道,提早打补丁是一件很重要的事情。
因为Linux上面的软件几乎都是经过GPL的授权,所以每个软件几乎均提供源代码,并且你可以自行修改代码,以符合你个人的需求!
什么是开放源码、编译器与可执行文档
在讨论一个程序代码是很么之前,我们先来谈论一下什么是可执行文件。
在Linux系统上面,一个文件能不能被执行看的是有没有可执行权限(X)。不过,Linux系统上真正认识的可执行文件其实是二进制文件(binary program),如/bin/touch即为二进制程序代码。
shell scripts虽然也能够执行,但它只是利用shell(bash)这个程序的功能来进行一些判断式,而最终执行的除了bash提供的功能外,仍是调用一些已经编译好的二进制程序来执行的!当然,bash本身就是一个二进制程序。
利用file命令来查看一个文件是否为binary
如果是binary而且可执行的话,他就会显示执行文件类别(ELF 64-bit LSB executable),同时会说明是否使用共享库(uses shared libs)。而如果是一般的script,那它就会显示 text executable之类的字样。
事实上,/etc/init.d/network显示的Bourne-Again shell script这,是因为我们script的#!/bin/bash的原因。
既然Linux操作系统真正认识的其实是binary program,那么我们是如何做出这样一个二进制程序的呢?
首先,必须要写程序,一般用文本处理器(如vi)或IDE来进行程序的编写,写完的程序就是所谓的程序源代码啰;
程序源代码其实就是一般的纯文本文件;
在完成源代码的编写后,接下来就是将这个文件 “编译” 称为操作系统能够看懂的二进制程序;
编译自然需要用到“编译器”来操作,经过编译程序的编译与连接之后,生成一个可执行的二进制程序。
举例来说,在Linux上最标准的程序语言是C,我使用C进行原始程序的书写。写完后,以Linux上标准的C语言编译器gcc这个程序来编译,就可以制作出一个可执行的二进制程序了。
事实上,编译过程中还会产生所谓的“目标文件(Object file)”,以 “.o”结尾。C语言的源码文件通常以“.c”结尾。
此外,有时我们在程序中“调用、引用”其他外部子程序,或者是利用其他软件提供的函数功能。这个时候,我们就必须在编译的过程中,将该函数库加进去。如此一来,编译程序就可以将所有的程序代码与函数库做一个链接(Link)以生成正确的执行文件。
开放源码:就是程序源代码,写给人类看的程序语言,但机器并不认识,所以无法执行;
编译器:将程序源码编译成为机器看得懂的语言,类似翻译者的角色;
可执行文件:经过编译程序编译后,变成机器看得懂的二进制程序后称为可以执行的文件;
什么是函数库
什么是函数库?举个栗子,我们Linux系统上通常已经提供一个可以进行身份验证的模块--PAM模块。这个模块提供的功能可以让很多的程序在被执行的时候,除了可以验证使用者登录信息外,还可以将身份确认的资料记录在日志文件里,以方便系统管理员的追踪。
既然有这么好的功能,那如果我要编写具有身份认证功能的程序时,直接引用该PAM的功能就好啦,我也不需要重新设计认证机制!也就是说,在我的程序代码里面,设置去掉用PAM的函数功能,我的程序就可以利用Linux原本的身份认证程序。此外,Linux内核也提供了相当多的函数库给硬件开发者利用。
函数库又分为动态函数库与静态函数库。函数库,类似于子程序的角色,可以被调用来执行的一段功能函数。
什么是make与configure
事实上,使用类似于gcc的编译器来进行编译的过程并不简单。因为一套软件并不会仅有一个程序,而是一堆程序程序代码文件。所以除了每个主程序与子程序需要写上一条编译过程的指令外,还需要写上最终的链接程序。
这个时候,我们就可以使用make这个命令的相关功能来进行编译过程的命令简化了!
当执行make时,make会在当前的目录下搜寻Makefile(makefile)这个文本文件,而Makefile里面则记录了源码如何编译的详细信息。make会自动判别源码是否经过变动了而自动更新执行文件。
make是一个程序,会去找Makefile这个文本文件。通常软件开发商都会写一个检测程序来检测用户的操作环境,以及该操作系统是否有软件开发商所需要的其他功能。该检测程序检测完毕后,就会主动建立这个Makefile的规则文件啦。通常这个检测程序的文件名是configure或者config。
为什么要检测操作系统?不同Linux版本内核使用的系统调用可能不同,而且每个软件所依赖的函数库也不相同。
同时,软件开发商不会仅针对Linux开发,而是对整个Unix-Like做开发。所以它也必须要检测该操作系统平台有没有提供合适的编译器!当然就要检测环境啊!
检测是否有适合的编译器,来编译本软件的程序源代码;
检测是否已经存在本软件所需要的函数库,或其他需要的依赖软件;
检测操作系统平台是否适合本软件,包括Linux的内核版本;
检测内核的头定义文件(header include)是否存在,驱动程序必须要检测。
由于不同的Linux distribution的函数库文件所放置的路径,或者是函数库的文件名定义,或者是预安装的编译器,以及内核的版本都不相同。
因此,同一套软件在不同的平台上执行时,必须要重复编译,因此才需要源码。
什么是Tarball的软件
如果能够将这些程序源码通过打包与压缩的技术来将文件的数量与容量减小。不但让用户容易下载,软件开发商网络带宽也能够节省很多。这就是Tarball文件的由来。
一个内核的源码文件大概是几百M,如果每个人都去下载这样的一个内核文件,那网络带宽会变得很拥挤!
所谓的Tarball文件,其实就是将软件的所有源码文件先以 "tar"打包,然后再通过压缩技术来压缩。通常是以 gzip来压缩。
因为利用了 tar 和 gzip 的功能,所以tarball文件一般的文件扩展名为 .tar.gzip 或者是简写 .tgz;不过由于 bzip2 与 xz 的压缩效率较好,所以Tarball渐渐地以 bzip2 和 xz 的压缩技术来取代 gzip啰。因此文件扩展名也有 .tar.bz2 , .tar.xz之类的。
所以说,Tarball是一个压缩包,你将它解压之后,里面的文件通常会有:
源代码文件(Source Code);
检测程序文件(configure或config);
本软件的简易说明与安装说明(INSTALL 和 README)。
INSTALL和README文件是很重要的,参考着两个文件Tarball软件的安装就很简单了。
如何安装和升级软件
那么怎么安装与升级一个Tarball软件呢?
新版本有新功能;
旧版本有安全漏洞;
旧版本软件执行效率不佳。
当一个软件有安全问题时,千万不要怀疑,赶紧更新。基本上更新方法有两类:
直接以源码通过编译来安装与升级;
直接以编译好的二进制程序来安装与升级。
直接源码的方式虽然具有很高的弹性,但毕竟麻烦一点。如果Linux distribution厂商能够针对自己的系统平台进行编译等过程,再将编译好的二进制程序放出的话,由于环境是相同的,那就可以直接在我的电脑上面安装,省去复杂编译的过程。
预先编译好的程序的机制存在于很多distribution,包括Red Hat系统发展的RPM软件管理机制与yum在线更新模式。Debian使用的dpkg软件管理机制与apt在线更新模式等等。
一个软件的Tarball是如何安装的呢?
1,将Tarball由厂商的网页上下载下来;
2,将Tarball解压,生成很多源码文件;
3,开始以gcc进行源码的编译(会产生object files);
4,然后以gcc进行函数库、主程序、子程序的链接,已形成主要的二进制程序;
#3,4步骤可以通过make命令来简化
5,将上述的二进制程序以及相关的配置文件安装到自己的主机上。
使用传统程序语言进行编译的简单范例
经过上面介绍之后,你应该比较清楚的知道“源码、编译器、函数库与可执行文件”之间的相关性了。
单一程序:输出 Hello World
以Linux上最常见的C语言来编写这个程序。
请确认Linux系统里面安装了gcc编译器;
rpm -q gcc
yum groupinstall Development Tools #安装开发工具
编辑程序源代码:
vim hello.c \\建议带上C文件后缀名
#include <stdio.h> \\#号行并不是注释
int main(void)
{
print("Hello World\n")
}
编译与执行:
在默认状态下,我们直接以 gcc 编译源码,并且不加上任何参数,则执行文件会被自动设置为 a.out 这个文件名,这个 a.out 就是编译成功的可执行二进制程序。
如果我们想要产生目标文件(object file)来进行其他动作,并且修改默认的执行文件名称。
只要编译生成一个 a.out 二进制文件就好了嘛,为什么还要生成目标文件后再生成可执行文件?接着往下看吧!
主程序、子程序链接:子程序的编译
如果我们在一个主程序里面又调用了另一个子程序呢?这是一个很常见的程序写法,可以简化整个程序的可读性!在下面例子中,我们以 thanks.c 这个主程序去调用 thanks_2.c 这个子程序。
gcc -c thanks.c thanks_2.c #编译产生 目标文件(object file)
gcc -o thanks thanks.o thanks_2.o #生成可执行文件thanks
现在明白为什么要生成目标文件了吧?由于大多时候我们的源码文件并非只有一个文件,所以我们无法直接进行编译。这个时候就需要先生成目标文件,然后再以链接制作新的二进制可执行文件即可!
另外,如果以后你对thanks_2.c这个文件的内容作了修改,则你只需要重新编译thanks_2.c来产生新的thanks_2.o,然后再以链接制作出新的二进制可执行文件即可!而不必重新编译其他没有改动过的源码文件。
对于软件开发者来说,只用重新编译修改过的文件,这是一个很重要的功能。
调用外部函数库:加入链接的函数库
如果说要计算数学公式呢?看看下面这个程序。
#include <stdio.h>
#include <math.h>
int main(void)
{
float value;
value = sin(3.14/2);
printf("%f\n",value);
}
gcc sin.c #新的 gcc 会主动将函数抓来给你用,所以只要加上 include <math.h>就好!
新版的gcc会主动帮你将所需要的函数库抓进来编译,所以不会出现报错信息!事实上,数学函数库使用的是 libm.so 这个函数库,最好在编译的时候将这个函数库写进去。
另外,这个函数库放置的地方是系统默认会去找的 /lib,/lib64,所以你也可与不使用 -L path去指定函数库目录。
gcc sin.c -lm -L/lib -L/lib64 #指定函数库目录;
# -l 加入某个函数库;
# m 代表libm.so这个函数库,其中lib和文件扩展名( .a 或 .so)不需要写;
#所以 -lm 表示使用libm.so(lib.a)这个函数库的意思。
# -L/path 从给出的path找寻lib.so。
gcc的简单用法(编译、参数、链接)
gcc为Linux上面最标准的编译器,这个gcc是由GNU计划所维护的。介绍几个gcc常用的参数。
另外,我们通常称 -Wall 或者 -O 这些非必要参数为标志(FLAGS),因为我们使用的是C语言,所以有时会称为CFLAGS。这些变量在make先关用法时很重要!
用make进行宏编译
make可以简化编译过程里面所执行的指令,同时还具有很多方便的功能。
为什么要用make
假设我的执行文件里面包含了四个源码文件,分别是main.c,haha.c,sin.c,cos.c这四个文件。
main.c #主要目的让使用者输入角度与调用其他三个子程序;
haha.c #输出一堆有的没的信息;
sin.c #计算输入角度的sin值;
cos.c #计算输入角度cos值。
那么你可能需要这样编译:
gcc -c main.c
gcc -c haha.c
gcc -c sin.c
gcc -c cos.c
#生成目标文件(object file),但不生成二进制程序
gcc -o main main.o haha.o sin.o cos.o #链接成为执行文件
./main #执行可执行文件
编译的过程需要进行好多动作,而且如果要重新编译,则上述的流程还得重来一遍。如果可以的话,能不能一个步骤就给它完成所有动作呢?
make工具就是用来简化gcc编译流程的。
先试试在目录下建立一个Makefile的文件
如果我们建立一个shell script来将上面的所有动作都集结在一起,不是具有同样的效果吗?
效果不一样。以上面的测试为例,我们仅写出了main需要的目标文件,结果make会主动地去判断每个目标文件相关的源码文件,并直接予以编译,最后再直接进行链接的的动作!真的很方便!
此外,如果我们更动过某些源码文件,则make也可以主动的判断哪一个源码与相关的目标文件有改动过,并仅更新该文件!如此一来,将可大大的节省很多编译时间呢!要知道,在程序进行编译行为时,会消耗很多的CPU资源呢!
所以,make有这些好处:
简化编译时所需要执行的指令;
若在编译完成后,修改了某个源码文件,则make仅会针对被修改的文件进行编译,其他的object file不会被更改;
最后可以依照相依性来更新(update)执行文件。
make里面最需要注意就是那个规则文件,也就是Makefile这个文件的语法。
Makefile的基本语法与参数
基本的Makefile规则:
目标(target): 目标文件1 目标文件2...
<tab空格> gcc -o 欲新建的可执行文件 目标文件1 目标文件2...
#特别注意,命令行必须要以tab键作为开头才行
那个目标(target)就是我们想要建立的信息,而目标文件就是具有相关性的object files。要建立可执行文件的语法就是以 <tab>开头的那一行。
特别注意,命令行必须要以<tab键>作为开头才行。
Makefile基本规则:
#代表注释;
<tab>需要在命令行(如gcc编译命令)的只一个字符;
目标(target)与依赖文件(指目标文件)之间需以":"分割。
举个栗子:
vi Makefile
main: main.o haha.o sin.o cos.o
gcc -o main main.o haha.o sin.o cos.o -lm #不接-L/path表示使用系统默认
clean:
rm -f main main.o haha.o sin.o cos.o
如果我们想要建立的是,使用 make main;
如果想要删除,使用 make clean;
如果想先清除在编译的话,使用 make clean main。
makefile也可以像shell script那样,将重复的信息定义为变量,简化Makefile以方便使用。
与bash shell script的语法有点不太相同,Makefile变量的基本语法为:
1,变量与变量内容以 = 隔开,两边可以具有空格;
2,变量左边不可有<tab>;
3,变量与变量内容 = 两边不能具有 : ;
4,在习惯是,变量最好使用大写字母为主;
5,运用变量时,以 $(变量) 或 ${变量} 使用;
6,在该shell中定义的变量是可以被套用的,如CFLAGS;
7,在命令模式也可以定义变量;
由于gcc在进行编译行为时,会主动的去读取CFLAGS这个环境变量,所以可以直接通过shell定义这个环境变量。
CFLAGS="-Wall" make clean main
#这个动作在make进行编译时,会去取用CFLAGS的变量内容。也可以在Makefile文件里面定义。
环境变量的优先规则:
make指令后面加上的环境变量优先;
Makefile里面指定的环境变量第二;
shell原本具有的环境变量第三。
#注意,$@代表目前的目标(target)
gcc -o $@ ${OBJS} ${LIBS}
Tarball的管理与建议
了解了源码的相关信息后,再来了解如何使用具有源码的Tarball(压缩包)来建立一个属于自己的软件了!
从前面几个小节的说明中,我们知道其实Tarball的安装是可以跨平台的,因为C语言的程序在各个平台上面是可以互通的,只是需要的编译器可能不相同而已。如Linux有gcc而Windows上也有相应的C编译器。
如果源码跨平台编译没有成功呢?只需要修改小部分代码就可以进行跨平台的移植了。也就是说,我们在Linux下写的程序,理论上是可以在Windows上面编译的。这就是源码的好处。所以,扩平台性强大语言也体现了它的优势。
使用源码管理软件所需要的基础软件
从源码的说明我们晓得要生成一个二进制程序需要很多东西的呢!包括如下软件:
gcc或cc等C语言编译器(complier);
make及autoconfig等软件;
需要Kernel提供的Librarys以及相关的Include文件;
按照软件开发商提供的README与INSTALL文件说明步骤来进行,安装是容易的。
yum groupinstall Development Tools #安装gcc
yum groupinstall X Software Development #安装图形界面软件
yum groupinstall Legacy Software Development #安装较旧的软件
Tarball安装的基本步骤
Tarball方式解压出的软件是需要重新编译可执行的二进制文件的。而Tarball是以tar这个命令来打包与压缩文件。所以,需要先将Tarball解压,然后 到源码所在的目录下进行Makefile的建立,再以make来进行编译与安装的动作。
安装流程基础操作大多如下:
1,取得源文件:将Tarball文件在/usr/local/src目录下解压;
2,取得步骤流程:进入新建立的目录下面,去查阅INSTALL和README等相关文件的的内容;
3,依赖属性软件安装:根据INSTALL/README的内容查看并安装好一些依赖的软件;
4,建立Makefile文件:以自动检测程序(configure或config)检测操作系统,并建立Makefile这个文件;
5,编译:以make这个程序并使用该目录下的Makefile作为它的参数设置值,来进行make动作;
6,安装:以make这个程序,并以Makefile这个参数设置值,依据install这个目的(target)的指定来安装到正确的路径!
注意第二点,解压后的文件里面的README一般都会有详细的解释。
至于Makefile生成以后,里面会有相当多的目标(target),最常见的就是 install 与 clean。
make将源码进行编译。注意了,编译完成的可执行文件与相关的配置文件都还在此目录当中哦!因此,最后要进行 make install 来将编译完成的所有咚咚锵都给他安装到正确的路径里去,最后就可以使用该软件了!
Tarball软件大概安装方式:
1,./configure #这个步骤是建立Makefile文件啰;
2,make clean #这个步骤不一定有,它清除object file;
3,make #make依据Makefile的设置进行编译;
4,make install #通常这是最后的安装步骤了,make依据Makefile文件里的install目标,将编译完成的资料安装到指定目录中去。
上面步骤是一步一步来进行的,只执行某个步骤无法成功,那么后续步骤耶无法进行!因此必须要每一步都成功才行!
一般Tarball软件安装的建议事项(如何删除?升级?)
或许你已经发现了,为什么Tarball要在/usr/local/src里面解压呢?基本上,在默认的情况下,原本的Linux distribution发布安装的软件大多是在 /usr 里面的,而用户自行安装的软件则建议放在/usr/local里面。这是考虑到管理软件的便利性。
man会去搜寻/usr/local/man 里面的说明文件。因此,将软件安装在/usr/local下的话,那么自然安装完成之后,该软件的说明就可以被找到了。
建议将自己安装的软件放在/usr/local下,源码则建议放在/usr/local/src下。
来看看Linux distribution默认的软件安装路径会用到哪些?以Apache为例:
/etc/httpd; #配置文件
/usr/lib; #函数库
/usr/bin; #执行文件
/usr/share/man; #说明文件
如果你是以Tarball来安装Apache时,如果放在/usr/local里面,由于/usr/local原本就默认有这几个目录,所以你的资料会被放在:
/usr/local/etc ;
/usr/local/bin ;
/usr/local/lib ;
/usr/local/man ;
如果你的每个软件都选择在默认的路径下安装的话,那么所有的软件的文件都将放在这四个目录当中,因此,如果你都安装在这个目录下的话,那么未来在想要升级或卸载的时候,就会比较难以查找文件的来源!
而如果你在安装的时候选择的是单独的目录,例如我将Apache安装在/usr/local/apache下,那么你的文件目录就会变成:
/usr/local/apache/etc ;
/usr/local/apache/bin ;
/usr/local/apache/lib ;
/usr/local/apache/man ;
单一软件的文件都在同一个目录下,那么要卸载就简单多了。只要将该目录删除即可视为该软件以被卸载。如 rm -rf /usr/local/apache 就算卸载了这个软件。
这种方式虽然有利于软件的卸载,但我们在执行某些指令的时候,与该指令是否存在PATH这个环境参数所记录的路径有关。我们/usr/local/apache/bin肯定不在PATH里面。所以执行apache就得要利用绝对路径了,否则就得将这个/usr/local/apache/bin加入PATH里面去。
除此之外,Tarball在升级的时候也挺困难的,怎么说呢?还是以Apache来说。WWW服务器为了考虑互动性,所以通常会将PHP+MySQL+Apache一起安装,这样的话,那每个软件在安装的时候都有一定的顺序与程序!因为他们之间具有的相关性,所以安装时需要三者同时考虑到他们的函数库与相关的编译参数。
假设今天我只要升级PHP呢?有时候因为只涉及动态函数库的升级,那么我只要升级PHP即可!其他的部分或许影响不大。但如果PHP需要重新编译的模块比较多,那么可能会连带的,连apache这个程序也需要重新编译才行,真是有点头痛。没办法,Tarball有优点也有缺点!
由于Tarball在升级与安装上面具有这些特色,亦即Tarball在反安装上面具有比较高的难度,所以为了方便Tarball的管理,建议建议:
最好将Tarball的源码解压到/usr/local/src下;
安装时,最好安装到/usr/local这个默认路径下;
考虑未来的反安装步骤,最好可以将每个软件单独的安装在/usr/local下;
未安装到单独目录的软件的man page加入 man path搜索
老实说,时至今天真的不太需要tarball的安装了!
一个简单的例子,利用ntp来示范
如何利用Tarball来安装ntp(network time protocol)这个软件。
假设我的要求如下:
下载的ntp.xxx.tar.gz文件放在/root目录下;
源码要解压到/usr/loca/src下;
软件安装到/usr/local/ntp目录中;
解压下载的ntp的Tarball,并参考README/INSTALL文件:
cd /usr/loca/src
tar -zxvf /root/ntp.xxx.tar.gz #解压到此目录
cd ./ntp.xxx
cat README or cat INSTALL
检测configure支持的参数,并建立Makefile规则文件:
[ ntp.xxx ] ./configure --help | more #查询可用参数有哪些
#--prefix=PREFIX install architecture-independent files in PREFIX;
#--prefix=/path 表示软件要安装到哪个目录去,如果没有指定,则默认在/usr/local;
#--enable-all-clocks + include all suitable non- PARSE clocks:
#--enable-parse-clocks - include all suitable PARSE clocks:
#特别要留意关于gcc的检查,最后需要成功的建立Makefile文件才行
最后开始编译与安装:
make clean;make
make check
make install
完成之后,你可以看看/usr/local/ntp看看。
利用patch更新源码
如何更新以Tarball方式安装的软件呢?
事实上,当我们发现一些软件的漏洞,通常是某一段代码写的不好所导致的。因此,所谓的“更新源码”常常是更改部分文件的部分内容而已。既然如此,我们是否可以就那些被更改的文件来进行修改即可?
这有什么好处呢?首先,没有更改过的文件的目标文件(object file)根本就不需要重新编译,而且有改动多的文件又可以利用make来自动update(更新)。如此一来,我们原先的设置(Makefile文件里的规则)将不需要重新修改或检测。可以节省很多时间。如果将旧版的源码文件改写成新的版本,那么就能直接编译而不需要全部的新版本的Tarball重新下载一遍。
利用 diff 命令可以对比两个文件之间的差异性,我们也知道了新旧版本源码之间的差异,然后再利用 patch 命令来更新旧版文件。
很多软件开发商在更新了源码之后,几乎都会放出所谓的 patch file,也就是直接将源码update的一个方式。
假设我有old file 和 patch file:
main-0.1.tgz #main的0.1版本
main-0.1-to-0.2.patch #将main由0.1升级到0.2的patch file
将两者解压到/root下:
tar -zxvf main-0.1.tgz
cd main-0.1
make clean
./main #测试旧版功能
查看patch file内容:
上面有底线那部分,代表使用diff去比较时,两个文件所在路径,这个路径非常重要。
patch基本语法:
patch -p数字 < file.patch
#-p后面的数字代表 拿掉file.patch第一行里面的几个 "/" 线
特别留意那个『 -p数字』,那是与patch_file 里面列出的档名有关的资讯。假如在 patch_file 第一行写的是这样:
*** /home/guest/example/expatch.old
那么当我下达『 patch -p0 < patch_file 』时,则更新的文件是『/home/guest/example/expatch.old 』;
如果『 patch -p1 < patch_file』,则更新的文件为『home/guest/ example/expatch.old』;
如果『patch -p4 < patch_file』则更新『expatch.old』;
也就是说,-pxx那个xx代表『拿掉几个斜线(/)』的意思!
好了,根据刚刚上面的信息,我们可以发现比较的文件是在main-0.1/xxx与main-0.2/xxx 。所以说,如果你是在main-0.1底下,并且想要处理更新时,就得要拿掉一个目录(因为并没有main-0.2的目录存在,我们是在当前的目录进行更新的!),因此使用的是-p1才对喔!
更新源码,并且重新编译程序:
只要下载了patch file, 就能够对你的软件源码进行更新。只不过更新了源码并非软件就更新。你还要将该软件进行编译安装后才行。因为patch的功能只是更新源码文件。
patch -R < ../main-0.1-to-0.2.patch #还原
函数库管理
在Linux系统中,函数库是很重要的一个项目。因为很多软件之间都会互相调用彼此提供的函数库来进行特殊功能的运行,如验证身份的PAM模块,网络连接加密的SSL函数库。
动态函数库与静态函数库
依据函数库的使用类型而分为静态函数库(Static)与动态函数库(Dynamic)。
静态函数库的特点:
扩展名(.a):这类函数的扩展名为 libxxx.a;
编译行为:这些函数库在编译的时候会直接整合到执行程序中,所以利用静态函数库编译成的文件会比较大;
独立执行的状态:这类函数库最大的优点,就是编译成功的可执行文件可以独立执行,而不需要再向外部要求读取函数库的内容;
升级难易度:虽然执行文件可以独立执行,但因为函数库是直接整合到执行文件中,因此若函数库升级时,整个执行文件必须重新编译才能将新版的函数库整合到程序中。也就是说,只要函数库升级了,所有将函数库纳入的程序都需要重新编译。
动态函数库的特点:
扩展名(.so):扩展名通常为libxxx.so的类型;
编译行为:动态函数库在编译的时候,在程序里面只有一个 “指向(pointer)” 的位置而已。也就是说,动态函数库的内容并没有被整合到执行文件中,而是当执行文件要使用到函数库的机制时,程序才会去读取函数库来使用。由于执行文件中仅具有指向动态函数库所在的指向而已,并不包含函数库的内容,所以他的文件会比较小一点。
独立执行的状态: 这类函数库编译出来的程序不能被独立执行,因为当我们使用到函数库机制时,程序才会去读取函数库,所以函数库文 必须要存在才行。而且, 函数库所在的目录和文件名也不能改变。
升级难易度:虽然此类执行文件无法独立运行,然而由于是具有指向的功能,所以,当函数库升级后,执行文件根本不需要进行重新编译的行为,因为执行文件会直接指向新的函数库文件。
目前Linux distribution比较倾向于使用动态函数库,因为如同上面提到的最重要的一点,就是函数库的升级方便!
由于Linux系统里面的软件依赖性太复杂了,如果使用太多的静态函数库,那么升级某一个函数库时,就会对整个系统造成很大的影响!因为其他依赖的执行文件也要重新编译!这个时候动态函数库就有用多了,因为只要动态函数库升级就好,其他无需变动。
绝大多数的函数库都放在 /lib64,/lib目录下!
此外,Linux系统里面很多的函数库是由Kernel提供的。那Kernel的函数库放在哪里呢?就放在/lib/modules里面。
注意, 不同版本的内核提供的函数库差异性很大,很容易由于函数库的不同而导致很多原本可执行的软件无法顺利运行!
idconfig与/etc/ls.so.conf
如果我们将常用的动态函数库提前加载到高速缓存(Cache)中,如此一来,当软件要取用动态函数库时,就不需要从头由硬盘里面读出来啰。这样就大大增加了动态函数库的读取速度!没错,这个时候就需要Idconfig与/etc/ld.so.conf的帮助了。
如何将动态函数库加载到高速缓存中?
首先必须在/etc/ld.so.conf里面写下“想要加载进内存当中的动态函数库所在的目录”,注意是目录不是文件;
接下来则利用ldconfig这个执行文件将/etc/ld.so.conf的信息读入高速缓存中;
同时也将信息记录一份在/etc/ld.so.cache这个文件中!
事实上,ldconfig还可以用来判断动态函数库的链接资讯。如你想将目前你系统下的mariadb函数库加入到高速缓存中时,你可以:
程序的动态函数库解析:ldd
如何判断某个可执行的binary文件含有什么动态函数库呢?很简单,利用ldd就可以晓得!
例如我想知道/usr/bin/passwd这个程序含有的动态函数库有哪些,可以这样做:
如果你常常升级安装RPM的软件时,应该常常会发现那个“依赖属性”的问题。没错,我们可以先以ldd来观察“相依赖函数库”之间的相关性。如上面的libc.so.6其实还跟ld-linux-x86-64.so.2有关。
检验软件的完整性
有没有可能我们下载的文件本身就有问题,因为cracker无处不在。这个时候我们就要通过每个文件读他的指纹验证数据了!我们可以利用MD5/sha1或更严密的sha256等指纹验证机制来判断该文件有没有被更动过。
md5sum / sha1sum / sha256sum
目前有多种机制可以计算文件的指纹码,我们选择较为广泛的MD5,SHA1或SHA256 加密机制来处理。
此处用前面谈到的ntp软件来检查看看。首先看一下ntp软件的版本,其官网上有提供md5sum的数据。
如何确认我们下载的文件是正确没问题的呢?这样处理一下:
一般而言,每个系统里面的文件内容大概都不相同,如你的系统中的/etc/passwd这个登录信息与我的不一样,所以又md5sum这个文件志文分析程序所自行计算出来的指纹表当然就不相同啰!
那么如何应用这个东西呢?基本上,你必须要在Linux系统上为你的这些重要的文件进行指纹数据库的建立(好像在做户口调查)。
将下面这些重要文件建立指纹数据库:
/etc/passwd;
/etc/shadow;
/etc/group;
/usr/bin/passwd;
/sbin/rpcbind;
/bin/login;
/bin/ls;
/bin/ps;
/bin/top;
这几个文件最容易被修改了!因为很多木马程序执行的时候,还是会有所为的“执行程序PID”,为了怕被root追查到,所以他们都会修改这些检查进程的文件,如果你可以替这些文件建立指纹数据库(就是使用md5sum)检查一次,将该文件指纹记录下来,然后常常以shell script的方式由程序自行来检查指纹是都相同),那么对于文件系统来说会比较安全啦!
重点回顾:
源码大多是纯文本,需要通过编译器编译后,才能转换成Linux系统能够识别的可执行的二进制文件;
开放源码可以加速软件的更新速度,让软件效能更快、漏洞修补更及时;
在Linux系统中,最标准的C语言编译器为gcc;
在编译的过程中,可以由其他软件提供的函数库来使用该软件的相关机制与功能;
为了简化编译过程中复杂的指令输入,可以由make与Makefile规则定义,来简化程序的更新、编译与链接等动作;
Tarball为使用tar与gzip/bzip2/xz压缩功能所打包与压缩的,具有源码的文件;
一般而言,要使用Tarball管理Linux系统上的软件,最好需要gcc,make,autoconfig,Kernel source,Kernel header等前驱软件才行。所以在安装Linux之初,最好就能够选择Software development 以及Kernel development之类的群组;
函数库有动态与静态两种。动态函数库在升级上具有较佳的优势,动态函数库扩展名为 .so,静态则是则是直接被整合到执行程序中,扩展名为 .a;
patch的主要功能在更新源码,所以更新源码之后,还需要进行重新编译安装等动作;
可利用 ldconfig 与 /etc/ld.so.conf, /etc/ld.so.conf.d/*.conf 来制作动态函数库的链接与存取;
通过 md5sum,sha1sum,sha256sum 的编码,可以判断下载的文件是否为原厂商放出且未被篡改的正确文件。同理,可用于校验本机文件。