现在硬盘容量大了,价格也便宜了,对于经常折腾FreeBSD的人来说,便有下载全部packages的冲动,因为每次安装,都需要很长的时间,特别是安装桌面,没有几个小时那是不行的,而整个packages库也就40G多一点,对于现在的硬盘来说,就是不到三部高清电影,随便找地方就能放下。
以前的pkg_add -r 的时代,packages是ftp协议,用一个ftp工具就轻松地同步整个packages库,但现在pkg走的是http和pkg协议,ftp那一套不好用了,用http也比较麻烦,还在不停地扫描文件,看是不是最新的。
新的pkg系统其实自带了这个功能,就是fetch子命令,简单看一下man:
# man pkg-fetch
……
NAME
pkg fetch -- fetch remote packages
SYNOPSIS
pkg fetch [-r reponame] [-dqUy] [-Cgix] pkg-name [...]
pkg fetch [-r reponame] [-o destdir] [-dqUy] -a
pkg fetch [-r reponame] [-dqUy] -u
pkg fetch [--repository reponame] [--output destdir]
[--{dependencies,quiet,no-repo-update,yes}]
[--{case-sensitive,glob,case-insensitive,regex}] pkg-name [...]
pkg fetch [--repository reponame]
[--{dependencies,quiet,no-repo-update,yes}] --all
pkg fetch [--repository reponame]
[--{dependencies,quiet,no-repo-update,yes}] --available-updates
DESCRIPTION
pkg fetch is used to download binary packages from a remote repository.
One or more packages, or patterns can be specified.
……
这个fetch子命令就是专门用来下载txz包的,可以单独下载指定的包,以及它的依赖,并可以存放到指定的目录中去,还可以指定下载的源服务器,这对于使用镜像源服务器来说非常方便。
根据man,其实就可以简单地构造出下载整个packages的命令来:
# pkg fetch -yo /root/pkg/ -a
解释一下:
-y: 对于提问,都回答以Y。在下载的过程中,pkg要首先分析pkg数据库,找出需要下载的软件包列表,并给出相应的大小,然后提问是不是要下载,这个时候需要回答y 才能继续。加上这个参数后,就自动认为用户回答了y。
-o: 指定存放txz文件的目录。如果不指定,就默认进入/var/cache/pkg/里面。
-a: 所有软件包。如果下载某一个软件包,可以直接用软件名,并且不需要带版本号。
但是需要如果你真以为上面的命令就能下载整个packages库的话,那你就太天真了:过几分钟后,就会出现一个类似提示,然后就默默地退出:
Fetching BitcoinArmory-0.92.3.txz: 100% 2 MiB 6.5kB/s 04:34
pkg: cached package BitcoinArmory-0.92.3: size mismatch, fetching from remote
具体原因我没有进一步追查,但是看字面意思推测,应该是:网站上的文件大小跟数据库里的文件大小不同,所以pkg就报错后退出,因为网站上的txz文件是随时更新的,镜像站应该机率更大,因为会有新文件还没有更新过来,实际操作中,我试过几个站,报这个错误的机率确实比官方站要大的多。
虽然直觉中应该有个参数忽略这个问题,但是找了一大圈,确实没找到。
pkg系统还有一大好处,就是“断点续传”功能,在BitcoinArmory这个包上出了错,下次仍然从这个地方开始,并且会检查已经存在的文件,如果有更新则会下载新的文件,这点其实非常好,整个packages下载下来之后,如果想更新,用crontab每天跑一下就可以自动更新了,不需要再用其他的手段,非常方便。
根据这个功能,所以可以写一个脚本,在每次pkg异常退出后,再重新启动它,我写了一个非常简单的脚本:
#!/bin/sh
pkg fetch -yo /web/pkg/ -a
while [ $? -ne 0 ]
do
echo ".....try again! \n"
sleep 2
pkg fetch -yo /web/pkg/ -a
done
运行一下,它就会不停地重启pkg进程。
几个说明:
1、pkg-fetch的man上说,可以使用pkg.conf里的环境变量,我测试的几个都不起作用,不知道是bug还是我测试的方式不对,起码这几个不能使用:
FETCH_RETRY = 300
FETCH_TIMEOUT = 3000
WORKERS_COUNT = 1
2、pkg fetch会启动多个进程同时下载,进程数默认等同于hw.ncpu,但是实际测试只开两个进程。