用busybox1.13.1构建基于MIPS的嵌入式根文件系统
一、主机环境
笔者所用环境为mipsel-unknown-linux-gnu-gcc 3.4.3 GLIBC版本为2.2.5,建议使用高版本进行测试,不过笔者没有测试过,是否会存在问题。
gcc version 3.4.1 (fedora core 5)
所需源文件: busybox-1.13.1.tar.bz2; 网上可轻易下载
二、用Busybox创建nfs文件系统
1、解压busybox-1.13.1.tar.bz2
[root@vm-dev rootfs]# ls
busybox-1.13.1.tar.bz2
[root@vm-dev rootfs]# tar -vxjf busybox-1.13.1.tar.bz2
[root@vm-dev rootfs]# cd busybox-1.13.1
[root@vm-dev busybox-1.13.1]# pwd
/work/busybox-1.13.1
[root@vm-dev busybox-1.13.1]# vi Makefile
[root@vm-dev busybox-1.13.1]#
修改Makefile中的ARCH和CROSS_COMPILE与本机的路径一致,注意,如果在/root/.bash_profile中指定了路径,则不需要再给出路径。
CROSS_COMPILE ?= mipsel-unknown-linux-gnu-
...
ARCH ?= mips
2、编译busybox。
先make menuconfig,修改以下:
[root@vm-dev busybox-1.13.1]# make menuconfig
Busybox Settings --->
Build Options --->
[*] Build BusyBox as a static binary (no shared libs)
//直接编译成静态库,省事点
(mipsel-unknown-linux-gnu-) Cross Compiler prefix
//这里和Makefile里保持一致,应该写一处就行了
Installation Options --->
[ ] Don't use /usr
//使用usr目录
Busybox Library Tuning --->
[*] Fancy shell prompts
//一定要选上,否则很多转意字符无法识别
Shells --->
Choose your default shell (ash) --->
//这里选择shell为ash,应该是默认选中的
--- ash
//把ash这档的选项全部选上
Miscellaneous Utilities --->
[ ] inotifyd
//不选
保存退出,直接make,make install。
可以看到如下目录
[root@vm-dev busybox-1.13.1]# ls _install/
bin linuxrc sbin usr
[root@vm-dev busybox-1.13.1]#
3、用shell脚本创建根文件系统的目录结构
用shell脚本创建根文件系统的目录结构,并在想要建立根文件系统的地方运行此脚本。我是用root用户登陆的,直接创建了设备节点。
[root@vm-dev root_stand]# cat build_fs.sh
#!/bin/sh
echo "makeing rootdir"
mkdir rootfs
cd rootfs
echo "makeing dir: bin dev etc lib proc sbin sys usr"
mkdir bin dev etc lib proc sbin sys usr #8 dirs
mkdir usr/bin usr/lib usr/sbin lib/modules
#Don't use mknod, unless you run this Script as
mknod -m 600 dev/console c 5 1
mknod -m 666 dev/null c 1 3
echo "making dir: mnt tmp var"
mkdir mnt tmp var
chmod 1777 tmp
mkdir mnt/etc mnt/jiffs2 mnt/yaffs mnt/data mnt/temp
mkdir var/lib var/lock var/log var/run var/tmp
chmod 1777 var/tmp
echo "making dir: home root boot"
mkdir home root boot
echo "done"
[root@vm-dev root_stand]#
执行这个sh:
[root@vm-dev root_stand]# sh build_fs.sh
makeing rootdir
makeing dir: bin dev etc lib proc sbin sys usr
making dir: mnt tmp var
making dir: home root boot
done
创建出一个主文件夹rootfs,里面有一批文件:
[root@vm-dev root_stand]# cd rootfs/
[root@vm-dev rootfs]# ls
bin boot dev etc home lib mnt proc root sbin sys tmp usr var
[root@vm-dev rootfs]#
4、把busybox源码目录下的etc的内容拷贝到这里的etc下
[root@vm-dev rootfs]# cd etc/
[root@vm-dev etc]# ls
[root@vm-dev etc]# cp -a /work/busybox-1.13.1/examples/bootfloppy/etc/* ./
[root@vm-dev etc]# ls
fstab init.d inittab profile
[root@vm-dev etc]#
5、修改拷贝过来的profile文件
[root@vm-dev etc]# vi profile
# /etc/profile: system-wide .profile file for the Bourne shells
echo "Processing /etc/profile"
# no-op
# Set search library path
echo " Set search library path"
export LD_LIBRARY_PATH=/lib:/usr/lib
# Set user path
echo " Set user path"
PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PATH
# Set PS1
echo " Set PS1"
HOSTNAME=`/bin/hostname`
# 此处让shell提示符显示host名称的。是`,不是’,要注意
# 会在进入根系统后显示Jacky
export PS1="\\e[32m[$USER@$HOSTNAME \\w\\a]\\$\\e[00;37m "
# 此处\\e[32m是让后面的“[$USER@$HOSTNAME \\w\\a]”显示为绿色
# \\e[00是关闭效果
# \\e[05是闪烁
# 37m是让后面的显示为白色
# 多个命令可以;号隔开
echo "All done!"
echo
6、修改初始化文件inittab和fstab
Inittab
[root@vm-dev etc]# vi inittab
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::restart:/sbin/init
tty2::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount -a -r
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff –a
Fstab
[root@vm-dev etc]# vim fstab
proc /proc proc defaults 0 0
none /tmp ramfs defaults 0 0
mdev /dev ramfs defaults 0 0
sysfs /sys sysfs defaults 0 0
7、修改初始化的脚本文件init.d/rcS
[root@vm-dev etc]# vi init.d/rcS
#! /bin/sh
echo "Processing etc/init.d/rc.S"
#hostname ${HOSTNAME}
hostname up-tech
echo " Mount all"
/bin/mount -a
echo " Start mdev...."
/bin/echo /sbin/mdev > proc/sys/kernel/hotplug
mdev -s
echo "****************************************************"
echo " rootfs by NFS, s3c2410"
echo " Created by lyj_uptech @ 2008.11.28"
echo " Good Luck"
echo " www.up-tech.com"
echo "****************************************************"
echo
8、创建一个空的mdev.conf文件,在挂载根文件系统时用到
[root@vm-dev etc]# touch mdev.conf
9、从本机拷贝passwd、shadow、group文件。
[root@vm-dev etc]# cp /etc/passwd .
[root@vm-dev etc]# cp /etc/shadow .
[root@vm-dev etc]# cp /etc/group .
修改passwd文件,把第一行和最后一行的bash修改成ash。
10、把busybox默认安装目录中的文件全部复制到rootfs中
会发现多了linuxrc -> bin/busybox文件,这是挂载文件系统需要执行的。
[root@vm-dev etc]# cd ..
[root@vm-dev etc]# cp -Rfv /work/busybox-1.13.1/_install/* ./
OK,以上用busybox创建了一个基本的文件系统。
PS:
如果编译busybox时选择动态库方式编译,则需要查看生成的busybox使用哪些动态库,然后把它们拷贝到rootfs/lib目录下。
[root@vm-dev lib]# arm-linux-readelf -d ../bin/busybox
参考文献:http://blog.chinaunix.net/u2/65122/showart.php?id=1671023
2009年3月30日星期一
用busybox1.13.1构建基于MIPS的嵌入式根文件系统
2009年3月26日星期四
双向链表
双向链表
维基百科,自由的百科全书
跳转到: 导航, 搜索
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
/* 线性表的双向链表存储结构 */
typedef struct DuLNode
{
ElemType data;
struct DuLNode *prior,*next;
}DuLNode,*DuLinkList;
/*带头结点的双向循环链表的基本操作(14个) */
void InitList(DuLinkList *L)
{ /* 产生空的双向循环链表L */
*L=(DuLinkList)malloc(sizeof(DuLNode));
if(*L)
(*L)->next=(*L)->prior=*L;
else
exit(OVERFLOW);
}
void DestroyList(DuLinkList *L)
{ /* 操作结果:销毁双向循环链表L */
DuLinkList q,p=(*L)->next; /* p指向第一个结点 */
while(p!=*L) /* p没到表头 */
{
q=p->next;
free(p);
p=q;
}
free(*L);
*L=NULL;
}
void ClearList(DuLinkList L) /* 不改变L */
{ /* 初始条件:L已存在。操作结果:将L重置为空表 */
DuLinkList q,p=L->next; /* p指向第一个结点 */
while(p!=L) /* p没到表头 */
{
q=p->next;
free(p);
p=q;
}
L->next=L->prior=L; /* 头结点的两个指针域均指向自身 */
}
Status ListEmpty(DuLinkList L)
{ /* 初始条件:线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */
if(L->next==L&&L->prior==L)
return TRUE;
else
return FALSE;
}
int ListLength(DuLinkList L)
{ /* 初始条件:L已存在。操作结果:返回L中数据元素个数 */
int i=0;
DuLinkList p=L->next; /* p指向第一个结点 */
while(p!=L) /* p没到表头 */
{
i++;
p=p->next;
}
return i;
}
Status GetElem(DuLinkList L,int i,ElemType *e)
{ /* 当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR */
int j=1; /* j为计数器 */
DuLinkList p=L->next; /* p指向第一个结点 */
while(p!=L&&jnext;
j++;
}
if(p==L||j>i) /* 第i个元素不存在 */
return ERROR;
*e=p->data; /* 取第i个元素 */
return OK;
}
int LocateElem(DuLinkList L,ElemType e,Status(*compare)(ElemType,ElemType))
{ /* 初始条件:L已存在,compare()是数据元素判定函数 */
/* 操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
int i=0;
DuLinkList p=L->next; /* p指向第1个元素 */
while(p!=L)
{
i++;
if(compare(p->data,e)) /* 找到这样的数据元素 */
return i;
p=p->next;
}
return 0;
}
Status PriorElem(DuLinkList L,ElemType cur_e,ElemType *pre_e)
{ /* 操作结果:若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱, */
/* 否则操作失败,pre_e无定义 */
DuLinkList p=L->next->next; /* p指向第2个元素 */
while(p!=L) /* p没到表头 */
{
if(p->data==cur_e)
{
*pre_e=p->prior->data;
return TRUE;
}
p=p->next;
}
return FALSE;
}
Status NextElem(DuLinkList L,ElemType cur_e,ElemType *next_e)
{ /* 操作结果:若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后继, */
/* 否则操作失败,next_e无定义 */
DuLinkList p=L->next->next; /* p指向第2个元素 */
while(p!=L) /* p没到表头 */
{
if(p->prior->data==cur_e)
{
*next_e=p->data;
return TRUE;
}
p=p->next;
}
return FALSE;
}
DuLinkList GetElemP(DuLinkList L,int i) /* 另加 */
{ /* 在双向链表L中返回第i个元素的地址。i为0,返回头结点的地址。若第i个元素不存在,*/
/* 返回NULL */
int j;
DuLinkList p=L; /* p指向头结点 */
if(i<0||i>ListLength(L)) /* i值不合法 */
return NULL;
for(j=1;j<=i;j++)
p=p->next;
return p;
}
Status ListInsert(DuLinkList L,int i,ElemType e)
{ /* 在带头结点的双链循环线性表L中第i个位置之前插入元素e,i的合法值为1≤i≤表长+1 */
/* 改进算法2.18,否则无法在第表长+1个结点之前插入元素 */
DuLinkList p,s;
if(i<1||i>ListLength(L)+1) /* i值不合法 */
return ERROR;
p=GetElemP(L,i-1); /* 在L中确定第i个元素前驱的位置指针p */
if(!p) /* p=NULL,即第i个元素的前驱不存在(设头结点为第1个元素的前驱) */
return ERROR;
s=(DuLinkList)malloc(sizeof(DuLNode));
if(!s)
return OVERFLOW;
s->data=e;
s->prior=p; /* 在第i-1个元素之后插入 */
s->next=p->next;
p->next->prior=s;
p->next=s;
return OK;
}
Status ListDelete(DuLinkList L,int i,ElemType *e)
{ /* 删除带头结点的双链循环线性表L的第i个元素,i的合法值为1≤i≤表长 */
DuLinkList p;
if(i<1) /* i值不合法 */
return ERROR;
p=GetElemP(L,i); /* 在L中确定第i个元素的位置指针p */
if(!p) /* p=NULL,即第i个元素不存在 */
return ERROR;
*e=p->data;
p->prior->next=p->next;
p->next->prior=p->prior;
free(p);
return OK;
}
void ListTraverse(DuLinkList L,void(*visit)(ElemType))
{ /* 由双链循环线性表L的头结点出发,正序对每个数据元素调用函数visit() */
DuLinkList p=L->next; /* p指向头结点 */
while(p!=L)
{
visit(p->data);
p=p->next;
}
printf("\n");
}
void ListTraverseBack(DuLinkList L,void(*visit)(ElemType))
{ /* 由双链循环线性表L的头结点出发,逆序对每个数据元素调用函数visit()。另加 */
DuLinkList p=L->prior; /* p指向尾结点 */
while(p!=L)
{
visit(p->data);
p=p->prior;
}
printf("\n");
}
链表的C语言实现之循环链表及双向链表
链表的C语言实现之循环链表及双向链表
2005-06-15 13:46作者:leton2008出处:BLOG责任编辑:方舟
一、循环链表
循环链表是与单链表一样,是一种链式的存储结构,所不同的是,循环链表的最后一个结点的指针是指向该循环链表的第一个结点或者表头结点,从而构成一个环形的链。
循环链表的运算与单链表的运算基本一致。所不同的有以下几点:
1、在建立一个循环链表时,必须使其最后一个结点的指针指向表头结点,而不是象单链表那样置为NULL。此种情况还使用于在最后一个结点后插入一个新的结点。
2、在判断是否到表尾时,是判断该结点链域的值是否是表头结点,当链域值等于表头指针时,说明已到表尾。而非象单链表那样判断链域值是否为NULL。
二、双向链表
双向链表其实是单链表的改进。
当我们对单链表进行操作时,有时你要对某个结点的直接前驱进行操作时,又必须从表头开始查找。这是由单链表结点的结构所限制的。因为单链表每个结点只有一个存储直接后继结点地址的链域,那么能不能定义一个既有存储直接后继结点地址的链域,又有存储直接前驱结点地址的链域的这样一个双链域结点结构呢?这就是双向链表。
在双向链表中,结点除含有数据域外,还有两个链域,一个存储直接后继结点地址,一般称之为右链域;一个存储直接前驱结点地址,一般称之为左链域。在c语言中双向链表结点类型可以定义为:
typedef struct node
{
int data; /*数据域*/
struct node *llink,*rlink; /*链域,*llink是左链域指针,*rlink是右链域指针*/
}JD;
当然,也可以把一个双向链表构建成一个双向循环链表。
双向链表与单向链表一样,也有三种基本运算:查找、插入和删除。
双向链表的基本运算:
1、查找
假若我们要在一个带表头的双向循环链表中查找数据域为一特定值的某个结点时,我们同样从表头结点往后依次比较各结点数据域的值,若正是该特定值,则返回指向结点的指针,否则继续往后查,直到表尾。
下例就是应用双向循环链表查找算法的一个程序。
#include <stdio.h>
#include <malloc.h>
#define N 10
typedef struct node
{
char name[20];
struct node *llink,*rlink;
}stud;
stud * creat(int n)
{
stud *p,*h,*s;
int i;
if((h=(stud *)malloc(sizeof(stud)))==NULL)
{
printf("不能分配内存空间!");
exit(0);
}
h->name[0]=’\0’;
h->llink=NULL;
h->rlink=NULL;
p=h;
for(i=0;i<n;i++)
{
if((s= (stud *) malloc(sizeof(stud)))==NULL)
{
printf("不能分配内存空间!");
exit(0);
}
p->rlink=s;
printf("请输入第%d个人的姓名",i+1);
scanf("%s",s->name);
s->llink=p;
s->rlink=NULL;
p=s;
}
h->llink=s;
p->rlink=h;
return(h);
}
stud * search(stud *h,char *x)
{
stud *p;
char *y;
p=h->rlink;
while(p!=h)
{
y=p->name;
if(strcmp(y,x)==0)
return(p);
else p=p->rlink;
}
printf("没有查找到该数据!");
}
void print(stud *h)
{
int n;
stud *p;
p=h->rlink;
printf("数据信息为:\n");
while(p!=h)
{
printf("%s ",&*(p->name));
p=p->rlink;
}
printf("\n");
}
main()
{
int number;
char studname[20];
stud *head,*searchpoint;
number=N;
clrscr();
head=creat(number);
print(head);
printf("请输入你要查找的人的姓名:");
scanf("%s",studname);
searchpoint=search(head,studname);
printf("你所要查找的人的姓名是:%s",*&searchpoint->name);
}
2009年3月6日星期五
两个变量交换的三种方法
两个变量交换的三种方法
在我们写程序的时候,经常会遇到两个变量A与B交换的操作,通常大家会借助第三个变量来实现:
如:C=A;A=B;B=C;
这种方法需要借助第三变量来实现;
第二种方法是利用加减法实现两个变量的交换,
如:A=A+B;B=A-B;A=A-B;
第三种方法是得用位异或运算来实现,也是效率最高的一种,在大量数据交换的时候,效率明显优于前两种方法,
如:A=A^B;B=A^B;A=A^B;
原理:利用一个数异或本身等于0和异或运算符合交换率。
希望对大家有帮助!
package test;
public class VarTest
{
public static void main(String[] args)
{
int a = 3;
int b = 2;
int c;
c = a;
a = b;
b = c;
System.out.println("a:" + a);
System.out.println("b:" + b);
System.out.println("**********");
a = a + b;
b = a - b;
a = a - b;
System.out.println("a:" + a);
System.out.println("b:" + b);
System.out.println("************");
a = a ^ b;
b = a ^ b;
a = a ^ b;
System.out.println("a:" + a);
System.out.println("b:" + b);
}
}
2009年3月3日星期二
QuickPwn2.2.5多国语言版教程(iPhone 2.2.1固件 破解)
QuickPwn2.2.5多国语言版教程(iPhone 2.2.1固件
破解)
QuickPwn2.2.5下载地址http://www.chinamac.com/download/44922.html
QuickPwn2.2.5(-2)支持2.2.1、2.2、2.1及2.0.x.固件的一代iPhone(越狱+解锁)、iPhone 3G(越狱+不能解锁)以及iPod Touch(一代越狱)。由于此次加入了中文支持,而默认语言是英文,所以先简单介绍一下语言的切换方法:
1.先打开QuickPwqn2.2.5,在弹出的蓝色提示框上点击OK按钮开始使用。
2.注意下最下面状态栏里的小地球了没有?
点击后在弹出的菜单中选择最下方的中文
WOW,中文出现了!
下面详细介绍一下破解过程:
注意:iPhone 3G请暂时不要升级至2.2.1。
注意事项:
1.2008新款MacBook请先行查看其是否支持DFU功能,如果不能,请转移到其它支持DFU的机器或系统下进行破解\越狱工作。
2.iPhone2.2以上的升级请使用iTunes8.0.2进行!
破解所需工具及其它版本破解教程
所需软件 | 下载地址 |
iTunes8.0.2 | 下载地址 |
QuickPwn2.2.5多国语言版 | 下载地址 |
一代:iPhone1,1_2.2.1_5H11_Restore.ipsw | 下载地址 |
二代(3G iPhone):iPhone1,2_2.2.1_5H11_Restore.ipsw | 下载地址 |
BootLoader 3.9和4.6 | 下载地址 |
Microsoft .NET Framework 2.0简体版 | 下载地址 |
其它固件 | 下载地址 |
1.启动软件后不再需要你要破解的设备,连接USB后QuickPwn会自动识别。
2.QuickPwn接下来会自动读取你的固件版本,并在浏览框下方用文字来提示。选择成功后,设备图片上会显示一个绿色的大对勾。
3.直接进入功能选择界面了,这里可以选择是否安装Cydia和Installer,可以选择是否替换开机和恢复画面,还可以选择是否进行解锁(只对1代iPhone起作用)。
如果你是第一次破解2G版的iPhone,则应该把解锁你的iPhone也选中,在稍后的窗口中添加BL36和Bl46两个文件。
如果你是3G版的iPhone则没有“解锁你的iPhone”这个选项。
4.开始破解前的准备画面,QuickPwn会提示你一些注意事项,比如会尝试关闭iTunes、不要在虚拟环境下进行破解等等,这时记得将iPhone与电脑连接好并点击右下角继续。
5.开始破解了,下面显示的是破解的五个步骤,进行到哪个步骤时,相应那一行的文字就会亮起,中间的三步是需要大家跟着操作的,这三步是软件在指导你进入DFU模式。具体过程是:等待QuickPwn帮你进入恢复模式;
当第二行文字亮起时我们需要马上按住Home键并持续5秒,
第三行文字亮起时马上按住电源键但不要放开Home,等待倒计时10秒结束;
第四行文字亮起时我们松开电源键并按住Home不放等待30秒(有时不用等到30秒,会提前结束),成功的话会亮起第五行字并出现进度条。在操作过程中电脑右下角的任务栏会不断弹出一些提示,不用管它。
如果进入DFU失败,会弹出提示让你再按要求操作一遍,直到成功为止。
进入DFU成功后,会看到QuickPwn向iPhone上传文件的进程,耐心等待即可。
6.破解成功后会看到下面的画面,这时等待iPhone重启,重启完毕后iPhone我们就完成了整个的破解工作。
如果进入DFU失败,会弹出提示让你再按要求操作一遍,直到成功为止。
进入DFU成功后,会看到QuickPwn向iPhone上传文件的进程,耐心等待即可。
6.破解成功后会看到下面的画面,这时等待iPhone重启,重启完毕后iPhone我们就完成了整个的破解工作。
http://www.chinamac.com/uploadfile/2009/0203/20090131163228415.jpg