本章目标

l 了解Linux的文件系统层次标准(FHS)

l 了解根文件系统下各目录的作用

l 掌握构建根文件系统的方法:移植Busybox、构造各个目录、文件等

l 掌握制作yaffs、jffs2文件系统映象文件的方法

推广

想了解更多嵌入式知识请移步到

100ask.taobao.com

 

17.1  Linux文件系统概述

17.1.1  Linux文件系统的特点

类似于Windows下的C、D、E等各个盘,Linux系统也可以将磁盘、Flash等存储设备划分为若干个分区,在不同分区存放不同类别的文件。与Windows的C盘类似,Linux一样要在一个分区上存放系统启动所必需的文件,比如内核映象文件(在嵌入式系统中,内核一般单独存放在一个分区中)、内核启动后运行的第一个程序(init)、给用户提供操作界面的shell程序、应用程序所依赖的库等。这些必需的、基本的文件,合称为根文件系统,它们存放在一个分区中。Linux系统启动后首先挂接这个分区──称为挂接(mount)根文件系统。其他分区上所有目录、文件的集合,也称为文件系统,比如我们常说:“挂接硬盘第二个分区”、“挂接硬盘第二个分区上的文件系统”。

Linux中并没有C、D、E等盘符的概念,它以树状结构管理所有目录、文件,其他分区挂接在某个目录上──这个目录被称为挂接点或安装点(mount point),然后就可以通过这个目录来访问这个分区上的文件了。比如根文件系统被挂接在根目录“/”上后,在根目录下就有根文件系统的各个目录、文件:/bin、/sbin、/mnt等;再将其他分区挂接到/mnt目录上, /mnt目录下就有这个分区的各个目录、文件。

在一个分区上存储文件时,需要遵循一定的格式,这种格式称为文件系统类型,比如fat16、fat32、ntfs、ext2、ext3、jffs2、yaffs等。除这些拥有实实在在的存储分区的文件系统类型外,Linux还有几种虚拟的文件系统类型,比如proc、sysfs等,它们的文件并不存储在实际的设备上,而是在访问它们时由内核临时生成。比如proc文件系统下的uptime文件,读取它时可以得到两个时间值(用来表示系统启动后运行的时间秒数、空闲的时间秒数),每次读取时都由内核即刻生成,每次读取结果都不一样。

“文件系统类型”常被简称为“文件系统”,比如“硬盘第二个分区上的文件系统是EXT2”──这时指的就是文件系统类型。所以“文件系统”这个术语,有时候指的是分区上的文件集合,有时候指的是文件系统类型,需要根据语境分辨,读者在阅读各类文献时需要注意这点。

 

17.1.2  Linux根文件系统目录结构

为了在安装软件时能够预知文件、目录的存放位置,为了让用户方便地找到不同类型的文件,在构造文件系统时,建议遵循FHS标准(Filesystem Hierarchy Standard,文件系统层次标准)。它定义了文件系统中目录、文件分类存放的原则、定义了系统运行所需的最小文件、目录的集合,并列举了不遵循这些原则的例外情况及其原因。FHS并不是一个强制的标准,但是大多的Linux、Unix发行版本遵循FHS。

本节根据FHS标准描述Linux根文件系统的目录结构,并不深入描述各个子目录的结构,读者可以自行阅读FHS标准了解这些内容。FHS文档可以从网站http://www.pathname.com/fhs/中下载。

Linux根文件系统中一般有如图17.1所示的几个目录。

 

图17.1 Linux根文件系统结构

下面依次讲述这几个目录的作用。

1. /bin目录

该目录下存放所有用户(包括系统管理员和一般用户)都可以使用的、基本的命令,这些命令在挂接其他文件系统之前就可以使用,所以/bin目录必须和根文件系统在同一个分区中。

/bin目录下常用的命令有:cat、chgrp、chmod、cp、ls、sh、kill、mount、umount、mkdir、mknod、[、test等。额外说明,[命令其实就是test命令,在脚本文件中“[ expr ]”就等价于“test expr”。

2. /sbin目录

该目录下存放系统命令,即只有管理员能够使用的命令,系统命令还可以存放在/usr/sbin、/usr/local/sbin目录下。/sbin目录中存放的是基本的系统命令,它们用于启动系统、修复系统等。与/bin目录相似,在挂接其他文件系统之前就可以使用/sbin,所以/sbin目录必须和根文件系统在同一个分区中。

/sbin目录下常用的命令有:shutdown、reboot、fdisk、fsck等。

不是急迫需要使用的系统命令存放在/usr/sbin目录下。本地安装的(Locally-installed)的系统命令存放在/usr/local/sbin目录下。

3. /dev目录

该目录下存放的是设备文件。设备文件是Linux中特有的文件类型,在Linux系统下,以文件的方式访问各种外设,即通过读写某个设备文件操作某个具体硬件。比如通过“/dev/ttySAC0”文件可以操作串口0,通过“/dev/mtdblock1”可以访问MTD设备(NAND Flash、NOR Flash等)的第2个分区。

设备文件有两种:字符设备和块设备。在PC上执行命令“ls /dev/ttySAC0 /dev/hda1 -l”可以看到如下结果。其中首行的字母“b”、“c”表示这是一个块设备文件或字符设备文件;“3,   1”、“4,  64”表示设备文件的主、次设备号;主设备号用来表示这是哪类设备,次设备号用来表示这是这类设备中的哪个。

brwxrwxr-x    1 root     49         3,   1 Oct  9  2005 /dev/hda1

crwxrwxr-x    1 root     root       4,  64 Sep 24  2007 /dev/ttySAC0

 

设备文件可以使用mknod命令创建,比如:

mknod /dev/ttySAC0 c 4 64

mknod /dev/hda1 b 3 1

 

/dev的创建有3种方法:

(1)手动创建。

在制作根文件系统的时候,就在/dev目录下创建好要使用的设备文件,比如ttySAC0等。系统挂接根文件系统后,就可以使用/dev目录下的设备文件了。

(2)使用devfs文件系统:这种方法已经过时

在以前的内核中,有一个配置选项CONFIG_DEVFS_FS,它用来将虚拟文件系统devfs挂接在/dev目录上,各个驱动程序注册时会在/dev目录下自动生成各种设备文件。这就免去了手动创建设备文件的麻烦,在制作根文件系统时,/dev目录可以为空。

使用devfs比手动创建设备节点带来很多便利,但是它仍有一些无法克服的缺点,比如:

① 不确定的设备映射:

比如USB接口连接两台打印机A和B,在都开机的情况下以/dev/usb/lp0访问A、以/dev/usb/lp1访问B。但是假如A没有上电,则系统启动时会根据扫描到的设备的顺序,以/dev/usb/lp0访问B。

② 没有足够的主/次设备号:

主次设备号是两个8位的数字,它们并不足以与日益增加的外设一一对应。

③ 命名不够灵活:

由于devfs由内核创建设备节点,当想重新修改某个设备的名字时需要修改、编译内核。

④ devfs消耗大量的内存

由于这些缺点,在linux 2.3.46引入devfs之后,又在linux 2.6.13后面的版本中移除了devfs,而使用udev机制代替。

 

(3)udev。

udev是个用户程序(u 是指user space,dev是指device),它能够根据系统中硬件设备的状态动态地更新设备文件,包括设备文件的创建,删除等。

使用udev机制也不需要在/dev目录下创建设备节点,它需要一些用户程序的支持,并且内核要支持sysfs文件系统。它的操作相对复杂,但是灵活性很高。

在busybox中有一个mdev命令,它是udev命令的简化版本。

 

4. /etc目录

如表17.1、17.2所示,该目录下存放各种配置文件。对于PC上的Linux系统,/etc目录下目录、文件非常多,比如下面两个表格所列出来的。这些目录、文件都是可选的,它们依赖于系统中所拥有的应用程序,依赖于这些程序是否需要配置文件。在嵌入系统中,这些内容可以大为精减。

17.1                       

/etc目录下的子目录

目录 描述
opt 用来配置/opt下的程序(可选)
X11

用来配置X Window(可选)

sgml


用来配置SGML(可选)



xml


用来配置XML(可选)




17.2    

 /etc目录下的文件

文件 描述
export 用来配置NFS文件系统(可选)
fstab 用来指明当执行“mount -a”时,需要挂接的文件系统(可选)
mtab 用来显示已经加载的文件系统,通常是/proc/mounts的链接文件(可选)
ftpusers 启动FTP服务时,用来配置用户的访问权限(可选)
group 用户的组文件(可选)
inittab init进程的配置文件(可选)


 
ld.so.conf
其他共享库的路径(可选)
passwd 密码文件(可选)


5. /lib
目录 

该目录下存放共享库和可加载模块(即驱动程序),其中的共享库用于启动系统、运行根文件系统中的可执行程序,比如/bin、/sbin目录下的程序。其他不是根文件系统所必需的库文件可以放在其他目录,比如/usr/lib、/usr/X11R6/lib、/var/lib等。

表17.3是/lib目录中的内容。

17.3                           

/lib目录中的内容

目录/文件 描述
libc.so.* 动态连接C库(可选)
ld* 连接器、加载器(可选)
modules 内核可加载模式存放的目录(可选)


6. /home
目录 

用户目录,它是可选的。对于每个普通用户,在/home目录下都有一个以用户名命名的子目录,里面存放用户相关的配置文件。

 

7. /root目录

根用户(用户名为root)的目录,与此对应,普通用户的目录是/home下的某个子目录。

 

8. /usr目录

/usr目录的内容可以存在另一个分区中,在系统启动后再挂接到根文件系统中的/usr目录下。里面存放的是共享的、只读的程序和数据,这表明/usr目录下的内容可以在多个主机间共享──这要这些主机也是符合FHS标准的,/usr中的文件应该是只读的,其他主机相关的、可变的文件应该保存在其他目录下,比如/var。

/usr目录通常包含如下内容,嵌入式系统中,这些内容可以进一步精减。/usr目录中的内容如表17.4所示。

17.4                              

/usr目录中的内容

目录 描述
bin 很多用户命令存放在这个目录下
include C程序的头文件,这在PC上进行开发时才用到,在嵌入式系统中不需要
lib 库文件
local 本地目录
sbin 非必需的系统命令(必需的系统命令放在/sbin目录下)
share 架构无关的数据
X11R6 XWindow系统
games 游戏
src 源代码


9. /var
目录 

与/usr目录相反,/var目录中存放可变的数据,比如spool目录(mail、news、打印机等用的), log文件、临时文件。

 

10. /proc目录

这是一个空目录,常作为proc文件系统的挂接点。proc文件系统是个虚拟的文件系统,它没有实际的存储设备,里面的目录、文件都是由内核临时生成的,用来表示系统的运行状态,也可以操作其中的文件控制系统。

系统启动后,使用以下命令挂接proc文件系统(常在/etc/fstab进行设置以自动挂接):

# mount –t proc none /proc

 

11. /mnt目录

用于临时挂接某个文件系统的挂接点,通常是空目录;也可以在里面创建一些空的子目录,比如/mnt/cdram、/mnt/hda1等,用来临时挂接光盘、硬盘。

 

12. /tmp目录

用于存放临时文件,通常是空目录。一些需要生成临时文件的程序要用到/tmp目录,所以/tmp目录必须存在并可以访问。

为减少对Flash的操作,当在/tmp目录上挂接内存文件系统,如下:

# mount –t tmpfs none /tmp

 

 

17.1.3  Linux文件属性介绍

Linux系统有如表17.5所示的几种文件类型。

17.5                             

Linux文件类型

文件类型 描述
普通文件 这是最常见的文件类型
目录文件 目录也是一种文件
字符设备文件 用来访问字符设备
块设备文件 用来访问块设备
FIFO 用于进程间的通信,也称为命名管道
套接口 用于进程间的网络通信
连接文件 它指向另一个文件,有软连接、硬连接


使用“ls -lih”命令可以看到各个文件的具体信息,下面选取这几种文件,列出它们的信息:
 

228883 -rw-r--r--    2 root     root            6 Sep 27 22:10 readme.txt

228884 lrwxrwxrwx    1 root     root           10 Sep 27 22:11 ln_soft -> readme.txt

 228883 -rw-r--r--    2 root     root            6 Sep 27 22:10 ln_hard

 228882 drwxr-xr-x    2 root     root         4.0K Sep 27 22:10 tmp_dir

 228880 crw-r--r--    1 root     root       4,  64 Sep 27 22:09 ttySAC0

 228881 brw-r--r--    1 root     root      31,   0 Sep 27 22:09 mtdblock0

 228885 prw-r--r--    1 root     root            0 Sep 27 22:16 my_fifo

343929 srwxr-xr-x    1 root     root            0 May 20  2006 klaunchertIdhOa.slave-socket

除设备文件ttySAC0、mtdblock0外,这些信息都分为8个字段,比如:

228883 -rw-r--r--    2 root     root            6 Sep 27 22:10 readme.txt

字段1     2         3  4        5              6      7          8

它们的意义如下:

(1)字段1:文件的索引节点inode

索引节点里存放一个文件的上述信息,比如文件大小、属主、归属的用户组、读写权限等,并指明文件的实际数据存放的位置。

(2)字段2:文件种类和权限

这字段共分10位,格式如下:

图17.2 文件类型及属性


文件类型有7种,“-”表示普通文件,“d”表示目录,“c”表示字符设备,“b”表示块设备,“p”表示FIFO(即管道),“l”表示软连接(也称符号连接),“s”表示套接口(socket)。

没有专门的符号来表示“硬连接”类型,硬连接也是普通文件,只不过文件的实际内容只有一个副本,连接文件、被连接文件都指向它。比如上面的ln_hard文件是使用命令“ln readme.txt ln_hard”创建出来的到readme.txt文件的硬连接,readme.txt和ln_hard的地位完全一致,它们都指向文件系统中的同一个位置,它们的“硬连接个数”都是2,表示这个文件的实际内容被引用两次──可以从上面的文件信息中看到这两个文件的inode都是228883。

硬连接文件的引入作用有二:使得可以用别名来引用一个文件,避免文件被误删除──只有当硬连接个数为1时,对一个文件执行删除操作才会真正删除文件的副本。但是它有如下缺点:不能创建到目录的连接,被连接文件和连接文件必须在同一个文件系统中。对此,引入软连接,也称符号连接,软连接只是简单地指向一个文件(可以是目录),并不增加它的硬连接个数。比如上面的ln_soft文件就是使用命令“ln -s readme.txt ln_hard”创建出来的到readme.txt文件的软连接,它使用另一个inode。

剩下的9位分为3组,分别用来表示文件拥有者、同一个群组的用户、其他用户对这个文件的访问权限。每组权限由rwx三位组成,表示可读、可写、可执行。如果某一位被设为“-”,则表示没有相应的权限,比如“rw-”表示只有读写权限,没有执行权限。

(3)字段3:硬连接个数,这在上面已经提到。

(4)字段4:文件拥有者

(5)字段5:所属群组

(6)字段6:文件或目录的大小

(7)字段7:最后访问或修改时间

(8)字段8:文件名或目录名

 

对于设备文件,字段6表示主设备号,字段7表示次设备号。

 

17.2  移植Busybox

所谓制作根文件系统,就是创建上节提到的各种目录,并且在里面创建各种文件。比如在/bin、/sbin目录下存放各种可执行程序,在/etc目录下存放配置文件,在/lib目录下存放库文件。这节讲述如何使用Busybox来创建/bin、/sbin等目录下的可执行文件。

17.2.1  Busybox概述

Busybox是一个遵循GPL v2协议的开源项目。Busybox将众多的UNIX命令集合进一个很小的可执行程序中,可以用来替换GNU fileutils、shellutils等工具集。Busybox中各种命令与相应的GNU工具相比,所能提供的选项较少,但是能够满足一般应用。Busybox为各种小型的或者嵌入式系统提供了一个比较完全的工具集。

Busybox在编写过程对文件大小进行的优化,并考虑了系统资源有限(比如内存等)的情况。与一般的GNU工具集动辄几M的体积相比,动态连接的Busybox只有几百K,即使静态连接也只有1M左右。Busybox按模块进行设计,可以很容易地加入、去除某些命令,或增减命令的某些选项。

在创建一个最小的根文件系统时,使用Busybox的话,只需要在/dev目录下创建必要的设备节点、在/etc目录下创建一些配置文件就可以了──当然,如果Busybox使用动态连接,还要在/lib目录下包含库文件。

Busybox支持uClibc库和glibc库,对Linux 2.2.x之后的内核支持良好。

Busybox的官方网站是http://www.busybox.net/,源码可以从http://www.busybox.net/downloads/下载,本书使用busybox-1.7.0.tar.bz2。

 

17.2.2  init进程介绍及用户程序启动过程

本节介绍Linux系统中用户程序启动的一些基础知识,读者可以直接阅读下一节开始移植Busybox。

init进程是由内核启动的第一个(也是唯一的一个)用户进程(进程ID为1),它根据配置文件决定启动哪些程序,比如执行某些脚本、启动shell、运行用户指定的程序等。init进程是后续所有进程的发起者,比如init进程启动/bin/sh程序后,才能够在控制台上输入各种命令。

init进程的执行程序通常是/sbin/init,上面讲述的init进程的作用只不过是/sbin/init这个程序的功能。我们完全可以编写自己的/sbin/init程序,或者传入命令行参数“init=xxxxx”指定某个程序作为init进程运行。

一般而言,在Linux系统有两种init程序:BSD init和System V init。BSD和System V是两种版本的UNIX系统。这两种init程序各有优缺点,现在大多Linux的发行版本使用System V init。但是在嵌入式领域,通常使用Busybox集成的init程序,下面基于它进行讲解。

1. 内核如何启动init进程

内核启动的最后一步就是启动init进程,代码在init/main.c文件中:

748 static int noinline init_post(void)

749 {

……

756     if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)

757         printk(KERN_WARNING "Warning: unable to open an initial console.\n");

758

759     (void) sys_dup(0);

760     (void) sys_dup(0);

761

762     if (ramdisk_execute_command) {

763         run_init_process(ramdisk_execute_command);

764         printk(KERN_WARNING "Failed to execute %s\n",

765                 ramdisk_execute_command);

766     }

……

774     if (execute_command) {

775         run_init_process(execute_command);

776         printk(KERN_WARNING "Failed to execute %s.  Attempting "

777                     "defaults...\n", execute_command);

778     }

779     run_init_process("/sbin/init");

780     run_init_process("/etc/init");

781     run_init_process("/bin/init");

782     run_init_process("/bin/sh");

783

784     panic("No init found.  Try passing init= option to kernel.");

785 }

786

代码并不复杂,其中的run_init_process函数使用它的参数所指定的程序来创建一个用户进程。需要注意,一旦run_init_process函数创建进程成功,它将不会返回。

内核启动init进程的过程如下:

(1) 打开标准输入、标准输出、标准错误设备。

Linux中最先打开的3个文件分别称为标准输入(stdin)、标准输出(stdout)、标准错误(stderr),它们对应的文件描述符分别为0、1、2。所谓标准输入就是在程序中使用scanf(……)、fscanf(stdin, ……)获取数据时,从哪个文件(设备)读取数据;标准输出、标准错误都是输出设备,前者对应printf(……)、fprintf(stdout, ……),后者对应fprintf(stderr, ……)。

第756行尝试打开/dev/console设备文件,如果成功,它就是init进程标准输入设备。

第759、760将文件描述符0复制给文件描述符1、2,所以标准输入、标准输出、标准错误都对应同一个文件(设备)。

在移植Linux内核时,如果发现打印出“Warning: unable to open an initial console.”,其原因大多是:根文件系统虽然被正确挂接了,但是里面的内容不正确──要么没有/dev/console这个文件,要么它没有对应的设备。

 

(2) 如果ramdisk_execute_command变量指定了要运行的程序,启动它。

ramdisk_execute_command的取值(代码也在init/main.c中)分3种情况:

① 如果命令行参数中指定了“rdinit=……”,则ramdisk_execute_command等于这个参数指定的程序。

② 否则,如果/init程序存在,ramdisk_execute_command就等于“/init”。

③ 否则,ramdisk_execute_command为空。

本书所用的命令行没有设定“rdinit=……”,根文件系统中也没有/init程序,所以ramdisk_execute_command为空,第763~765这几行的代码不执行。

 

(3) 如果execute_command变量指定了要运行的程序,启动它。

如果命令行参数中指定了“init=……”,则execute_command等于这个参数指定的程序,否则为空。

本书所用的命令行没有设定“init=……”,所以第775~777这几行的代码不执行。

 

(4) 依次尝试执行/sbin/init、/etc/init、/bin/init、/bin/sh。

第779行执行/sbin/init程序,这个程序在我们的根文件系统中是存在的,所以init进程所用的程序就是/sbin/init。从此系统的控制权交给/sbin/init,不再返回init_post函数中。

run_init_process函数也在init/main.c中,代码如下:

184 static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };

185 char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };

……

739 static void run_init_process(char *init_filename)

740 {

741     argv_init[0] = init_filename;

742     kernel_execve(init_filename, argv_init, envp_init);

743 }

744

所以执行/sbin/init程序时,它的环境参数为“"HOME=/", "TERM=linux"”。

 

2. Busybox init进程的启动过程

Busybox init程序对应的代码在init/init.c文件中,下面以busybox-1.7.0为例进行讲解。

先概述其流程,再结合一个/etc/inittab文件讲述init进程的启动过程。

(1)Busybox init程序流程。

流程图如图17.3所示,其中与构建根文件系统关系密切的是控制台的初始化、对inittab文件的解释及执行。

图17.3 Busybox init程序流程图

 

内核启动init进程时已经打开“/dev/console”设备作为控制台,一般情况下Busybox init程序就使用/dev/console。但是如果内核启动init进程的同时设置了环境变量CONSOLE或console,则使用环境变量所指定的设备。在Busybox init程序中,还会检查这个设备是否可以打开,如果不能打开则使用“/dev/null”。

Busybox init进程只是作为其他进程的发起者和控制者,并不需要控制台与用户交互,所以init进程会把它关掉──系统启动后运行命令“ls /proc/1/fd/”可以看到该目录为空。init进程创建其他子进程时,如果没有在/etc/inittab中指明它的控制台,则使用前面确定的控制台。

 

/etc/inittab文件的相关文档和示例代码都在Busybox的examples/inittab文件中。

如果存在/etc/inittab文件,Busybox init程序解析它,然后按照它的指示创建各种子进程;否则使用默认的配置创建子进程。

/etc/inittab文件中每个条目用来定义一个子进程,并确定它的启动方法。格式如下:

<id>:<runlevels>:<action>:<process>

例如:

ttySAC0::askfirst:-/bin/sh

对于Busybox init程序,上述各个字段作用如下:

① <id>:表示这个子进程要使用的控制台(即标准输入、标准输出、标准错误设备)。如果省略,则使用与init进程一样的控制台。

② <runlevels>:对于Busybox init程序,这个字段没有意义,可以省略。

③ <action>:

表示init进程如何控制这个子进程,有如表17.6所示的8种取值:

17.6                  /etc/inittab文件中<action>字段的意义

action名称 执行条件 说明
sysinit 系统启动后最先执行 只执行一次,init进程等待它结束才继续执行其他动作

wait

 

系统执行完sysinit进程后 只执行一次,init进程等待它结束才继续执行其他动作
once 系统执行完wait进程后 只执行一次,init进程不等待它结束
respawn 启动完once进程后 init进程监测发现子进程退出时,重新启动它
askfirst 启动完respawn进程后 与respawn类似,不过init进程先输出“Please press Enter to activate this console.”,等用户输入回车键之后才启动子进程。
shutdown 当系统关机时 即重启、关闭系统命令时
restart Busybox中配置了CONFIG_FEATURE_USE_INITTAB,并且init进程接收到SIGHUP信号时 先重新读取、解析/etc/inittab文件,再执行restart程序
ctrlaltdel 按下Ctrl+Alt+Delete组合键时  


④ <process>:要执行的程序,它可以是可执行程序,也可以是脚本。
 

如果<procss>字段前有“-”字符,这个程序被称为“交互的”。

 

在/etc/inittab文件文件的控制下,init进程的行为总结如下:

① 在系统启动前期,init进程首先启动<action>为sysinit、wait、once的3类子进程。

② 在系统正常运行期间,init进程首先启动<action>为respawn、askfirst的两类子进程,并监视它们,发现某个子进程退出时重新启动它。

③ 在系统退出时,执行<action>为shutdown、restart、ctrlaltdel的3类子进程(之一或全部)。

 

如果根文件系统中没有/etc/inittab文件,Busybox init程序将使用如下默认的inittab条目:

::sysinit:/etc/init.d/rcS

::askfirst:/bin/sh

tty2::askfirst:/bin/sh

tty3::askfirst:/bin/sh

tty4::askfirst:/bin/sh

::ctrlaltdel:/sbin/reboot

::shutdown:/sbin/swapoff -a

::shutdown:/bin/umount -a -r

::restart:/sbin/init

 

(2)/etc/inittab实例。

仿照Busybox的examples/inittab文件,创建一个inittab文件,内容如下:

# /etc/inittab

# 这是init进程启动的第一个子进程,它是一个脚本,可以在里面指定用户想执行的操作

# 比如挂接其他文件系统、配置网络等

::sysinit:/etc/init.d/rcS

 

# 启动shell,以/dev/ttySAC0作为控制台

ttySAC0::askfirst:-/bin/sh

 

# 按下Ctrl+Alt+Delete之后执行的程序,不过在串口控制台中无法输入Ctrl+Alt+Delete组合键

::ctrlaltdel:/sbin/reboot

# 重启、关机前执行的程序

::shutdown:/bin/umount -a -r

 

17.2.3  编译/安装Busybox

http://www.busybox.net/downloads/下载busybox-1.7.0.tar.bz2。

使用如下命令解压得到busybox-1.7.0目录,里面就是所有的源码:

$ tar xjf busybox-1.7.0.tar.bz2

 

Busybox集合了几百个命令,在一般系统中并不需要全部使用。可以通过配置Busybox来选择这些命令、定制某些命令的功能(选项)、指定Busybox的连接方法(动态连接还是静态连接)、指定Busybox的安装路径。

1.  配置Busybox

在busybox-1.7.0目录下执行“make menuconfig”命令即可进入配置界面。Busybox将所有配置项分类存放,表17.7列出了这些类别,其中的“说明”是针对嵌入式系统而言的:

17.7                         Busybox配置选项分类

配置项类型 说明
Busybox Settings Busybox的一些总体设置,里面分为下面5个子类

Busybox Settings --->

General Configuration

一些通用的设置,一般不需要理会

Busybox Settings --->

Build Options

连接方式、编译选项等

Busybox Settings --->

Debugging Options

调试选项,使用Busybox时将打印一些调试信息。一般不选。

Busybox Settings --->

Installation Options

Busybox的安装路径,不需设置,可以在命令行中指定

Busybox Settings --->

Busybox Library Tuning

Busybox的性能微调,比如设置在控制台上可以输入的最大字符个数,一般使用默认值即可
Archival Utilities 各种压缩、解压缩工具,根据需要选择相关命令
Coreutils 核心的命令,比如ls、cp等。
Console Utilities 控制台相关的命令,比如清屏命令clear等。只是提供一些方便而已,可以不理会。
Debian Utilities Debian命令(Debian是Linux的一种发行版本),比如which命令可以用来显示一个命令的完整路径。
Editors 编辑命令,一般都选中vi
Finding Utilities 查找命令,一般不用
Init Utilities init程序的配置选项,比如是否读取inittab文件。使用默认配置即可。
Login/Password Management Utilities 登录、用户帐号/密码等方面的命令
Linux Ext2 FS Progs Ext2文件系统的一些工具
Linux Module Utilities 加载/卸载模块的命令,一般都选中
Linux System Utilities 一些系统命令,比如显示内核打印信息的dmesg命令、分区命令fdisk等。
Miscellaneous Utilities 一些不好分类的命令
Networking Utilities 网络方面的命令,可以选择一些可以方便调试的命令,比如telnetd、ping、tftp等。
Process Utilities 进程相关的命令,比如查看进程状态的命令ps、查看内存使用情况的命令free、发送信号的命令kill、查看最消耗CPU资源的前几个进程的命令top等。为方便调试,可以都选中。
Shells 有多种shell,比如msh、ash等。一般选择ash。
System Logging Utilities 系统记录(log)方面的命令
Runit Utilities 本书没有用到
ipsvd utilities 监听TCP、DPB端口,发现有新的连接时启动某个程序
   

 本节使用默认配置,执行“make menuconfig”后退出、保存配置即可。

下面只讲述一些常用的选项,以便读者参考。Busybox的配置过程大多是选择、去除各种命令,一目了然。

(1)Busybox的性能微调。

设置TAB键补全,比如在控制给上输入一个“ifc”后按TAB键,它会补全为“ifconfig”。如下配置:

Busybox Settings  --->

    Busybox Library Tuning  --->

        [*]   Tab completion

 

(2)连接/编译选项。

以下选项指定是否使用静态连接:

Build Options  --->

    [ ] Build BusyBox as a static binary (no shared libs)

使用glibc时,如果静态编译Buxybox会提示以下警告信息,表示会出现一些莫名其秒的问题:

#warning Static linking against glibc produces buggy executables

所以,本书使用动态连接的Busybos,在构造根文件系统时需要在/lib目录下放置glibc库文件。

 

(3)Archival Utilities选项。

选择tar命令:

Archival Utilities  --->

    [*] tar

    [*]     Enable archive creation

    [*]     Enable -j option to handle .tar.bz2 files

    [*]     Enable -X (exclude from) and -T (include from) options)

    [*]     Enable -z option

    [*]     Enable -Z option

    [*]     Enable support for old tar header format

    [*]     Enable support for some GNU tar extensions

    [*]     Enable long options

 

(4)Linux Module Utilities选项。

要使用可加载模块,下面的配置要选上:

Linux Module Utilities  --->    

    [*] insmod

    [*]   Module version checking

    [*]   Add module symbols to kernel symbol table

    [*]   In kernel memory optimization (uClinux only)

    [*]   Enable load map (-m) option

    [*]     Symbols in load map

    [*] rmmod

    [*] lsmod

    [*] Support version 2.6.x Linux kernels

(5)Linux System Utilities选项。

支持mdev,这可以很方便地构造/dev目录,并且可以支持热拔插设备。另外,为方便调试,选中mount、umount命令,并让mount命令支持NFS(网络文件系统)。

Linux System Utilities  --->

    [*] mdev

    [*]   Support /etc/mdev.conf

    [*]     Support command execution at device addition/removal

    [*] mount

    [*]     Support mounting NFS file systems

    [*] umount

    [*]   umount -a option

 

(6)Networking Utilities选项。

除其他默认配置外,增加ifconfig命令:

Networking Utilities  --->

    [*] ifconfig

    [*]     Enable status reporting output (+7k)

    [ ]     Enable slip-specific options "keepalive" and "outfill"

    [ ]     Enable options "mem_start", "io_addr", and "irq"

    [*]     Enable option "hw" (ether only)

    [*]     Set the broadcast automatically

 

2.  编译和安装Busybox

编译之前,先修改Busybox根目录的Makefile,使用交叉编译器:

175 ARCH            ?= $(SUBARCH)

176 CROSS_COMPILE   ?=

改为:

175 ARCH            ?= arm

176 CROSS_COMPILE   ?= arm-linux-

 

然后可执行“make”命令编译Busybox。

最后是安装,执行“make CONFIG_PREFIX=dir_path install”就可以将Busybox安装在dir_name指定的目录下。执行以下命令在/work/nfs_root/fs_mini目录下安装Busybox:

$ make CONFIG_PREFIX=/work/nfs_root/fs_mini install

 

一切完成后,将在/work/nfs_root/fs_mini目录下生成如下文件、目录:

drwxr-xr-x 2 book book 4096 2008-01-22 06:56 bin

lrwxrwxrwx 1 book book   11 2008-01-22 06:56 linuxrc -> bin/busybox

drwxr-xr-x 2 book book 4096 2008-01-22 06:56 sbin

drwxr-xr-x 4 book book 4096 2008-01-22 06:56 usr

 

其中linuxrc和上面分析的/sbin/init程序功能完全一样;其他目录下是各种命令,不过它们都是到/bin/busybox的符号连接,比如/work/nfs_root/fs_mini/sbin目录下:

lrwxrwxrwx 1 book book 14 2008-01-22 06:56 halt -> ../bin/busybox

lrwxrwxrwx 1 book book 14 2008-01-22 06:56 ifconfig -> ../bin/busybox

lrwxrwxrwx 1 book book 14 2008-01-22 06:56 init -> ../bin/busybox

lrwxrwxrwx 1 book book 14 2008-01-22 06:56 insmod -> ../bin/busybox

lrwxrwxrwx 1 book book 14 2008-01-22 06:56 klogd -> ../bin/busybox

……

除bin/busybox外,其他文件都是到bin/busybox的符号连接──busybox是所有命令的集合体,这些符号连接文件可以直接运行。比如在开发板上,运行“ls”命令和“busybox ls”命令是一样的。

 

 

17.3  使用glibc

在第二章制作交叉编译工具链时,已经生成了glibc库,可以直接使用它来构建根文件系统。

17.3.1  glibc库的组成

第二章制作的交叉编译工具链中,glibc库的位置是/work/tools/gcc-3.4.5-glibc-2.3.6/arm-linux/lib。

需要澄清一点,这个目录下的文件并非都属于glibc库,比如crt1.o、libstdc++.a等文件是GCC工具本身生成的。本书不区分它们的来源,统一处理。

里面的目录、文件可以分为8类:

① 加载器ld-2.3.6.so、ld-linux.so.2:

动态程序启动前,它们被用来加载动态库。

② 目标文件(.o):

比如crt1.o、crti.o、crtn.o、gcrt1.o、Mcrt1.o、Scrt1.o等。在生成应用程序时,这些文件像一般的目标文件一样被连接。

③ 静态库文件(.a):

比如静态数学库libm.a、静态c++库libstdc++.a等,编译静态程序时会连接它们。

④ 动态库文件(.so、.so.[0-9]*):

比如动态数学库libm.so、动态c++库libstdc++.so等,它们可能是一个链接文件。编译动态库时会用到这些文件,但是不会连接它们──在运行时才连接。

⑤ libtool库文件(.la):

在连接库文件时,这些文件会被用到,比如它们列出了当前库文件所依赖的其他库文件。程序运行时无需这些文件。

⑥ gconv目录:

里面是有头字符集的动态库,比如ISO8859-1.so、GB18030.so等。

⑦ ldscripts目录:

里面是各种连接脚本,在编译应用程序时,它们被用样指定程序的运行地址、各段的位置等。

⑧ 其他目录及文件

 

17.3.2  安装glibc

在开发板上只需要加载器和动态库,假设要构建的根文件系统目录为/work/nfs_root/fs_mini,如下操作即可:

$ mkdir -p /work/nfs_root/fs_mini/lib

$ cd /work/tools/gcc-3.4.5-glibc-2.3.6/arm-linux/lib

$ cp *.so* /work/nfs_root/fs_mini/lib –d

 

上面复制的库文件不是每个都会被用到,可以根据应用程序对库的依赖关系保留需要用到的。通过ldd命令可以查看一个程序会用到哪些库,主机自带的ldd命令不能查看交叉编译出来的程序,有两种替代方法:

① 如果有uClibc-0.9.28的代码,可以进入utils子目录生成ldd.host工具:

$ cd uClibc-0.9.28/utils

$ make ldd.host

然后将生成的ldd.host放到主机/usr/local/bin目录下即可使用。

比如对于动态连接的Busybox,它的库依赖关系如下:

$ ldd.host busybox

        libcrypt.so.1 => /lib/libcrypt.so.1 (0x00000000)

        libm.so.6 => /lib/libm.so.6 (0x00000000)

        libc.so.6 => /lib/libc.so.6 (0x00000000)

        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00000000)

这表示Busybox要使用的库文件有libcrypt.so.1、libm.so.6、libc.so.6,加载器为/lib/ld-linux.so.2(实际上在交叉工具链目录下,加载器为ld-linux.so.2)。上面的“not found”表示主机上没有这个文件──这没关系,单板的根文件系统上有就行。

 

② 可以使用以下命令:

$ arm-linux-readelf -a "your binary" | grep "Shared"

 

比如对于动态连接的Busybox,它的库依赖关系如下:

$ arm-linux-readelf -a ./busybox | grep "Shared"

 0x00000001 (NEEDED)                     Shared library: [libcrypt.so.1]

 0x00000001 (NEEDED)                     Shared library: [libm.so.6]

 0x00000001 (NEEDED)                     Shared library: [libc.so.6]

 

里面没有列出加载器,构造根文件系统时,它也要复制进去。

 

17.4  构建根文件系统

上面两节在介绍了如何安装Busbybox、C库,建立了bin/、sbin/、usr/bin/、usr/sbin/、lib/等目录──最小根文件系统的大部分目录、文件已经建好。本节介绍剩下的部分,假设单板的根文件系统在主机上的目录为/work/nfs_root/fs_mini。

17.4.1  构建etc目录

init进程根据/etc/inittab文件来创建其他子进程,比如调用脚本文件配置IP地址、挂接其他文件系统,最后启动shell等。

etc目录下的内容取决于要运行的程序,本节只需要创建3个文件:etc/inittab、etc/init.d/rcS、etc/fstab。

1.  创建etc/inittab文件

仿照Busybox的examples/inittab文件,在/work/nfs_root/fs_mini/etc目录下创建一个inittab文件,内容如下(其中各行的意义在第17.2.2节的最后有说明):

# /etc/inittab

::sysinit:/etc/init.d/rcS

ttySAC0::askfirst:-/bin/sh

::ctrlaltdel:/sbin/reboot

::shutdown:/bin/umount -a r

 

2.  创建etc/init.d/rcS文件

这是一个脚本文件,可以在里面添加想自动执行命令。以下命令完成配置IP地址、挂接/etc/fstab指定的文件系统:

#!/bin/sh

ifconfig eth0 192.168.1.17

mount -a

第一行表示这是一个脚本文件,运行时使用/bin/sh解析。

第二行用来配置IP地址。

第三行挂接/etc/fstab文件指定的所有文件系统。

最后,还要改变它的属性,使它能够执行:

chmod +x etc/init.d/rcS

 

3.  创建etc/fstab文件

内容如下,表示执行“mount -a”命令后将挂接proc、tmpfs文件系统:

# device     mount-point    type   options        dump  fsck order

proc           /proc        proc   defaults        0     0

tmpfs          /tmp         tmpfs  defaults        0     0

 

/etc/fstab文件被用来定义文件系统的“静态信息”,这些信息被用来控制mount命令的行为。文件中各字段意义如下:

① device:要挂接的设备

比如/dev/hda2、/dev/mtdblock1等设备文件;也可以是其他格式,比如对于proc文件系统这个字段没有意义,可以是任意值;对于NFS文件系统,这个字段为<host>:<dir>。

② mount-point:挂接点

③ type:文件系统类型

比如proc、jffs2、yaffs、ext2、nfs等;也可以是auto,表示自动检测文件系统类型。

④ options:挂接参数,以逗号隔开。

/etc/fstab的作用不仅仅是用来控制“mount -a”的行为,即使是一般的mount命令也受它控制,这可以从表17.8的参数看到。除与文件系统类型相关的参数外,常用的有以下几种取值:

17.8                         /etc/fstab参数字段常用的取值

参数名 说明 默认值
auto
noauto

决定执行“mount -a”时是否自动挂接。

auto:挂接;noauto:不挂接

auto
user
nouser

user:允许普通用户挂接设备;

nouser:只允许root用户挂接设备

nouser
exec
noexec

exec:允许运行所挂接设备上的程序

noexec:不允许运行所挂接设备上的程序

exec
Ro 以只读方式挂接文件系统  
rw 以读写方式挂接文件系统  
sync
async

sync:修改文件时,它会同步写入设备中;

async:不会同步写入

sync
defaults rw、suid、dev、exec、auto、nouser、async等的组合  


⑤ dump和fsck order:用来决定控制dump、fsck程序的行为。
 

dump是一个用来备份文件的程序,fsck是一个用来检查磁盘的程序。要想了解更多信息,请阅读它们的man手册。

dump程序根据dump字段的值来决定这个文件系统是否需要备份,如果没有这个字段,或其值为0,则dump程序忽略这个文件系统。

fsck程序根据fsck order字段来决定磁盘的检查顺序,一般来说对于根文件系统这个字段设为1,其他文件系统设为2。如果设为0,则fsck程序忽略这个文件系统。

 

17.4.2  构建dev目录

本节使用两种方法构建dev目录。

1.  静态创建设备文件

为简单起见,本书先使用最原始的方法处理设备:在/dev目录下静态创建各种节点(即设备文件)。

从系统启动过程可知,涉及的设备有:/dev/mtdblock*(MTD块设备)、/dev/ttySAC*(串口设备)、/dev/console、/dev/null,只要建立以下设备就可以启动系统:

$ mkdir –p /work/nfs_root/fs_mini/dev

$ cd /work/nfs_root/fs_mini/dev

$ sudo mknod console c 5 1

$ sudo mknod null c 1 3

$ sudo mknod ttySAC0 c 204 64

$ sudo mknod mtdblock0 b 31 0

$ sudo mknod mtdblock1 b 31 1

$ sudo mknod mtdblock2 b 31 2

 

注意:在一般系统中,ttySAC0的主设备号为4,但是在S3C2410、S3C2440所用的Linux 2.6.22.6上,它们的串口主设备号为204。

 

其他设备文件可以当系统启动后,使用“cat /proc/devices”命令查看内核中注册了哪些设备,然后一一创建相应的设备文件。

实际上,各个Linux系统中dev目录的内容很相似,本书最终使用的dev目录就是从其他系统中复制过来的。

 

2.  使用mdev创建设备文件

mdev是udev的简化版本,它也是通过读取内核信息来创建设备文件。

mdev的用法请参考busybox-1.7.0/doc/mdev.txt文件。mdev的用途主要有两个:初始化/dev目录、动态更新。“动态更新”不仅是更新/dev目录,还支持热拔插──接入、卸下设备时,执行某些动作,它需要内核支持“hotplugging”,即热热拔插。

要使用mdev,需要内核支持sysfs文件系统,为了减少对flash的读写,还要支持tmpfs文件系统。先确保内核已经设置了CONFIG_SYSFS、CONFIG_TMPFS配置项。

使用mdev的命令如下,请参考它们的注释以了解其作用:

$ mount -t tmpfs mdev /dev             /* 使用内存文件系统,减少对flash的读写 */

$ mkdir /dev/pts                       /* devpts用来支持外部网络连接(telnet)的虚拟终端 */

$ mount -t devpts devpts /dev/pts

$ mount -t sysfs sysfs /sys                   /* mdev通过sysfs文件系统获得设备信息 */

$ echo /bin/mdev > /proc/sys/kernel/hotplug   /* 设置内核,当有设备拔插时调用/bin/mdev程序 */

$ mdev s                                     /* 在/dev目录下生成内核支持的所有设备的结点 */

 

要在内核启动时,自动运行mdev。这要修改/work/nfs_root/fs_mini中的两个文件:修改etc/fstab来自动挂载文件系统、修改etc/init.d/rcS加入要自动运行的命令。修改后的文件如下:

① etc/fstab:

# device     mount-point    type   options        dump  fsck order

proc           /proc        proc   defaults        0     0

tmpfs          /tmp         tmpfs  defaults        0     0

sysfs          /sys         sysfs  defaults        0     0

tmpfs          /dev         tmpfs  defaults        0     0

 

② etc/init.d/rcS:加入下面几行

mount -a

mkdir /dev/pts

mount -t devpts devpts /dev/pts

echo /sbin/mdev > /proc/sys/kernel/hotplug

mdev -s

 

需要注意的是,单板上通过mdev生成的/dev目录中,S3C2410、S3C2440是串口名是s3c2410_serial0、1、 2,不是ttySAC0、1、2。需要修改etc/inittab文件:

ttySAC0::askfirst:-/bin/sh

改为:

s3c2410_serial0::askfirst:-/bin/sh

 

另外,mdev是通过init进程来启动的,在使用mdev构造/dev目录之前,init进程至少要用到设备文件/dev/console、/dev/null。所以要建立这两个设备文件:

$ mkdir –p /work/nfs_root/fs_mini/dev

$ cd /work/nfs_root/fs_mini/dev

$ sudo mknod console c 5 1

$ sudo mknod null c 1 3

 

17.4.3  构建其他目录

其他目录可以是空目录,比如proc、mnt、tmp、sys、root等,如下创建:

# cd /work/nfs_root/fs_mini

# mkdir proc mnt tmp sys root

 

现在,/work/nfs_root/fs_mini目录下就是一个非常小的根文件系统。单板可以将它作为网络根文件系统直接启动。如果要烧入单板,还要将它制作为一个文件──称为映象文件,这在下节介绍。

 

17.4.4  制作/使用yaffs文件系统映象文件

按照前面的方法,在/work/nfs_root目录下构造了两个根文件系统:fs_mini、fs_mini_mdev。前者使用dev/目录中事先建立好的设备文件,后者使用mdev机制来生成dev/目录,它们的差别只在于3点:etc/inittab文件、etc/init.d/rcS文件、dev/目录。下面两节以/work/nfs_root/fs_mini为例制作根文件系统映象。

 

所谓制作文件系统映象文件,就是将一个目录下的所有内容按照一定的格式存放到一个文件中,这个文件可以直接烧写到存储设备上去。当系统启动后挂接这个设备,就可以看到与原来目录一样的内容。

制作不同类型的文件系统映象文件,要使用不同的工具。

1.  修改制作yaffs映象文件的工具

在yaffs源码中有个utils目录(假设这个目录为/work/system/Development/yaffs2/utils),里面是工具mkyaffsimage和mkyaffs2image的源代码。前者用来制作yaffs1映象文件,后者用来制作yaffs2映象文件。

目前mkyaffsimage工具只能生成老格式的yaffs1映象文件,需要修改才能支持新格式。对mkyaffsimage代码的修改都在补丁文件yaffs_util_mkyaffsimage.patch中,读者可以直接打补丁,也可以根据本小节进行修改。

yaffs1新、老格式的不同在于oob区的使用发生了变化:一是ECC较验码的位置发生了变化,二是可用空间即标记(tag)的数据结构定义发生了变化。

另外,由于配置内核时没有设置CONFIG_YAFFS_DOES_ECC,yaffs文件系统将使用MTD设备层的ECC较验方法,制作映象文件时也使用与MTD设备层相同的函数计算ECC码。

① oob区中较验码的位置变化:

oob区中使用6字节来存放ECC较验码,前3字节对应上半页,后3字节对应下半页。

参考第16章中“yaffs文件系统移植”小节,从nand_oob_16结构可知,以前的较验码在oob区中存放的位置为8、9、10、13、14和15,现在改为0、1、2、3、6和7。

 

② oob区中可用空间的数据结构定义变化:

oob区中可用的空间有8字节,它用来存放文件系统的数据,代码中这些数据被称为标记(tag)。

老格式的yaffs1中,这8字节的数据结构如下定义(在yaffs_guts.h文件中):

typedef struct {

    unsigned chunkId:20;

    unsigned serialNumber:2;

    unsigned byteCount:10;

    unsigned objectId:18;

    unsigned ecc:12;

    unsigned unusedStuff:2;

} yaffs_Tags;

 

新格式的yaffs1中,它如下定义(在yaffs_packedtags1.h文件中):

typedef struct {

    unsigned chunkId:20;

    unsigned serialNumber:2;

    unsigned byteCount:10;

    unsigned objectId:18;

    unsigned ecc:12;

    unsigned deleted:1;

    unsigned unusedStuff:1;

    unsigned shouldBeFF;      /* 新格式中,这个字节没有使用,yaffs_PackedTags1还是8字节 */

} yaffs_PackedTags1;

 

新、老结构有细微差别:老结构中有两位没有使用(unusedStuff);新结构中只有一位没有使用,另一位(deleted)被用来表示当前页是否已经删除。

 

③ oob区中ECC码的计算:

如果配置内核时设置了CONFIG_YAFFS_DOES_ECC,则yaffs文件系统将使用yaffs2/yaffs_ecc.c文件中的yaffs_ECCCalculate函数来计算ECC码;否则使用drivers/mtd/nand/nand_ecc.c文件中的nand_calculate_ecc函数。

mkyaffsimage工具原来的代码中使用yaffs_ECCCalculate函数。 由于上面配置内核时,没有选择CONFIG_YAFFS_DOES_ECC,为了使映象文件与内核保持一致,要修改mkyaffsimage源码,使用nand_calculate_ecc函数

 

对mkyaffsimage的修改就是依据这3点进行:

① 增加头文件:

修改文件mkyaffsimage.c,加上下面这行,里面定义了yaffs_PackedTags1结构:

#include "yaffs_packedtags1.h"

 

② 修改mkyaffsimage.c文件的write_chunk函数:

代码如下:

231 static int write_chunk(__u8 *data, __u32 objId, __u32 chunkId, __u32 nBytes)

232 {

233 #ifdef CONFIG_YAFFS_9BYTE_TAGS   /* 如果要生成老格式的yaffs1映象文件,定义这个宏 */

…… /* 原来的代码 */

260 #else

261     yaffs_PackedTags1 pt1;

262     yaffs_ExtendedTags  etags;

263     __u8 ecc_code[6];

264     __u8 oobbuf[16];

265     

266     /* 写页数据,512字节 */

267     error = write(outFile,data,512);

268     if(error < 0) return error;

269

270     /* 构造tag */

271     etags.chunkId       = chunkId;

272     etags.serialNumber  = 0;

273     etags.byteCount     = nBytes;

274     etags.objectId      = objId;

275     etags.chunkDeleted  = 0;

276

277     /*

278      * 重定位oob区中的可用数据(称为tag)

279      */

280     yaffs_PackTags1(&pt1, &etags);

281

282     /* 计算tag本身的ECC码 */

283     yaffs_CalcTagsECC((yaffs_Tags *)&pt1);

284

285     memset(oobbuf, 0xff, 16);

286     memcpy(oobbuf+8, &pt1, 8);

287

288     /*

289      * 使用与内核MTD层相同的方法计算一页数据(512字节)的ECC码

290      * 并把它们填入oob

291      */

292     nand_calculate_ecc(data, &ecc_code[0]);

293     nand_calculate_ecc(data+256, &ecc_code[3]);

294

295     oobbuf[0] = ecc_code[0];

296     oobbuf[1] = ecc_code[1];

297     oobbuf[2] = ecc_code[2];

298     oobbuf[3] = ecc_code[3];

299     oobbuf[6] = ecc_code[4];

300     oobbuf[7] = ecc_code[5];

301

302     nPages++;

303

304     /* 写oob数据,16字节 */

305     return write(outFile, oobbuf, 16);

306 #endif  

307 }

308 

 

值得注意的是:第275行设置新tag结构中增加的chunkDeleted成员;第292~300行将计算出来的ECC码填入新的ECC位置──它正是nand_oob_16结构的eccpos数组定义的位置。

其中第292、293行的nand_calculate_ecc函数是从内核源文件drivers/mtd/nand/nand_ecc.c修改而来:在/work/system/Development/yaffs2/utils目录下新建一个同名文件nand_ecc.c,把内核文件nand_ecc.c的nand_calculate_ecc函数、函数中用到的nand_ecc_precalc_table数组摘出来;并去除函数中的第一个形参“struct mtd_info*mtd”──在这个函数中没用到这个参数。

 

③ 添加文件,修改Makefile:

第280行的yaffs_PackTags1函数在上一层目录yaffs_packedtags1.c中定义,先将这个文件复制到当前目录:

$ cp ../yaffs_packedtags1.c ./

 

另外,and_calculate_ecc函数是在新加的nand_ecc.c中定义的,所以要修改Makefile,把yaffs_packedtags1.c和nand_ecc.c也编译进mkyaffsimage工具中:

31 MKYAFFSSOURCES = mkyaffsimage.c

改为:

31 MKYAFFSSOURCES = mkyaffsimage.c yaffs_packedtags1.c nand_ecc.c

 

现在,在/work/system/Development/yaffs2/utils目录下执行“make”命令生成mkyaffsimage工具,将它复制到/usr/local/bin目录:

$ sudo cp mkyaffsimage /usr/local/bin

$ sudo chmod +x /usr/local/bin/mkyaffsimage

 

2.  制作/烧写yaffs映象文件

使用如下命令将/work/nfs_root/fs_mini目录制作为fs_mini.yaffs文件:

# cd /work/nfs_root

# mkyaffsimage fs_mini fs_mini.yaffs

 

将fs_mini.yaffs放入tftp目录或nfs目录后,在U-Boot控制界面就可以下载、烧入NAND Flash中,操作方法请参考《15.2.6  U-Boot的常用命令》。为方便读者,将命令列出来(以下命令将yaffs.img烧入MTD2分区,即yaffs分区):

① tftp 0x30000000 fs_mini.yaffs 或 nfs 0x30000000 192.168.1.57:/work/nfs_root/fs_mini.yaffs

② nand erase 0xA00000 0x3600000

③ nand write.yaffs 0x30000000 0xA00000 $(filesize)

 

现在可以修改命令行参数以MTD2分区作为根文件系统,比如在U-Boot控制界面如下设置:

# set bootargs noinitrd console=ttySAC0 root=/dev/mtdblock2 rootfstype=yaffs

# saveenv

 

 

17.4.5  制作/使用jffs2文件系统映象文件

1.  编译制作yaffs映象文件的工具

/work/tools/mtd-utils-05.07.23.tar.bz2是MTD设备的工具包,编译它生成mkfs.jffs2工具,用它来将一个目录制作成jffs2文件系统映象文件。

这个工具包需要zlib压缩包,先安装zlib。在/work/GUI/xwindow/X/deps下有zlib源码zlib-1.2.3.tar.gz,执行以下命令进行安装:

$ cd /work/GUI/xwindow/X/deps

$ tar xzf zlib-1.2.3.tar.gz

$ cd zlib-1.2.3

$ ./configure --shared --prefix=/usr

$ make

$ sudo make install

 

然后编译mkfs.jffs2:

$ cd /work/tools

$ tar xjf mtd-utils-05.07.23.tar.bz2

$ cd mtd-utils-05.07.23/util

$ make

$ sudo make install

 

2.  制作/烧写jffs2映象文件

使用如下命令将/work/nfs_root/fs_mini目录制作为fs_mini.jffs2文件:

$ cd /work/nfs_root

$ mkfs.jffs2 -n -s 512 -e 16KiB -d fs_mini -o fs_mini.jffs2

上面命令中,“-n”表示不要在每个擦除块上都加上清除标志,“-s 512”指明一页大小为512字节,“-e 16KiB”指明一个擦除块大小为16KB,“-d”表示根文件系统目录,“-o”表示输出文件。

 

将fs_mini.jffs2放入tftp目录或nfs目录后,在U-Boot控制界面就可以将下载、烧入NAND Flash中,操作方法请参考《15.2.6  U-Boot的常用命令》。为方便读者,将命令列出来(以下命令将jffs2.img烧入MTD1分区,即jffs2分区):

① tftp 0x30000000 fs_mini.jffs2 或 nfs 0x30000000 192.168.1.57:/work/nfs_root/fs_mini.jffs2

② nand erase 0x200000 0x800000

③ nand write.jffs2 0x30000000 0x200000 $(filesize)

 

系统启动后,就可以使用“mount -t jffs2 /dev/mtdblock1 /mnt”挂接jffs2文件系统。

也可以修改命令行参数以MTD1分区作为根文件系统,比如在U-Boot控制界面如下设置:

# set bootargs noinitrd console=ttySAC0 root=/dev/mtdblock1 rootfstype=jffs2

# saveenv

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. Content Provider Basics

    Android API GuidesContent Provider 负责管理访问结构化数据集,encapsulate 数据,提供安全访问数据机制。 访问数据的Client 与 提供数据的Provider 处于两个进程。Client 使用ContentResolver, 负责与实现ContentProvider接口的实例进行进程间通信IPC。 一般来讲,无需开…...

    2024/4/17 6:24:58
  2. 完美开源(基于SpringBoot+Mybatis+Thymeleaf+Vue)开发框架

    完美开源V7.0(基于SpringBoot+Mybatis+Thymeleaf+Vue)开发框架基础开发框架支持多套主界面框架。自定义表单引擎流程引擎数据查询引擎报表计算引擎项目地址 基础开发框架 (国内自主开发框架,操作、配置更简便、执行效率更高效,完全免费使用,开放源代码,可以通过修改代码新增…...

    2024/4/27 13:41:47
  3. win10系统下搭建Python开发环境和TensorFlow深度学习环境(CPU版)

    #win10系统下搭建TensorFlow深度学习环境分两步 文章目录1.1 安装Anaconda(Python编译器+包管理器)1.2 安装Pycharm(Python开发环境) ##1. 搭建Python开发环境 1.1 安装Anaconda(Python编译器+包管理器) 下载Anaconda安装包,按照默认的方式安装即可。 官方下载链接:htt…...

    2024/4/17 6:26:16
  4. C# 页面request传入参数封装进Dictionary

    将Request传递过来的参数放到Dictionary中,可以减少大量的重复代码。用以代替Java中的Request.parameterMap();方法。public static Dictionary<object, object> request2Dic(HttpRequest request){Dictionary<object, object> returnDic = new Dictionary<obj…...

    2024/4/17 6:25:10
  5. 告诉你一个学习编程的诀窍(建议收藏)

    作者 | ithuangqing来源 | 编码之外(ID:ithuangqing)不怕和你说,如果我在大学的时候能够明白这些,说不定我现在已经在阿里上班了,最起码不会像现在这个样子……可能你会好奇,哎,庆哥庆哥,啥东西啊,被你说的那么厉害,我现在还在大学啊,你懂得,哈哈的确,我现在想起…...

    2024/4/17 6:24:46
  6. Android content provider基础与使用

    如果你想实现不同应用之间的数据共享,就不得不用content provider了。在Android中,content provider是一个特殊的存储数据的类型,它提供了一套标准的接口用来获取以及操作数据。并且,android自身也提供了几个现成的content provider:Contacts, Browser, CallLog, Settings…...

    2024/4/27 14:22:23
  7. Java--简单工厂模式、工厂方法模式、抽象工厂模式

    一.实验目的熟悉建模工具。 掌握简单工厂模式、工厂方法模式、抽象工厂模式,并进行设计应用。二、实验内容 (1)、 简单工厂模式使用简单工厂模式模拟女娲(Nvwa)造人(Person),如果传入参数M,则返回一个Man对象,如果传入参数W,则返回一个Woman对象,请实现该场景。现需…...

    2024/4/17 6:24:10
  8. react-native transform如何写

    transform: [{translateX: 100}]...

    2024/4/17 6:23:58
  9. LOL(英雄联盟)的历史之S1赛季

    今天心血来潮,说一说本人最爱的游戏——英雄联盟,说到这个游戏,想必大家并不陌生,就算没有玩过也应听过,这款盛行了数年的游戏不见有衰落之势,因为这款游戏带给玩家的体验是空前绝后的,它不像cs,cf,dnf.......这些游戏一样,它更加的公平,而且游戏的视角发生了极大的…...

    2024/4/20 16:02:51
  10. 规则引擎的介绍与Drools的流程分析

    规则引擎(RuleEngine)是一个有限状态机,通过入参实现状态转移,在Java中定义为JSR94规范。规则引擎目前的开源实现主要是JBoss家族的Drools,采用友好的Apache协议(意味着可以作为商业产品)。以及据说非常贵的ILOG引擎,还有一些国内引擎。 1. 规则引擎的简介 规则引擎一般用于…...

    2024/4/17 6:24:16
  11. 十大在线编程学习网站

    http://www.csdn.net/article/2013-12-03/2817687-best-websites-to-learn-mobile-dev-and-design/2...

    2024/4/17 6:24:40
  12. python实现将深度学习应用于医学图像以辅助医疗

    转自fc013,仅做学习用问题导读:1.怎样利用python处理图像?2.什么是卷积?3.什么是Keras?  运用深度学习技术进行图像和视频分析,并将它们用于自动驾驶汽车、无人机等多种应用场景中已成为研究前沿。近期诸如《A Neural Algorithm of Artistic Style》等论文展示了如何将…...

    2024/4/17 6:24:52
  13. 设计模式系列-2工厂模式

    文章目录工厂模式类图代码实现总结 工厂模式工厂模式下类不会将对象的创建逻辑暴露给用户,也就是不会使用new来创建对象,而是使用提供的通用接口来创建。类图代码实现定义类型接口package com.pattern.factory;public interface Shape {public void draw(); }定义三个具体的行…...

    2024/4/18 15:32:26
  14. Android Document——2.4.1 基本的Content Provider

    Content Provider Basics一个Content Provider的管理器能够访问中央存储库的数据。一个provider是android程序的一部分,该provider通常提供它自己的UI供数据使用。然而,contentprovider最初的目的是被别的app使用client provider object访问数据使用的。Provider和客户端的pr…...

    2024/4/17 6:24:58
  15. 500V,线性稳压器LDO ZCC2786A替代KP3310

    产品描述 ZCC2786A是一款紧凑型无电感设计的离线式线性稳压器。ZCC2786A输出电压已 由内部设定为5V/3.3V/2.7V三个版本。ZCC2786A是一种简单可靠的获得偏置供 电的离线式电源解决方案。 ZCC2786A集成了650V功率MOSFET,启动控制电路,VDD电压控制电路,AC交流 信号同步检测电路…...

    2024/4/17 6:24:16
  16. ​Fedora 22正式版:云系统、桌面和服务器大变革

    Fedora Linux 22已经发布,除桌面版本更新外,真正的改进是在云系统和服务器方能的功能改进。在该版本后,Fedora将重回六个月的版本升级周期,下次的时间点大约在万圣节。Fedora 22是建立在Fedora 21的基础之上,仍然提供工作站(桌面)、服务器和云系统三种类型系统。在Fedor…...

    2024/4/17 6:26:10
  17. 常见深度学习框架比较

    常见的深度学习框架有 TensorFlow 、Caffe、Theano、Keras、PyTorch、MXNet等,如下图所示。这些深度学习框架被应用于计算机视觉、语音识别、自然语言处理与生物信息学等领域,并获取了极好的效果。下面将主要介绍当前深度学习领域影响力比较大的几个框架,内容出自书籍《深度…...

    2024/4/17 6:25:34
  18. 简单工厂模式,工厂方法模式,抽象工厂模式(从放弃到入门)

    简单工厂模式,工厂方法模式,抽象工厂模式(从放弃到入门)@(设计模式)工厂模式,很多讲设计模式的书中,工厂模式都是第一个讲的模式,因为其最简单。但是在实际开发中,工厂模式是非常常见的。在java开发中经常遇到一个类叫 xxxFactory,虽然不是所有带 Factory的类都是工厂…...

    2024/4/17 6:27:04
  19. 软件实训:手把手写一个javaweb项目

    前言: 三个星期的实训过去了大半,剩下的时间要开始搞实训项目,所以花点时间整理一下实训的收获。感谢何老师,讲得简练清晰,引人入胜。感谢相遇。 开发环境: IDE:Eclipse IDEA JDK:JDK8 DB:MySql5.5 服务器:tomcat-7 浏览器:谷歌chrom 实现功能: 1.用户登陆,通过查…...

    2024/4/17 6:25:46
  20. Android Contacts 联系人源码分析

    Android Contacts总览Contacts应用是由Google Android团队编写的Android原生应用。在应用层面上涉及到Contacts.apk, ContactProvider.apk。其他相关的在Framwork,以及framework与linux内核之间的SQLite.Contacts.apk只是界面层的逻辑,主要实现UI的流程。对于联系人的查询,存…...

    2024/4/17 6:26:10

最新文章

  1. 2024年Q1季度洗衣机行业线上市场销售数据分析

    Q1季度洗衣机线上市场表现不如预期。 根据鲸参谋数据显示&#xff0c;2024年1月至3月线上电商平台&#xff08;京东天猫淘宝&#xff09;洗衣机累计销量约650万件&#xff0c;环比下降14%&#xff0c;同比下降14%&#xff1b;累计销售额约96亿元&#xff0c;环比下降30%&#…...

    2024/4/27 15:17:38
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. Windows 2008虚拟机安装、安装VM Tools、快照和链接克隆、添加硬盘修改格式为GPT

    一、安装vmware workstation软件 VMware workstation的安装介质&#xff0c;获取路径&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1AUAw_--yjZAUPbsR7StOJQ 提取码&#xff1a;umz1 所在目录&#xff1a;\vmware\VMware workstation 15.1.0 1.找到百度网盘中vmwa…...

    2024/4/24 23:48:40
  4. 【蓝桥杯嵌入式】13届程序题刷题记录及反思

    一、题目分析 考察内容&#xff1a; led按键&#xff08;短按&#xff09;PWM输出&#xff08;PA1&#xff09;串口接收lcd显示 根据PWM输出占空比调节&#xff0c;高频与低频切换 串口接收&#xff08;指令解析&#xff09;【中断接收】 2个显示界面 led灯闪烁定时器 二…...

    2024/4/25 7:42:47
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/4/26 18:09:39
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/26 20:12:18
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/26 23:05:52
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/4/27 4:00:35
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/25 18:39:22
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/27 14:22:49
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/26 21:56:58
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/27 9:01:45
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/26 16:00:35
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/25 18:39:16
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/25 18:39:16
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/26 22:01:59
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/25 18:39:14
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/4/26 23:04:58
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/25 2:10:52
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/25 18:39:00
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/26 19:46:12
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/4/27 11:43:08
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/27 8:32:30
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57