六、Linux企业级YUM软件管理

  1. 云栖社区>
  2. 博客>
  3. 正文

六、Linux企业级YUM软件管理

技术小阿哥 2017-11-27 15:03:00 浏览838
展开阅读全文

一、软件包的安装

程序员首先通过开发工具开发出软件来,最初的称为源码包,就是人能看的明白的。然后编译成机器可以看懂的二进制软件。而rpm就是红帽公司研发的适合自动化安装软件的一套软件管理工具。包含软件的存放位置,库文件、头文件,配置文件、文件间依赖关系等各种关系的管理工作。

1、软件包的组成部分

二级制程序:

                   安装位置:/bin /sbin、/usr/bin、/usr/sbin、/usr/local/bin、/usr/local/sbin。

库文件:也可以是可执行程序,可以是被其他程序调用的。在开发中通常称为函数,公共函数越多(库文件),软件包的适应性越强,包越小。

                   安装位置:/lib、/usr/lib、/usr/local/lib

配置文件:/etc/

帮助文件/手册:/usr/share/doc/

2、软件包管理工具(rpm):

文件清单

文件放置路径

提供的功能说明

依赖关系

3、rpm:package manager 软件包管理器

具有的功能:打包、安装、查询、卸载、升级、校验。

打包:就是将源码编译成可以安装、执行的软件包。

4、编译软件包依赖的环境:

4.1编译器:gcc,g++

提供编译环境,通常需要指明二进制文件的路径及库文件的路径

4.2库:/etc/ld.so.conf、/etc/ld.so.conf.d/*.conf

4.3手册路径:/etc/man.config。man -M

4.4头文件:协调各个文件。默认:/usr/include。

编译过程需要收集编译所需要的库文件,如果库文件不健全,编译不会成功。

5、程序安装的种类:

1、通用二级制格式(类似绿色软件,解压后直接使用)

2、软件包管理器rpm

3、源代码编译

知识点:java实现跨平台的根本就是由于java有一个虚拟机jvm,但是这个jvm是有系统平台要求的,它的上面java程序都可以运行,这样就解决了跨平台问题。

6、RPM包的命名规范

源程序命名:major.minor.release.tar.gz(bz2/xz)

主版本号.次版本号.修改次数.适用平台.适用CPU类型.tar.压缩格式

rpm包命名:name-version-release.arch.rpm

发行号:用于标示rpm编译的发行号。                

                   el6:redhat 6以上

                   el5:redhat 5

                   suse11:suse11版以上

arch:主机平台

           i686:p2以上cpu,32位

           x86-64:64位

           amd64:debian 64位

           ppc 

           noarch:无平台限制

rpm分包:将一个大的软件包依据功能分成多个软件包,所以安装过程中需要先安装主包,依据情况安装支包。(bind和bind_devel)


7、rpm软件包验证

rpm包验证机制:可以验证来源的合法性、软件包的完整性。

系统安装完毕后会在/etc/pki/rpm-gpg/目录下将官方的公钥放在这里。要验证从网络上下载的rpm包是否真实可靠,需要先通过命令导入公钥,然后进行验证。

查找公钥

locate GPG-KEY

1、导入公钥

rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6 

2、验证软件包合法性

[root@localhost ~]# rpm -K zsh-4.3.10-7.el6.i686.rpm 
zsh-4.3.10-7.el6.i686.rpm: rsa sha1 (md5) pgp md5 OK

二、RPM命令

1、参数:

-K:检测rpm包完整性合法性。默认

--nodigest:不检查完整性

--no signature:不检查合法性

--install、-i:安装

-v:显示详细信息。

-h:显示进度条

--nodeps:忽略依赖关系,安装不一定可用。

--test:测试安装

--prefix  :指定新的安装路径


2、卸载

--replacepkgs:重新安装软件包

-e:卸载软件包 --nodeps可用不卸载依赖包

卸载和重新安装过程中,如果之前对软件的配置文件进行过更改,linux是会将修改的文件在原路径上另存一份并重新命名的,以保障用户配置文件的完整。

[root@localhost]~# rpm -e zsh

warning: /etc/zlogin saved as /etc/zlogin.rpmsave

3、查询

-q、--query:查询包信息是否安装。

-qi:查看软件包详细信息

-qa:查询所有已安装的rpm软件汇总(qi顺序不能颠倒)

-qd:查询rpm包的帮助文档安装路径

-ql:查询指定软件包包含的文件(list)

-qc:只显示rpm包的配置文件

-qf:查询指定文件所属软件

-qR:查询软件的依赖关系

4、查询rpm包的相关脚本:

rpm -q --scripts

perinstall:安装前脚本

postinstall:安装后脚本

preuninstall:卸载前脚本

postunstaill:卸载后脚本

5、查询未安装的包的相关信息:

rpm -qp(i、l、d、c) rpm包名

6、升级

-U:没安装就安装,有安装则更新

-F:只更新,不安装。

-Uvh或者-Fvh

注意:内核不应该升级,而是选择安装,本身内核允许多版本的存在。

7、校验和数字证书

-V:校验安装的软件包配置文件等信息是否被修改过。

-Va:列出系统所有安装的软件被改动的文件

-Vp:后面加文件,显示所属软件可能被改动的文件

-Vf:列出摸个文件是否被改动过


[root@client ~]# rpm -Va 
S.5....T.  c /etc/login.defs
.......T.  c /etc/inittab
.......T.  c /etc/rc.d/rc.local
文件类型
c(config):表示配置文件
d(document):文档
l(license):授权文件
r(readme):readme文件
属性:
S(size):文件的容量大小是否被更改
M(modediffers):文件类型、属性是否更改
5:md5已经不同
D(device):设备的主次号码改变
L(link):link路径更改
U(user):文件所有者更改
G(group):文件属组更改
T(time):文件创建时间更改

三、RPM数据库

rpm软件之间的依赖关系是通过数据库保存的,每次yum安装软件时会先从yum仓库中同步数据库信息,并保存在/var/lib/rpm/目录下,关系rpm软件的正常使用。

如果出现损坏,需要重建:

--initdb:初始化数据库。不会覆盖原有数据库

--rebuilddb:重建rpm数据库。

四、YUM命令

1、查询

list:用来显示相关程序包 (all、installed、available)

yum list all bind* :显示所有仓库中和以安装的bind*包

repolist:显示可用的仓库(all、enable、disabled)

info:查看包的安装情况及详细信息。

grouplist:可用及以安装的软件组

groupinfo “group-name”:显示包组内容及信息

清理缓存(清理的是已经安装的软件及包组的相关信息,从服务器上下载的安装包)

clean:清理缓存(packages、metadata)

makecache:手动建立缓存

2、安装

install:安装

groupinstall:安装软件包组

reintall:重新安装

info:显示指定软件包的详细信息

list:列出yum仓库所管理的所有软件(包括未安装的)

update:软件包升级,不指定软件包升级全部。

update-to:升级到指定版本。

check-update:检查可以升级的软件包最新版本

(upgrade、upgrade-to废弃了)

3、卸载

remove:默认会将被卸载包所依赖的包一同卸载,需要注意。

清理下载文件:

缓存位置:/var/cache/yum

清理参数:clean

        packages:删除已下载的软件包

        headers:删除软件文件头,类似索引列表

        metadata:删除yum仓库信息。

4、文件的所属软件包

provides:查询指定文件是由那个软件包生成的。

search:模糊匹配查询命令,查找包含不完整文件名的所有文件。

5、安装软件包组

安装开发环境依赖的软件包组:

Development Tools

Server Platform Development

Desktop Platform Development

软件包组的安装、更新

groupinstall、groupupdate、groupremove

五、YUM仓库的创建


createrepo:创建程序仓库。

yum仓库通常都是在互联网上由大公司提供的,我们只需要在本地创建配置文件,并将yum源指向哪里就可以了。当然也可以创建自己本地的yum仓库。通常数据库文件默认存放位置为/var/lib目录下。

1、yum源配置文件

/etc/yum.repos.d/*.repo

[base]

name=CentOS-$releasever - Base

mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os

#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/ ##yum源

gpgcheck=1

gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

cost=100


[gongbing]

name= centos 6

baseurl=file:///media/cdrom/

enable=1

gpgcheck=0

cost=200 cost用来定义yum源的优先级,通常本地优先级高于其他

实例:创建epel第三方仓库,建议第三方仓库多了会造成冲突。

[epel]

name=epel

mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=epel-$releasever&arch=$basearch

enabled=1

gpcheck=0

#wget http://ftp.riken.jp/Linux/fedora/epel/RPM-GPG-KEY-EPEL-6           # 下载 epel repo 的公钥

灵活应用yum源(适用于centos官网yum源)baseurl:baseurl=http://mirror.centos.org/centos/$releasever/centosplus/$basearch/

$releasever:显示当前发行版本,比如5、6、7,而在网站中6指向最新的6.7目录。

$basearch:显示系统平台版本,x86,686,x86_64。

练习编写163的linux-yum源

baseurl=http://mirrors.163.com/centos/$releasever/os/$basearch/


2、本地安装

yum命令同样支持安装磁盘上的rpm包,相对rpm命令的优势就是可以依据此rpm包的依赖关系从互联网的yum仓库中下载依赖包并安装。

linux5以前的yum如果安装本地的yum源,可以使用参数:localinstall、localupdate。而在6以后的linux统一使用install来完成。

历史:

history:查看历史操作。

--nogpgcheck:不检查软件包完整性和可靠性。

3、创建自己的yum仓库

创建非常简单,各种参数都可以不用。

3.1、安装创建YUM仓库所需要的命令-createrepo

[root@37-test grub]# yum install createrepo

3.2、制作yum仓库,需要创建并指定目录

[root@37-test pkg]# createrepo /root/lnmp-setup-bin/pkg/

Spawning worker 0 with 1 pkgs

Workers Finished

Gathering worker results


Saving Primary metadata

Saving file lists metadata

Saving other metadata

Generating sqlite DBs

Sqlite DBs complete


3.3、创建仓库完成后,自动在目录中生成repodata目录。

[root@37-test pkg]# ls

dtedu.tar.gz                       repodata        setup.tar.gz

puppetlabs-release-6-7.noarch.rpm  scripts.tar.gz

[root@37-test pkg]# 


3.4、在文件夹里生成repodata文件夹,里面包括

filelists.sqlite.gz(rpm包的文件列表,引擎为sqlite)

filelists.xml.gz(rpm包的文件列表,引擎为xml)

primary.sql.gzprimary.xml.gz(包之间的依赖关系)

other.xml.gz(rpm包其他信息,比如新增、改进功能)

other.sqlite.bz2rpm(包其他信息,比如新增、改进功能)

repomd.xml文件(纪录数据库的时间戳,用于客户机和服务器间同步)

[root@37-test repodata]# ls

53d2a531435469b1468bcb0f4a9a92b91383c47d2c2532a0c659294fa5ae386c-other.sqlite.bz2

817d1464cbb2750d478cb792fc94b20b2bacbd842a031e7e31425f6e64d8996f-filelists.sqlite.bz2

8e54eef08b1deb052bb3b51ac28a5eb63492594a2789855ac1923315757de807-primary.xml.gz

96c0b7b52aff973e1a816d2e24af178dd775b68f71943a09c71827283716464c-primary.sqlite.bz2

ae3f2e69e30ddf499c40bce4183d2770b366adad39f629d047de0d2366a642b8-filelists.xml.gz

f0053afeca4af6335a88a07891be2547c9d6583f127435d77d4027d39eb8b43d-other.xml.gz

repomd.xml


3.5、客户端配置本地yum仓库

[localrepo]

name=pkg

baseurl=file:///root/lnmp-setup-bin/pkg/

enable=1

gpgcheck=0


[root@37-test repodata]# yum repolist

已加载插件:fastestmirror, refresh-packagekit

Loading mirror speeds from cached hostfile

 * base: mirror.bit.edu.cn

 * epel: mirrors.tuna.tsinghua.edu.cn

 * extras: mirror.bit.edu.cn

 * updates: mirror.bit.edu.cn

localrepo                                                | 2.9 kB     00:00 ... 

localrepo/primary_db                                     | 1.9 kB     00:00 ... 

仓库标识               仓库名称                                           状态

base                   CentOS-6 - Base                                     6,696

epel                   Extra Packages for Enterprise Linux 6 - x86_64     12,150

extras                 CentOS-6 - Extras                                      62

localrepo              pkg                                                     1

ntop                   ntop packages                                           6

ntop-noarch            ntop packages                                           9

puppetlabs-deps        Puppet Labs Dependencies El 6 - x86_64                 77

puppetlabs-products    Puppet Labs Products El 6 - x86_64                    565

saltstack-zeromq4      Copr repo for zeromq4 owned by saltstack                8

updates                CentOS-6 - Updates                                    686

repolist: 20,260


3.6、yum客户端会在本地生成一个yum仓库数据库:

[root@37-test repodata]# ll /var/lib/yum/repos/x86_64/6/

总用量 40

drwxr-xr-x. 2 root root 4096 8月  26 2012 base

drwxr-xr-x  2 root root 4096 10月 14 10:42 epel

drwxr-xr-x. 2 root root 4096 8月  26 2012 extras

drwxr-xr-x  2 root root 4096 12月  8 09:16 gongbing

drwxr-xr-x  2 root root 4096 11月 21 14:40 ntop

drwxr-xr-x  2 root root 4096 11月 21 14:40 ntop-noarch

drwxr-xr-x. 2 root root 4096 8月  26 2012 puppetlabs-deps

drwxr-xr-x. 2 root root 4096 8月  26 2012 puppetlabs-products

drwxr-xr-x  2 root root 4096 11月 22 11:30 saltstack-zeromq4

drwxr-xr-x. 2 root root 4096 8月  26 2012 updates

补充:LFTP

get:文件下载

mget:多文件下载

mirror:下载目录及文件

!command:使用linux命令

六、编译源代码:

编译源代码首先需要编译环境才能编译源代码,然后对于编译工具使用了make命令,这条命令依据makefile来进行编译,那makefile又是如何而来的呢?它通过configure脚本和makefile.in来生成makefile文件。


1、依赖环境,需要开发包组

安装开发环境依赖的软件包组:

Development Tools

Server Platform Development

Desktop Platform Development

[root@37-test ~]# yum groupinfo "development tools"

已加载插件:fastestmirror, refresh-packagekit

设置组进程

Loading mirror speeds from cached hostfile

 * base: mirrors.tuna.tsinghua.edu.cn

 * epel: mirrors.tuna.tsinghua.edu.cn

 * extras: mirror.bit.edu.cn

 * updates: mirror.bit.edu.cn


组:开发工具

 描述:基本开发环境。

 必要的软件包:

   autoconf

   automake

   binutils

   bison

   flex

   gcc

   gcc-c++

   gettext

   libtool

   make

   patch

   pkgconfig

   redhat-rpm-config

   rpm-build

 默认的软件包:

   byacc

   cscope

   ctags

   cvs

   diffstat

   doxygen

   elfutils

   gcc-gfortran

   git

   indent

   intltool

   patchutils

   rcs

   subversion

   swig

   systemtap

 可选的软件包:

   ElectricFence

   PyYAML

   ant

   babel

   bzr

   ccache

   chrpath

   clips

   clips-devel

   clips-doc

   clips-emacs

   clips-xclips

   clipsmm-devel

   clipsmm-doc

   cmake

   cmucl

   colordiff

   compat-gcc-34

   compat-gcc-34-c++

   compat-gcc-34-g77

   cvs-inetd

   cvsps

   darcs

   dejagnu

   email2trac

   expect

   ftnchek

   gcc-gnat

   gcc-java

   gcc-objc

   gcc-objc++

   ghc

   git

   haskell-platform

   imake

   jpackage-utils

   kdewebdev

   ksc

   libstdc++-docs

   lua

   mercurial

   mock

   mod_dav_svn

   nasm

   nqc

   nqc-doc

   ocaml

   perltidy

   python-docs

   python-requests

   python-six

   qgit

   rpmdevtools

   rpmlint

   sbcl

   systemtap-sdt-devel

   systemtap-server

   trac

   trac-git-plugin

   trac-mercurial-plugin

   trac-webadmin

   translate-toolkit


2、编译安装源码包

2.1解压缩源码包

[root@37-test ~]# tar zxvf ntopng-2.4-stable.tar.gz -C /root/test/ 


-C:用于指定解压缩到那个目录里。


2.2进入源代码目录

2.2.1、配置源代码的.configure,作用是检测编译环境,此文件一般在软件包中存在,如果没有可以通过autoconf来生成。

  自定义编译变量:

  --help:获取帮助信息
  --prefix=指定安装路径
  --sysconfdir=指定配置文件路径 

./configure设置完后,会自动生成config.log和makefile文件。

[root@37-test ntopng-2.4-stable]# ls

autogen.sh      configure       doc       Makefile.in  scripts

autom4te.cache  configure.ac    docker    nDPI         src

CHANGELOG.md    configure.seed  httpdocs  ntopng.8     third-party

config.guess    contrib         include   packages     tmp

config.log      COPYING         LICENSE   README.md    tools



2.2.2、.configure结合makefile.in来生成makfile,makefile.in通过automake来生成。

2.2.3、编译源代码

make
make install

3、完善编译安装

编译安装和rpm安装的最大区别就是,rpm安装是有数据库的,安装完后系统知道可执行程序、库文件、帮助文档、配置文件都放在那里,可以自行寻找。而编译安装则不提供此功能,需要手动制定。

3.1定义path的全局环境变量

[root@37-test ~]# PATH=/usr/local/nagios/bin/:$PATH ##通过命令定义的变量是临时的。

修改/etc/profile或者创建/etc/profile.d/nagios.sh文件。

[root@37-test ~]# vi /etc/profile.d/nagios.sh

export PATH=/usr/local/nagios/bin/:$PATH

立即生效:

[root@37-test ~]# . /etc/profile.d/nagios.sh 


3.2添加编译软件所依赖的库文件,此库文件通常在编译软件包的安装目录中的lib目录下,可以通过/etc/ld.so.conf来设置,或者建议使用/etc/ld.so.conf.d/目录下创建*.conf文件。

[root@37-test ~]# vi /etc/ld.so.conf.d/nagios.conf

/usr/local/nagios/lib/ ##添加路径即可



3.3配置文件通常不用手动添加,编译的软件可以自己找到。

3.4帮助文件的添加,需要通过/etc/man.config文件进行配置,在MANPATH=处添加。

# Every automatically generated MANPATH includes these fields

#

MANPATH /usr/man

MANPATH /usr/share/man

MANPATH /usr/local/man

MANPATH /usr/local/share/man

MANPATH /usr/X11R6/man

MANPATH /usr/local/nagios/share/ 添加路径

#

# Uncomment if you want to include one of these by default

#

# MANPATH       /opt/*/man

# MANPATH       /usr/lib/*/man

# MANPATH       /usr/share/*/man


3.5添加头文件,使用ln -s 创建软连接到系统头文件目录/etc/include/中。

[root@37-test ~]# ln -sv /usr/local/nagios/include/ /usr/include/nagios

"/usr/include/nagios" -> "/usr/local/nagios/include/"

[root@mail ~]# ln -sv /usr/local/courier-authlib/include/* /usr/include/

"/usr/include/courier_auth_config.h" -> "/usr/local/courier-authlib/include/courier_auth_config.h"

"/usr/include/courierauthdebug.h" -> "/usr/local/courier-authlib/include/courierauthdebug.h"

"/usr/include/courierauth.h" -> "/usr/local/courier-authlib/include/courierauth.h"

"/usr/include/courierauthsaslclient.h" -> "/usr/local/courier-authlib/include/courierauthsaslclient.h"

"/usr/include/courierauthsasl.h" -> "/usr/local/courier-authlib/include/courierauthsasl.h"

"/usr/include/courierauthstaticlist.h" -> "/usr/local/courier-authlib/include/courierauthstaticlist.h"


知识点:

查看命令所依赖的库文件有哪些?ldd

[root@37-test ~]# ldd /bin/ls

linux-vdso.so.1 =>  (0x00007fff787b1000)

libselinux.so.1 => /lib64/libselinux.so.1 (0x00007fa143af6000)

librt.so.1 => /lib64/librt.so.1 (0x00007fa1438ee000)

libcap.so.2 => /lib/libcap.so.2 (0x00007fa1436e9000)

libacl.so.1 => /lib64/libacl.so.1 (0x00007fa1434e1000)

libc.so.6 => /lib64/libc.so.6 (0x00007fa14314d000)

libdl.so.2 => /lib64/libdl.so.2 (0x00007fa142f48000)

/lib64/ld-linux-x86-64.so.2 (0x00007fa143d27000)

libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fa142d2b000)

libattr.so.1 => /lib64/libattr.so.1 (0x00007fa142b26000)


查看运行命令的执行路径是什么?hash

[root@37-test ~]# hash

hits command

   1 /usr/bin/ldd

   1 /usr/local/nagios/bin/nrpe

   1 /bin/vi

   2 /usr/bin/man


ldconfig -v 

重新搜索系统中的所有库文件,并生成/etc/ld.so.cache。

[root@37-test ~]# ldconfig -v

ldconfig: /etc/ld.so.conf.d/kernel-2.6.32-642.11.1.el6.x86_64.conf:6: duplicate hwcap 1 nosegneg

ldconfig: 无法对 /usr/lib64/mysql 进行 stat 操作: 没有那个文件或目录

ldconfig: 多次给出路径“/usr/local/lib”

ldconfig: 多次给出路径“/usr/local/lib”

ldconfig: 多次给出路径“/usr/lib”

ldconfig: 多次给出路径“/usr/lib64”

/opt/glibc/lib:

libnss_nisplus.so.2 -> libnss_nisplus-2.14.so

ld-linux-x86-64.so.2 -> ld-2.14.so


七、编译源码格式的rpm包-SRPM


打包(rpm源代码包制作成rpm包,一般格式为:filename.src.rpm)

包制作过程是根据.spec文件来完成的。

源软件包经过编译后存放在/usr/src/目录下,并且一般在正确编译后会仅仅留下SRPMS里面的经过编译的软件包。

1、解压安装src.rpm包,有些安装需要创建指定的用户名。

[root@37-test ~]# rpm -ivh mingetty-1.00-3.src.rpm 

warning: mingetty-1.00-3.src.rpm: Header V3 DSA/SHA1 Signature, key ID db42a60e: NOKEY

   1:mingetty               ########################################### [100%]


2、进入解压目录,一般为用户家目录的rpmbuild中。

[root@37-test ~]# cd rpmbuild/S

SOURCES/ SPECS/   

[root@37-test SOURCES]# ll

总用量 20

-rw-rw-r--. 1 root root   259 3月   4 2002 mingetty-1.00-opt.patch

-rw-rw-r--. 1 root root 14038 3月   4 2002 mingetty-1.00.tar.gz


3、编译源码rpm包

[root@37-test SPECS]# rpmbuild -bb mingetty.spec 


-ba:生成二进制包及源码格式的rpm包

-bb:生成一个二进制格式的rpm包


可能会需要依赖包,将依赖包安装完毕后,重新编译。


[root@37-test rpmbuild]# ll

总用量 24

drwxr-xr-x 3 root root 4096 12月  9 14:11 BUILD

drwxr-xr-x 2 root root 4096 12月  9 14:11 BUILDROOT

drwxr-xr-x 3 root root 4096 12月  9 14:11 RPMS

drwxr-xr-x 2 root root 4096 12月  9 14:04 SOURCES

drwxr-xr-x 2 root root 4096 12月  9 14:11 SPECS

drwxr-xr-x 2 root root 4096 12月  9 14:07 SRPMS ##用于其他系统的重新制作编译

[root@37-test rpmbuild]# cd RPMS/

[root@37-test RPMS]# ls

x86_64

[root@37-test RPMS]# cd x86_64/

[root@37-test x86_64]# ls

mingetty-1.00-3.x86_64.rpm  mingetty-debuginfo-1.00-3.x86_64.rpm

[root@37-test x86_64]# rpm -ivh mingetty-debuginfo-1.00-3.x86_64.rpm 

Preparing...                ########################################### [100%]

   1:mingetty-debuginfo     ########################################### [100%]


问题:

1、error: line 4: Unknown tag: Copyright: GPL

此错误可以通过修改repc文件中的需要將"Copyright:"該改成新的Tag"License:" 即可




本文转自 blackstome 51CTO博客,原文链接:http://blog.51cto.com/137783/1916977,如需转载请自行联系原作者

网友评论

登录后评论
0/500
评论
技术小阿哥
+ 关注