热门关键字:  ubuntu  分区  函数  Fedora  linux系统进程

学会做嵌入式Linux操作系统

来源: 作者: 时间:2007-05-31 Tag: 点击:

1、这些启动标志变量,我定义在了/etc/sysconfig/bootserver当中,其内容如下:

#start server on system boot

#1:yes 0:no

enable_httpd=1

enable_adsl=1

enable_udhcpd=1

 

2、每种服务对应的脚本,我都放在了/etc/scripts下面。这些脚本,取决于你打算使用哪些服务程序了。脚本的来源,可以自己编写,有可能其源码中自带有,也可以到网上查找……我就不再一一赘述了,

 

OK,基本上,脚本的修改就完成了,下一步,将是建立RamDisk。

 

——————————————————————————————————————————————

附,读取网卡配置文件,启动网卡的C源码:

/************************************************************************

** author:kendo

** date:2005/10/26

 

***********************************************************************/

 

#include

#include

#include

#include

#include

#include

 

#define NETCFGDIR "/etc/sysconfig/network-scripts/"

 

struct _ifcfg{

char device[8];

char bootproto[8];

char br[16];

char netmask[16];

char ip[16];

char network[16];

int onboot;

};

 

void ParseKey(struct _ifcfg *ifcfg,char *key,char *value)

{

if(!strcmp(key,"DEVICE"))

{

strcpy(ifcfg->device,value);

}

else if(!strcmp(key,"BOOTPROTO"))

{

strcpy(ifcfg->bootproto,value);

}

else if(!strcmp(key,"BROADCAST"))

{

strcpy(ifcfg->br,value);

}

else if(!strcmp(key,"IPADDR"))

{

strcpy(ifcfg->ip,value);

}

else if(!strcmp(key,"NETMASK"))

{

strcpy(ifcfg->netmask,value);

}

else if(!strcmp(key,"NETWORK"))

{

strcpy(ifcfg->network,value);

}

else if(!strcmp(key,"ONBOOT"))

{

ifcfg->onboot=(strcmp(value,"yes") ? 0 : 1);

}

}

 

int main(int argc,char **argv)

{

FILE *fp;

DIR *dir;

int i;

char filename[50],buf[80];

char *index,*key,*value,*p;

struct _ifcfg *ifcfg;

struct dirent *ptr;

 

ifcfg=(struct _ifcfg *)malloc(sizeof(struct _ifcfg));

memset(ifcfg,0,sizeof(struct _ifcfg));

 

dir=opendir(NETCFGDIR); /*打开脚本目录*/

while((ptr=readdir(dir))!=NULL) /*读取所有文件*/

{

if(strncmp(ptr->d_name,"ifcfg-eth",9)) /*这里,只启动了以太网卡^o^*/

{

continue;

}

memset(filename,0,sizeof(filename));

sprintf(filename,"%s%s",NETCFGDIR,ptr->d_name);

if((fp=fopen(filename,"r"))==NULL) /*打开配置文件*/

{

continue;

}

 

while(!feof(fp))

{

memset(buf,0,sizeof(buf));

if(fgets(buf,80,fp)!=NULL) /*逐行读取分析*/

{

p=strchr(buf,'n');

if(p)

{

*p='';

}

index=buf;

key=strtok(index,"="); /*读取配置变量*/

value=strtok(NULL,"="); /*读取变量的值*/

ParseKey(ifcfg,key,value); /*分析之,存入结构ifcfg中*/

}

}

/*构建相应的命令*/

memset(buf,0,80);

strcpy(buf,"/sbin/ifconfig");

 

if(ifcfg->onboot)

{

sprintf(buf,"%s %s %s netmask %s broadcast %s",

buf,

ifcfg->device,

ifcfg->ip,

ifcfg->netmask,

ifcfg->br);

/*直接调用system来实现,当然也可以自己通过ioctl来设置,相应源码,我以前在c/c++版发过*/

system(buf);

}

}

free(ife);

return 0;

}

 

platinum 2005-11-1 02:52

 

[code]

memset(buf,0,80);

strcpy(buf,"/sbin/ifconfig");

 

if(ifcfg->onboot)

{

sprintf(buf,"%s %s %s netmask %s broadcast %s",

buf,

ifcfg->device,

ifcfg->ip,

ifcfg->netmask,

ifcfg->br);

/*直接调用system来实现,当然也可以自己通过ioctl来设置,相应源码,我以前在c/c++版发过*/

system(buf);

[/code]

两个问题

1、从这段代码看,实际调用了 /sbin/ifconfig 来完成网卡的设置,那么,这个程序是否必须用 root 来执行?

2、为何不用 system("command") 呢?

 

独孤九贱 2005-11-1 03:03

 

回复 19楼 platinum 的帖子

 

1、 ifconfig本身运行,应该不需要root吧?而至于在shell中的运行权限,要看看相应的权限位了,事实上它已经能够在我的系统中很好的运行了,测试过很多次的。不过现在我的系统,其实没有用这种方法的,我是自己封装了一个网卡管理的库,也就是重写了ifconfig,不过要把这些代码发上来,太麻烦了,所以,就用了解system简单了一点。

 

2、我不是很理解“为何不用 system("command") 呢?”这句话的含义,我用的是system(buf);你说的是不是为什么要去构建一个buf,而不是直接用system("/sbin/ifconfig ethXX……")?清楚一点……^o^

 

 

独孤九贱 2005-11-16 01:44

 

继续工作,交叉编译SNMP

 

一般系统都会有SNMP的支持,下载了net-snmp-5.1.3.1,先看看INSTALL和FAQ文档(因为以前从来没有碰过这个东东,见笑了……),按照说明,在原生主机上安装了一回,安装完成后,发现在指定安装目录下主要包括了几块文件:

bin:SNMP的一些功能脚本和程序;

sbin:主要的代理程序和trap程序:snmpd和snmptrap

include/lib:自身兼容及第三方开发所需的头文件及库文件;

share:主要是MIB文件;

 

然后回到安装目录下,运行./configuare --help,仔细查看了其安装编译选项,因为我定位的小型的系统,只需具备基本的SNMP功能即可,所以:

那些bin目录下的功能程序也不需要,对应--disable-applications

bin下的脚本也是不需要的,对应:--disable-scripts

用户手册也不需要:--disable-manuals

关闭ipv6支持:--disable-ipv6

还有一个--enable-mini-agent选项,说明是编译出一个最小化的snmpd,比较有趣,试试先。

对于交叉编译,还需要用--host指明目标平台。

 

OK,看完了帮助说明,开始编译了:

1、配置,根据以上确定的选项:

[root@skynet root]# CC=i386-linux-gcc ./configure --host=$TARGET --enable-mini-agent --disable-ipv6 --with-endianness=little --disable-applications --disable-manuals --disable-scripts --disable-ucd-snmp-compatibility

 

CC指明了编译器;--host指明了我的目标平台,这个环境变量在我前面定义的devedaq脚本中。

还算顺利,继续编译它:

[root@skynet net-snmp-5.1.3.1]# make LDFLAGS="-static"

 

呵呵,因为没有装lib库,所以我用了-static选项,指明是静态编译;

 

3、安装

安装就需要指明安装路径了,路径可以在.config的时候指定,因为那个时候,那串东东太长了,我在install时指定也不迟:

#make prefix=${TARGET_PREFIX} exec_prefix=${TARGET_PREFIX} install

 

4、检查一下:

[root@skynet net-snmp-5.1.3.1]# ls -l ${TARGET_PREFIX}/sbin

total 2120

-rwxr-xr-x 1 root root 2164301 Nov 16 09:22 snmpd

 

snmpd就是我们要的代理主程序了,大约静态编译有2M。

 

[root@skynet net-snmp-5.1.3.1]# ls -l ${TARGET_PREFIX}/bin

total 4380

-rwxr-xr-x 2 root root 391980 Oct 14 2004 ar

-rwxr-xr-x 2 root root 581228 Oct 14 2004 as

……

 

呵呵,那堆程序和脚本没有安装,如snmpwalk……

 

ls ${TARGET_PREFIX}/lib

ls -l ${TARGET_PREFIX}/include

 

 

看看我们需要的mib文件:

[root@skynet net-snmp-5.1.3.1]# ls ${TARGET_PREFIX}/share/snmp

mib2c.access_functions.conf mib2c.column_defines.conf mib2c.int_watch.conf mib2c.old-api.conf

mib2c.array-user.conf mib2c.column_enums.conf mib2c.iterate_access.conf mib2c.scalar.conf

mib2c.check_values.conf mib2c.conf mib2c.iterate.conf mibs

mib2c.check_values_local.conf mib2c.create-dataset.conf mib2c.notify.conf snmpconf-data

 

5、移植

基本完成了,因为snmpd太大了点,对它进行strip处理:

先备个份:

[root@skynet net-snmp-5.1.3.1]# cp ${TARGET_PREFIX}/sbin/snmpd ${TARGET_PREFIX}/sbin/snmpd.bak

[root@skynet net-snmp-5.1.3.1]# i386-linux-strip ${TARGET_PREFIX}/sbin/snmpd

[root@skynet net-snmp-5.1.3.1]# ls -l ${TARGET_PREFIX}/sbin/snmpd

-rwxr-xr-x 1 root root 503300 Nov 16 09:30 /home/skynet/tools/i386-linux/sbin/snmpd

 

经过处理后,还有近500KB了。

 

因为只有SNMP agent功能,即snmpd程序,其它的都可以忽略。用了静态编译,lib下边那些libnetsnmp文件都可以不需要了,程序运行

需要MIB库,也就是share下的内容,把这两个东东拷到rootfs相应的目录中去:

[root@skynet net-snmp-5.1.3.1]# cp ${TARGET_PREFIX}/sbin/snmpd ${PRJROOT}/rootfs/usr/sbin

[root@skynet net-snmp-5.1.3.1]# mkdir -p ${PRJROOT}/rootfs/usr/local/share

[root@skynet net-snmp-5.1.3.1]# cp -r ${TARGET_PREFIX}/share/snmp ${PRJROOT}/rootfs/usr/local/share

[root@skynet net-snmp-5.1.3.1]# cp EXAMPLE.conf ${PRJROOT}/rootfs/usr/local/share/snmp/snmpd.conf

 

最后一步是把安装目录下的配置文件范例拷到snmpd启动时默认的搜索目录中去。

 

6、测试

打开snmpd.conf看看:

[root@skynet net-snmp-5.1.3.1]# vi ${PRJROOT}/rootfs/usr/local/share/snmp/snmpd.conf

有如下语句:

# sec.name source community

com2sec local localhost COMMUNITY

com2sec mynetwork NETWORK/24 COMMUNITY

定义了两个用户,本地及网络的,以及它们的通读密钥,按自己的需要修改一下,如:

# sec.name source community

com2sec local 127.0.0.1 public

com2sec mynetwork 0.0.0.0 public

 

后面是定义用户的用户组等一大堆东东,事实上不用修改它们了。运行它:

[root@skynet net-snmp-5.1.3.1]# chroot ${PRJROOT}/rootfs /bin/sh

 

 

BusyBox v1.00 (2004.10.13-06:32+0000) Built-in shell (ash)

Enter 'help' for a list of built-in commands.

 

/ # snmpd

/ # exit

在我们自己的根文件系统环境下运行它,然后退出来。用ps查看:

#ps -aux

……

root 32270 0.0 0.3 1212 936 ? S 09:38 0:00 snmpd

 

[root@skynet net-snmp-5.1.3.1]# netstat -anu

……

udp 0 0 0.0.0.0:161 0.0.0.0:*

 

呵呵,已经成功启动了。用一个SNMP管理软件试试,可以成功地获取到信息。OK!

 

总结一下:

1、主程序+MIB库大了点,共计约2M,不过我确实没有办法再小了,而且一味求小,也不是我的目的。

2、功能稍微简单了些,只有agent,如果需要,可以类似地把其它程序加上去就可以了。

3、第一次玩net-snmp,还是有点生疏,比如我静态编译二进制程序,并不需要include/lib下的文件,但是如何关闭它们呢?我试过--disable-ucd-snmp-compatibility,不过好像不是这个选项……下次改进了……

 

独孤九贱 2005-11-16 05:38

 

继续工作,使用ramdisk

 

前提:内核编译时得选相应的支持选项,前文已有叙述。

 

1、rootfs中的/boot文件夹删除;

2、建立ramdisk:

使用dd命令建立一个空的文件系统映像:

# dd if=/dev/zero of=images/initrd.img bs=1k count=8192

 

大小8192K,用/dev/zero对其初始化;

 

利用刚才的空的文件系统映像,建立文件系统并安装它,使用了mke2fs命令:

# /sbin/mke2fs -F -v -m0 images/initrd.img

 

新建一个临时文件夹做mount之用:

# mkdir tmp/initrd

把建好的文件系统mount上来:

#mount -o loop images/initrd.img tmp/initrd

把根文件系统拷贝过来:

#cp -av rootfs/* tmp/initrd

# umount tmp/initrd

 

压缩:

# gzip -9 images/initrd.bin

 

这样,就得到了images/initrd.bin

 

把目标盘mount上来:

#mount -t ext2 /dev/hda1 /mnt/cf

新建一个/boot

#mkdir /mnt/cf/boot

 

把刚才建立的ramdisk镜像拷过来。然后把内核文件bzImage-2.4.27-rmk5也拷进去。

这样,boot文件夹里边有两个文件

initrd.bin

bzImage-2.4.27-rmk5

 

这个时候还不能安装lilo,因为lilo的配置文件中有/dev/hda……这样的东东,而目标盘上还没有……所以,临时建一个:

#mkdir /mnt/cf/dev

#cp -rf ${PRJROOT}/rootfs/dev/hda* /mnt/cf/dev

 

修改${PRJROOT}/rootfs/etc/target.lilo.conf,我的配置文件如下:

boot=/dev/hda

disk=/dev/hda

bios=0x80

 

image=/boot/bzImage-2.4.27-rmk5

initrd=/boot/initrd.bin

root=/dev/hda1

append="root=/dev/hda1"

# label=MyLinux

read-only

 

相比以前的,只是加了一句:initrd=/boot/initrd.bin,另外把label去掉了,因为否则lilo会报怨说语法错误。

 

好了,可以安装lilo了。以前我们的语句是:

lilo -r /mnt/cf -C etc/target.lilo.conf

现在我们的目标盘上没有etc这个目录了,更不用说target.lilo.conf,可以借助于工程目录中的了原文件,当然,我在目标硬盘上新建了/dev,然后把target.lilo.conf拷过去,还是用这句命令安装lilo。

 

这样,整个系统就完成了。


最新评论共有 4 位网友发表了评论
发表评论
评论内容:不能超过250字,需审核,请自觉遵守互联网相关政策法规。
用户名: 密码:
匿名?
注册