Linux 系统裁减指南2

4.3 提示
4.3.1 EXTRAVERSION
在系统中使用uname可以获得系统版本信息。比如Redhat 9:
[root@lips root]# uname -r
2.4.20-8
[root@lips root]#
返回结果表示了Redhat修订后的内核版本号。前面我们提到过,这个“-8”就
是Redhat附加在标准内核版本号后面的一个信息。
在一个运行LiPS的系统中,我们也需要确定当前使用的内核版本,通过版本信
息来知道这个内核的配置,也可以通过在标准内核版本后面附加特定的编码来实现

/usr/src/linux-2.4/Makefile中的变量EXTRAVERSION可以帮助我们达到这个目
标。下面是Makefile文件的最前面几行内容:
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 20
EXTRAVERSION = -8
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
现在KERNELRELEASE的值就是2.4.20-8。这个信息会被编译到内核中,uname工
具会从内核文件中提取出版本号。如果将Makefile做一些修改,比如,
EXTRAVERSION = -8-R2Lips
那么我们可以得到内核版本号2.4.20-8-R2Lips,表示为了创建LiPS而编译的一
个特定配置的内核,这个内核是以2.4.20-8为基础,R2Lips(Release 2 Lips)即
第二个版本。
对Makefile的修改要在编译内核之前完成。
4.3.2 .config
内核配置(make menuconfig)完成之后,会询问:
Do you wish to save your new kernel configuration?
< Yes > < No >
回答Yes,配置信息会保存在/usr/src/linux-2.4/.config文件中。注意以“.
”开头的文件是个隐藏文件,要用ls –a才看的到。.config是个文本文件,内容类
似下面:
#
# Loadable module support
#
CONFIG_MODULES=y
# CONFIG_MODVERSIONS is not set
CONFIG_KMOD=y
所以可以把这个文件保存起来,并且给文件名带上版本号,方便管理、使用。

cp .config ~/config-2.4.20-8-R2Lips




5 根文件系统

创建根文件系统比编译内核要复杂的多,也更难理解。这里的关键是掌握init
rd(初始化RAM盘)的使用方法。
5.1 根文件系统
这里我们将要创建的根文件系统与通常Linux主机的根文件系统类似,只是它应
该仅仅包括系统运行所必须的应用程序、库和相关文件的最小集合。根文件系统的
尺寸大小是一个重要的指标。
5.2 文件系统的内容
5.2.1 应用程序(applications)
/bin,/sbin,/usr/bin,/usr/sbin
应用程序大致可以分为3部分,第一是操作系统正常运行所需的基本工具软件,
比如bash,cp,rm等;第二是提供某项服务的服务器软件,比如httpd,telnetd,
proftpd等;第三是我们所开发的应用程序。其实后面讲的配置文件等也可以粗略按
照这个原则来分类。
到底需要复制哪些软件,弹性是比较大的,很多软件都是可要可不要,可以实
际情况灵活选择。这个列表可能很长,并且变化也比较大,因此不在这里列出。
为了进一步减小所创建的根文件系统的尺寸,可以考虑使用下列工具包软件来
替代某些标准的工具:
O BusyBox( http://www.busybox.net)
O TinyLogin( http://tinylogin.busybox.net)
O Embutils( http://www.fefe.de/embutils/)
其详细使用方法请参考相关资料,此处不再赘述。LIPS的实现目前没有使用这
些软件包。
5.2.2 设备文件(device files)
/dev
设备文件也可以称作设备节点(device node)。设备文件非常重要,缺少某些
有些设备文件可能导致系统不能正常运行甚至不能引导。有些设备文件是必须的,
而更多的是根据具体目标系统的硬件配置来进行取舍。
比如硬盘的设备文件,在完整的系统中一般有hda,hdb,……,hdt,即最多支
持20个IDE硬盘,每个硬盘有hdX1,hdX2,……,hdX32,(其中X表示a-t),即支
持32个分区,另外还有表示SCSI硬盘的节点。根据实际情况,如果只需要支持少量
的硬盘、少量的分区,这些节点可以被大大简化。如果目标系统中没有的设备,其
对应的设备文件也可以省掉。
设备文件
描述
/dev/console
系统控制台设备,非常重要。
/dev/fd0
第一个软驱
/dev/hda
/dev/hda[1-8]
IDE硬盘及分区
/dev/initctl
实际上是一个FIFO设备,跟init有关(切换运行级别时用于新init与原init通信)

/dev/initrd
Initial RAM disk
/dev/input
(目录)Input core(包括游戏杆、鼠标等)
/dev/kmem
内核虚拟内存
/dev/loop[0-7]
Loopback设备
/dev/mem
访问物理内存
/dev/null
NULL设备
/dev/psaux
PS/2鼠标
/dev/ptmx
UNIX98 PTY master
/dev/pts
(目录)UNIX98 PTY slaves
/dev/ptyp[0-7]
伪终端主设备(远程登录使用)
/dev/ram[0-7]
/dev/ramdisk
/dev/ram
RAM Disk设备。至少/dev/ram0是应用initrd机制所必须的。
/dev/ramdisk链接到/dev/ram0,是为了兼容老版本内核而保留的。
/dev/ram链接到/dev/ram1。
/dev/random
随机数发生器
/dev/sda
/dev/sda[1-8]
SCSI磁盘及分区设备
/dev/shm
共享内存设备
/dev/systty
指向系统tty设备的符号链接,一般是tty0。
/dev/tty
当前TTY设备
/dev/tty[0-7]
虚控制台(Virtual console)
/dev/ttyp[0-7]
伪终端从设备
/dev/ttyS0
/dev/ttyS1
串口(COM1和COM2)
/dev/urandom
速度更快、安全性较差的随机数发生器
/dev/zero
零设备,只能读0出来
设备节点的主设备号(Major)、次设备号(Minor)的文档是内核源代码中的
/Documentation/device.txt,如果有疑问可以查看这个文件[8]。
5.2.3 脚本和配置文件(scripts and configuration files)
/etc
/etc/rc.d目录下的启动脚本是系统的重要部分。必须对启动脚本做相应的修改
以简化系统的启动过程。
系统和各种应用程序用到的几乎所有的配置文件都位于/etc目录,是裁减Linu
x最麻烦的部分,最容易出问题。配置文件的选择需要综合很多方面的信息,需要对
系统有比较全面、深入的了解,并结合经验才能做出正确的判断。
配置文件
描述
/etc/default
(目录)某个命令(比如useradd)的缺省设置(man useradd(8))
/etc/ld.so.cache
由ldconfig命令根据/etc/ld.so.conf文件产生
/etc/ld.so.conf
库文件路径配置文件,ldconfig命令根据该配置文件生成/etc/ld.so.cache
/etc/localtime
本地时间、时区设置
/etc/login.defs
全局缺省设置
/etc/fstab
文件系统列表(man fstab(5))
/etc/group
组文件(man group(5))
/etc/hosts
列出主机名和IP地址(man hosts(5))
/etc/init.d
符号链接到/etc/rc.d/init.d
/etc/initlog.conf
Initlog日志配置文件(man initlog(8))
/etc/inittab
Init配置文件(man inittab(5))
/etc/ioctl.save
该文件包含了用于单用户模式的串口和终端参数,因为这些参数是由getty设置的,
而在单用户模式时没有运行getty,所以用该文件保存参数。单用户模式对系统安全
是个威胁,我们应该禁止使用单用户模式,因此这个文件实际上并没有必要复制过
来。
/etc/issue
登录信息和标识文件(man issue(5))
/etc/modules.conf
模块的配置文件(man modules.conf(5))
/etc/mtab
已经挂载的文件系统列表(man mount(8))
/etc/nsswitch.conf
Name Service Switch的配置文件(配置名称服务数据源和查询的顺序)(man nss
witch.conf(5))
/etc/pam.d
放置PAM配置文件的目录(有关PAM请参考5.5节)
/etc/passwd
用户口令文件(man passwd(5))
/etc/profile
系统环境变量和登录配置文件
/etc/rc.d
放置启动脚本的目录
/etc/services
列出可用的网络服务及其端口(man services(5))
/etc/termcap
终端(terminal)功能数据库(man termcap(5))
还有那些跟特定应用程序相关的配置文件,比如apache服务器需要的/etc/htt
pd/conf/httpd.conf 等,此处不再一一列出。
5.2.4 库文件(libraries)
/lib,/usr/lib,/usr/share
库文件也是系统运行所必需的。到底需要哪些库文件,是根据所复制的可执行
程序用 ldd 工具来确定的。比如,要知道/bin/bash需要哪些库文件,使用如下命
令:
[root@lips xmdong]# ldd /bin/bash
libtermcap.so.2 => /lib/libtermcap.so.2 (0x40020000)
libdl.so.2 => /lib/libdl.so.2 (0x40024000)
libc.so.6 => /lib/tls/libc.so.6 (0x42000000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
对复制到新的根文件系统的每个可执行程序,都要使用这种方法来确定其所需
要的库,然后把这些库文件也复制过来。
需要注意的是,有些库文件使用上述方法是找不出来的,但是却是系统必须的
。比如:
库文件
描述
/lib/libnss_files*
这个库是跟/etc/nsswitch.conf有关的,必不可少,否则系统不能正常使用。(ma
n nsswitch.conf(5))
/lib/security/pam_unix.so
这个库跟PAM有关,是安全、认证方面的,必不可少,否则系统无法登录。


5.2.5 必要的目录
/home,/mnt,/proc,/root,
/var,/var/log,/var/run,/var/lock/subsys


5.3 初始化RAM盘(initrd)
(参考资料[5])
初始化RAM盘(initrd)提供了引导器加载RAM盘的能力。这个RAM盘可以被挂载
(mount)成根文件系统,并执行其上的程序。然后,可以从另一个设备挂载一个新
的根文件系统,而原来的根文件系统(也就是initrd)会被移到一个目录里并卸载

initrd技术主要设计用来让系统启动过程可以分两个阶段进行,首先让内核以
一组最小的、被编译进内核里的驱动程序来启动,然后从initrd中加载其他的模块

5.3.1 操作步骤
使用initrd时,系统典型的引导步骤如下:
1) 引导器加载内核和初始化RAM盘;
2) 内核把initrd转到一个一般的RAM盘中,并且释放原来被initrd占用的RAM;
3) initrd以可读写模式被挂载到根目录;
4) 执行/linuxrc(linuxrc可以是任何可执行文件,包括shell脚本在内;它具有u
id 0即超级用户的权限,基本上可以做init程序中能够做的任何事情);
5) 在linuxrc中挂载真正的根文件系统;
6) linuxrc使用pivot_root系统调用,把真正使用的根文件系统挂载到根目录;
7) 在根文件系统上执行通常的引导过程(比如执行/sbin/init);
8) initrd文件系统被删除。
注意,改变根目录并不包括卸载旧的根文件系统,因此有可能在转变过程中仍
有进程在initrd上运行。另外,挂载在initrd目录下的根文件系统仍然是可用的。

5.3.2 引导选项
initrd技术增加了下列引导选项:
initrd=<path>
装入指定的文件作为初始化RAM盘。当使用 LILO 当引导器时,你可以用/etc/
lilo.conf 文件中 INITRD 这个配置参数,来指定初始化RAM盘文件。
noinitrd
initrd的数据仍会保留,但不会装入到一个RAM盘里,真正使用的根文件系统将
会被挂载。initrd的数据能夠从 /dev/initrd 这个设备中被读出来。注意,initr
d的数据可以是任何结构,并不一定必须是一个文件系统的映像,这个选项主要用来
进行debug。
注意:/dev/initrd 是一个只读并且只能使用一次的设备,最后一个程序一旦
关闭它, 所有数据将被释放,而且设备也不能再被打开。
root=/dev/ram0
initrd 先被挂载成根目录,接着进行正常的启动过程(这时RAM盘仍被挂载成
根)。
5.3.3 安装
首先:我们要在正常的根文件系统中创建一个容纳initrd文件系统的目录,例
如:
# mkdir /initrd
对目录名称并没有特别的限制,在pivot_root(2)的man手册页中有更详细的说
明。
如果根文件系统是在引导程序时被建立的(例如,你在制作安装软盘),在建
立根文件系统的同时应该创建 /initrd 目录。
在某些情况下initrd虽然未被挂载,只要有下列设备存在,它的內容仍是可被
访问的。(注意:这个设备无法在 devfs 下使用)
# mknod /dev/initrd b 1 250
# chmod 400 /dev/initrd
第二:支持初始化RAM盘的能力,及所有执行格式和文件系统模块,都必须直接
编译进内核,不能采用可加载模块的方式。
第三:必须制作一个RAM盘映像文件。大概的步骤是,在一个块设备上创建一个
文件系统,把需要的文件复制进去,然后把这个块设备的内容输出成一个initrd文
件。目前至少有3种设备适合作为这种块设备:
O 软盘(能拿到任何地方试验,但速度太慢);
O RAM盘(最快,但浪费内存);
O Loopback设备(比较合适的解决方案)。

下面,我们将讨论使用loopback设备创建initrd文件的方法。
1)
确认lookback设备已经配置到内核里。
2)
创建一个适当大小的空白文件系统,例如:
# dd if=/dev/zero of=initrd bs=300k count=1
# mke2fs -F -m0 initrd
3)
把这个文件系统挂载进来,例如:
# mount -t ext2 -o loop initrd /mnt
4)
创建控制台设备。
# mkdir /mnt/dev
# mknod /mnt/dev/console c 5 1
5)
复制所有可能在initrd环境中用到的文件到/mnt目录中。(别忘了/linuxrc文
件)
6)
initrd执行环境的测试需要反复进行修正,为了避免不断的重新启动,可以使
用下列命令:
# chroot /mnt /linuxrc
当然这样启用initrd还是有限制的,就是不能干扰正常系统的执行状态(比如
重新配置网络接口等等。如果在一个用pivot_root指令转换根目录的执行环境中,
就可以做这些事情了)。
7)
卸载这个文件系统:
# umount /mnt
8)
这时,初始化RAM盘系统就在“initrd”这个文件中了。可以把它压缩小一点:

# gzip -9 initrd
最后,必须启动内核并载入initrd系统。需要设置下列引导参数:
root=/dev/ram0 init=/linuxrc rw
(只有需要写入initrd文件系统时才需要附加rw参数)。
使用 LOADLIN 当引导器时,可以执行:
LOADLIN C:/LINUX/BZIMAGE initrd=C:/LINUX/INITRD.GZ root=/dev/ram0 i
nit=/linuxrc rw
使用 LILO当引导器时,可以在 /etc/lilo.conf 中如下设置:
image = /boot/bzImage
initrd = /boot/initrd.gz
append = "root=/dev/ram0 init=/linuxrc rw"
如果使用其他引导器,请参考相关文档。
5.3.4 改变根目录设备
在执行完重要任务的尾声,linuxrc一般会执行改变根目录设备的动作,并让所
有程序在真实的根文件系统中展开。这个过程包括下列步骤:
O 挂载新的根文件系统
O 把initrd自己转到这个根文件系统中
O 结束所有旧的对initrd根文件系统的存取动作
O 卸载initrd文件系统并释放RAM盘内存
挂载新的根文件系统很简单:只需要把它挂载到当前根文件系统中的一个目录
下即可。例如:
# mkdir /new-root
# mount -o ro /dev/hda1 /new-root
最终改变根文件系统由pivot_root()系统调用或者pivot_root工具来完成(参
考手册页pivot_root(8))。pivot_root可以把当前根文件系统转移到新根的一个目
录中,然后把指定的目录当作新的根。在调用pivot_root之前,必须先为旧根准备
目录,例如:
# cd /new-root
# mkdir initrd
# pivot_root . initrd
现在,linuxrc仍然可以访问旧的根文件系统。执行下列指令将完全结束与旧根
的联系:
# exec chroot . what-follows <dev/console >dev/console 2>&1
其中what-follows是新根下面的一个程序,比如/sbin/init。(注意,这时如
果没有/dev/console,系统不能启动)。同时,为了保持不同版本之间的兼容性,
需要特别注意下列事项:
O 在调用pivot_root之前,当前目录应该是新的根目录;
O 使用“.”(当前目录)作为pivot_root的第一个参数(新根),为旧根指定目录
的第二个参数也要用相对路径;
O chroot这个命令应该在新、旧根系统当中都能使用;
O 然后调用chroot转移根文件系统;
O 在exec命令中使用象 dev/console 这样的相对路径。
特别提示:让initrd文件系统的目录结构与新根文件系统的结构一致,有利于
转换过程的顺利。
这时,initrd可以卸载,RAM盘也可以释放:
# umount /initrd
# blockdev --flushbufs /dev/ram0
注意:如果linuxrc或者它调用的其他程序的执行因为某种原因中断,则会启用
旧的change_root机制。
5.3.5 使用场合
实现initrd的主要动机是允许系统安装时模块化的内核配置。这个过程大致如
下:
1) 系统可以用一个最小配置的内核从软盘或者其他存储媒体启动,然后载入initr
d系统;
2) /linuxrc来决定需要什么来进一步挂载真实的根文件系统(如设备类型、驱动程
序等)或者支持发行版媒体(如CD-ROM,网络,磁带等);
3) /linuxrc载入必须的内核模块;
4) /linuxrc建立并安装根文件系统;
5) /linuxrc调用pivot_root改变根文件系统,并通过chroot一个程序(继续安装过
程);
6) 安装引导器;
7) 引导器被配置成装入initrd以及相关的模块,建立起系统环境;
8) 现在,系统可以引导,并执行其他的安装任务。
Initrd的关键作用是能够多重配置一个正常操作的系统,而不需要用一个庞大
的内核,或者重新编译、连接内核。在制作Linux发行版(光盘等)、系统恢复盘等
方面有广泛的应用。
5.3.6 淘汰的根转换机制(change_root)
可以通过改写/proc/sys/kernel/real-root-dev这个文件的数字值来改变真实
的根设备。例如:
# echo 0x301 >/proc/sys/kernel/real-root-dev
但是这个机制已经被淘汰,虽然目前的内核仍然支持,不能保证以后的内核会
支持。所以不要使用。

5.4 系统初始化(init)
(参考资料[10])
5.4.1 init的任务
UNIX的init指的不是一个程序、而是一类程序。Init一般是指系统引导时执行
的第一个进程,也是唯一的进程。当内核完成计算机硬件的设置之后,就把控制权
交给init。内核只产生init这一个进程,而系统中其他所有进程都是由init负责产
生(spawn),主要包括各种系统服务进程,比如控制台的登录会话(getty)。主
要任务包括:
O 产生其他进程;
O 重新启动已经退出的进程;
O 负责清理系统中的“僵尸”进程(init是所有其他进程的祖先);
O 处理系统关机(stop所有进程,unmount文件系统);
内核并不关心拿什么来作为系统的init,可以是下列几种选择之一:
O SysVinit (作者:Miquel van Smoorenburg),或者
O simpleinit (作者:Peter Orbaek),或者
O 一个shell脚本,或者
O 嵌入式系统中你的应用程序。
不过路径名字必须是/sbin/init,/etc/init,或/bin/init(因为已经编译到
内核里面了)。如果这几个路径都找不到,系统就完蛋了。为了增加灵活性,内核
提供了命令行选项可以指定init路径:“init=”。
5.4.2 SysVinit
/etc/inittab
/etc/rc.d
大多数Linux发行版使用的init是SysVinit,也就是System V UNIX的实现。其
主要思想是规定了不同的“运行级别(runlevel)”。通过配置文件/etc/inittab
,定义了系统引导时做什么,进入或者切换到一个运行级别时做什么。配置文件每
一行的语法为:
id:runlevel:action:command
细节请参考手册页inittab(5)。
整个过程中用到的脚本都放在/etc/rc.d目录。
5.4.3 两种风格:Slackware vs. Debian
关于配置文件/etc/inittab和脚本/etc/rc.d的实现和组织主要有两种不同的风
格,其有代表性的发行版分别为Slackware和Debian(Redhat同Debian)。这两种风
格之间有几个明显的区别,可以比较容易的识别。
例如在/etc/inittab中,定义进入运行级别0时运行的脚本分别为/etc/rc.d/r
c.0和/etc/init.d/rc 0(在Redhat中/etc/init.d是指向/etc/rc.d/init.d的一个
符号链接,注意这里0是脚本rc的命令行参数)。因此,Slackware风格的/etc/rc.
d中应该是一系列相对独立的脚本,对应于配置文件中每个动作的定义(我没有见过
Slackware哦)。
在我们所熟悉的Redhat中,/etc/rc.d的组织要复杂的多,每个运行级别对应一
个子目录/etc/rc.d/rcX.d(X表示运行级别0~6),下面放的是一系列形如SXXfoo
和KXXbar(S表示Start某个服务,K表示Kill某个服务,XX是两位数字,决定了该脚
本执行的顺序)的符号链接,指向/etc/rc.d/init.d中的脚本,每个脚本对应一项
服务程序。
另外,还有两个重要脚本值得一提:/etc/rc.d/rc.sysinit是系统引导时首先
要执行的(完成系统初始化的各项工作),而/etc/rc.d/rc.local在最后执行(类
似DOS的autoexec.bat)。
读一下/etc/rc.d/rc.sysinit,/etc/rc.d/rc和/etc/rc.d/init.d/中的某个脚
本,就会对Redhat的启动过程和风格有比较清晰的了解。
据说Slackware风格比Debian的速度要快一些。可能是后者的组织结构比较复杂
的缘故吧。

5.5 PAM
(参考资料[11], http://www.kernel.org/pub/linux/libs/pam/,手册页pam
(8))
5.5.1 什么是PAM
PAM(Pluggable Authentication Modules)是为了解决计算机系统中用户认证
的问题而引入的一种实现方案。PAM的目标为:
O 将认证功能从应用中独立出来,单独进行模块化设计、实现和维护(而不是象以
前那样,将认证功能的代码跟应用程序编译在一块);
O 为这些认证模块建立标准API,以便各应用程序能方便的使用它们提供的各种功能

O 认证机制对其上层用户(包括应用程序和最终用户)是透明的。
PAM机制由SUN设计并首先在Solaris 2.3上部分实现,后来逐渐在其他UNIX平台
上实现,包括Linux(其实现称为Linux-PAM)。
5.5.2 PAM的结构
PAM采用分层的体系结构。最下面是模块层,负责实现具体的认证功能,包括帐
户管理(account)、口令鉴别(auth)、口令管理(password)和会话管理(ses
sion)4个模块。
应用接口层位于模块层之上,调用下层提供的服务,并向上(应用程序)隐藏
PAM实现的细节。
5.5.3 配置文件
/etc/pam.conf
/etc/pam.d (如果存在这个目录,则忽略/etc/pam.conf)
配置文件是应用接口层的另一个重要组件。其作用主要是为应用选定具体的鉴
别模块,模块间的组合以及规定模块的行为。
/etc/pam.conf的语法为每行5项(在Linux-PAM的手册页pam(8)中有更详细的描
述):
service type control module-path module-arguments
Service是服务的名字,比如login,su等。注意,/etc/pam.d目录下面有许多
配置文件,分别对应某项系统服务,文件名即等于service,因此每行只有4项。
Type为account,auth,password,session之一,即要使用的认证模块。每个
应用可以使用多个认证模块,或者说可以将模块“堆叠”使用,但是每一行只能定
义一个,因此一项服务可以有多行配置。
Control规定了如何处理模块认证失败或成功,可以是requisite、required、
sufficient或optional。
Module-path是PAM库文件的文件名。缺省路径是/lib/security/。
Module-arguments是可以传给模块的参数。
5.5.4 other
特别需要指出的是,有一个特殊的服务名字——other。如果没有明确指明应用
于某项服务的规则,就用other的定义来处理。因此,我们可以想到,系统中PAM的
最简配置为,只有/etc/pam.d/other这一个配置文件,即可处理所有的认证请求。
下面是我们用过的一个other配置文件的例子:
[xmdong@lips pam.d]$ cat other
#%PAM-1.0
auth required /lib/security/pam_unix.so
account required /lib/security/pam_unix.so
password required /lib/security/pam_unix.so
session required /lib/security/pam_unix.so
当然,这样处理对系统的安全性来说是不利的,最好还是给每项服务定义单独
的配置文件。这不过是一种简化问题的临时方案。
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值