2008年7月30日星期三

GSL

GSL(GNU Scientific Library)是一个 C 写成的用于科学计算的库,下面是一些相关的包
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Cfg-files/Unpacked/Failed-cfg/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad)
||/ Name Version Description
+++-====================================-==========================-============================================
un gsl (no description available)
ii gsl-bin 1.11-2 GNU Scientific Library (GSL) -- binary packa
ii gsl-doc-pdf 1.11-2 GNU Scientific Library (GSL) Reference Manua
un gsl-ref-html (no description available)
un gsl-ref-pdf (no description available)
pn gsl-ref-psdoc (no description available)
un libgsl0 (no description available)
ii libgsl0ldbl 1.11-2 GNU Scientific Library (GSL) -- library pack
其中,libgsl0ldbl 是真正的库:
/usr/lib/libgsl.so.0.12.0
/usr/lib/libgslcblas.so.0.0.0
/usr/share/doc/libgsl0ldbl/changelog.Debian.gz
/usr/share/doc/libgsl0ldbl/changelog.gz
/usr/share/doc/libgsl0ldbl/THANKS.gz
/usr/share/doc/libgsl0ldbl/BUGS.gz
/usr/share/doc/libgsl0ldbl/README
/usr/share/doc/libgsl0ldbl/AUTHORS
/usr/share/doc/libgsl0ldbl/SUPPORT
/usr/share/doc/libgsl0ldbl/TODO.gz
/usr/share/doc/libgsl0ldbl/copyright
/usr/share/doc/libgsl0ldbl/NEWS.gz
/usr/share/lintian/overrides/libgsl0ldbl
/usr/lib/libgsl.so.0
/usr/lib/libgslcblas.so.0
另外还有一个相关的 gsl-bin,里面主要两个程序,
/usr/share/man/man1/gsl-histogram.1.gz
/usr/share/man/man1/gsl-randist.1.gz
/usr/share/doc
/usr/share/doc/gsl-bin
/usr/share/doc/gsl-bin/changelog.Debian.gz
/usr/share/doc/gsl-bin/changelog.gz
/usr/share/doc/gsl-bin/copyright
/usr/bin
/usr/bin/gsl-randist
/usr/bin/gsl-histogram
gsl-randist 和 gsl-histogram 分别是产生随机样本和计算直方图的程序。

我们这里根据 gsl-doc-pdf 给出如何使用 GSL 的程序接口和例程。GSL 的程序使用的头文件一般放在 /usr/include/gsl/ 目录(libgsl0-dev),C 程序通常用 #include 让预处理程序 cpp 读入对应的函数、宏声明,连接的时候通过 -lgsl -lgslcblas 到对应的库,通常还可能连接到 -lm。为了使用某些 inline 函数,可以打开 HAVE_INLINE 宏。注意由于 long double 和使用平台相关,一般不推荐使用。

GSL 里面的命名规则大致是使用 gsl 作为前缀(没有 namespace,sigh),函数的话一般是 gsl_foo_fn(对应 double)其余的为 gsl_foo_type_fn,对于类型一般是 gsl_foo 或者 gsl_foo_type(没有 template,sigh again)。对应的头文件一般是 gsl_foo.h(含有所有的类型)或者 gsl_foo_type.h。

GSL 里面出错处理遵循 POSIX 线程库,正常返回 0,出错返回非零,并依照 gsl_errno.h 里面设置出错值。可以用 gsl_strerror 将返回值用字符串表达出来。默认情况下 GSL 提供的 error handler 就是打印出错问题并调用 abort,这是一个 gsl_error_handler_t 类型的函数,可以通过 gsl_set_error_handler() 函数设定。

Mathematical Functions 常用数学函数 gsl_math.h
包括常用的数学常数(M_*),GSL_POSINF、GSL_NEGINF、GSL_NAN 以及相应判断的函数 gsl_isnan()、gsl_isinf() 和 gsl_finite()。另外提供了一些函数值快速计算的方法,gsl_log1p() 计算 log( 1 + x),gsl_exp1m() 计算 ex-1,gsl_hypot() 和 gsl_hypot3 计算欧氏空间范数,gsl_acosh()、
gsl_asinh()、gsl_atanh() 是反双曲函数,gsl_ldexp(x, y) 计算 x . 2y,gsl_frexp() 计算在二进制下科学记数法下 x 的基数部分。求幂次 gsl_pow_int 或者 gsl_pow_n(n = 2, ..., 9)。测试符号 GSL_SIGN,奇偶性 GSL_IS_EVEN 和 GSL_IS_ODD。取大小 GSL_MAX、GSL_MIN。浮点数大小最好用 gsl_fcmp 函数。

Complex Numbers 复数 gsl_complex.h、gsl_complex_math.h
定义一个复数可以用 gsl_complex_rect 或者 gsl_complex_polar,另外获得实部、虚部 GSL_REAL 和 GSL_IMAG,设定 GSL_SET_COMPLEX,GSL_SET_REAL 和 GSL_SET_IMAG。可以求辐角 gsl_complex_arg()、模长 gsl_complex_abs()、模长平方 gsl_complex_abs2、模长对数 gsl_complex_logabs()。复数的加减乘除就是 gsl_complex_op() 其中 op 可以为 add、sub、mul 和 div,另外和实数有类似的运算 gsl_complex_op_real(),和虚数有 gsl_complex_op_imag(),共轭 gsl_complex_conjugate()、逆 gsl_complex_inverse() 和相反数 gsl_complex_negative。另外如求平方根 gsl_complex_sqrt(对实数求加 _real),幂次 gsl_complex_pow(次数为实数加 _real),指数 gsl_complex_exp,对数 gsl_complex_log(loh10 或者 log_b)。另外还有三角函数、反三角函数、双曲函数、反双曲函数。

Polynomial 多项式 gsl_poly.h
一般可以给定多项式的系数,用一个数组从低阶到高阶,调用 Horner 法求多项式函数值可以用 gsl_poly_eval(),对复数而言是 gsl_poly_complex_eval(),对复系数多项式为 gsl_complex_poly_complex_eval()。另外一种表达方式是使用 Newton 差分法表达,这时输入的是差分节点创建一个多项式,gsl_poly_dd_init(),求函数值可用 gsl_poly_dd_eval(),还可以把这种类型的多项式转换成为 Taylor 展开的形式 gsl_poly_dd_taylor()。对二次多项式求解根可以用 gsl_poly_solve_quadratic(),复根可以用 gsl_poly_complex_solve_quadratic()。对三次方程用 cubic 替换 quadratic。对高于 4 次的多项式没有解析解,往往用矩阵特征值进行近似,GSL 提供了一种解法,首先用 gsl_poly_complex_workspace_alloc() 分配储存根的空间,然后调用 gsl_poly_complex_solve() 求解,求解之后应该用 gsl_poly_complex_workspace_free() 释放。

Special Functions 特殊函数 gsl_sf.h、gsl_sf_*.h
一般有两种调用形式,一种和正常函数类似直接 gsl_sf_function(),另一种是 gsl_sf_function_e() 将返回值的地址传入函数。gsl_sf_result.h 提供了一个用于估计误差的结构体,一般函数有三个 mode 控制计算精度 GSL_PREC_DOUBLE、GSL_PREC_SINGLE 和 GSL_PREC_APPROX。提供的特殊函数有 airy(见 gsl_sf_airy.h)的函数值、零点、导数、导数零点,Bessel 函数(见 gsl_sf_bessel.h)的函数值、零点,Clausen 函数(见 gsl_sf_clausen.h),Coulomb 函数(见 gsl_sf_coulomb.h),Coupling 系数(见 gsl_sf_coupling.h),Dawson 函数(见 gsl_sf_dawson.h),Debye 函数(见 gsl_sf_debye.h),Dilogorithm 函数(见 gsl_sf_dilog.h),乘法误差函数(见 gsl_sf_elementary.h),椭圆积分(见 gsl_sf_ellint.h),Jacobi 椭圆函数(见 gsl_sf_elljac.h),误差函数(见 gsl_sf_erf.h,GNU libc 也有类似的函数),指数函数(见 gsl_sf_exp.h),指数积分(见 gsl_sf_expint.h),Fermi-Dirac 函数(见 gsl_sf_fermi_dirac.h),Gamma 和 Beta 函数(见 gsl_sf_gamma.h),Gegenbauer 函数(见 gsl_sf_gengenbauer.h),超几何函数(见 gsl_sf_hyperg.h),Laguerre 函数(见 gsl_sf_laguerre.h),Lambert W 函数(见 gsl_sf_lambert.h),Legendre 函数和球面调和函数(见 gsl_sf_legendre.h),对数及其相关函数(见 gsl_sf_log.h),Mathieu 函数(见 gsl_sf_mathieu.h),幂函数(见 gsl_sf_pow_int.h),Psi(digamma) 函数(见 gsl_sf_psi.h),Synchrotron 函数(见 gsl_sf_synchrotron.h),transport 函数(见 gsl_sf_transport.h),三角双曲函数(见 gsl_sf_trig.h),Zeta 函数(见 gsl_sf_zeta.h)。

Vectors and Matrices 向量与矩阵 gsl_block.h、gsl_vector.h、gsl_matrix.h
创建 vector 也好、matrix 也好,都依赖 gsl_block 这个结构,可以用 gsl_block_alloc() 和 gsl_block_calloc() 分配,gsl_block_free() 释放,另外有对流的输入输出,如 gsl_block_fread()、gsl_block_fwrite()、gsl_block_fprintf() 和 gsl_block_fscanf()。不管是 vector 还是 matrix 都含有一个 gsl_block 的指针,操作和 block 类似。如 vector 的的类似操作就是 gsl_vector_alloc()、
gsl_vector_calloc()、gsl_vector_fread()、gsl_vector_fwrite()、gsl_vector_fprintf() 和 gsl_vector_fscanf(),另外可以通过 gsl_vector_get() 和 gsl_vector_set() 获得/设定某一分量的值,gsl_vector_ptr() 和 gsl_vector_const_ptr() 获得一分量的地址,另外有一些函数方便初始 vector,如 gsl_vector_set_all()、gsl_vector_set_zero() 和 gsl_vector_set_basis()。为了访问一个 vector 元素的子集,可以使用 vector view 对象,这可以用一些函数产生(有对应的 const 版本),并最好仅仅在 stack 内使用(也就是直接操作对象本身,而不是指针),如 gsl_vector_subvector() 产生一个连续的子集,gsl_vector_subvector_with_stride() 产生一个带固定间隔的子集,gsl_vector_complex_real() 和 gsl_vector_complex_imag() 产生一个 real 或者 image 部分的 view,gsl_vector_view_array() 对一个数组产生 vector view,gsl_vector_view_array_with_stride() 产生带有固定间隔的 vector view。vector 之间的复制或者互换有 gsl_vector_memcpy() 和 gsl_vector_swap()。vector 元素之间互换 gsl_vector_swap_elements(),逆序 gsl_vector_reverse()。vector 之间的四则运算 gsl_vector_op(),数乘(op = scale),加上常数(op=add_constant)。vector 最大最小(op=max、min、minmax)或者对应的 index(op = max_index、min_index、minmax_index)。判断一个 vector 是否为 0 向量(op=isnull),正(ispos),负(isneg),非负(isnonneg)。matrix 和 vector 稍微不同之处在于用两个下标索引,前面函数多数只要把 vector 换成 matrix 即可。另外还可以为 matrix 的行或者列建立 view,gsl_matrix_(sub)row/column(),或者对角元素 gsl_matrix_(sub, super)diagonal()。将矩阵一行/列读到/写到一个 vector 可以用 gsl_matrix_get/set_row/col()。矩阵行列互换 gsl_matrix_swap_rows/columns() 或者方阵的行列交换 gsl_matrix_swap_rowcol(),转置或转置复制 gsl_matrix_transpose()、gsl_matrix_transpose_memcpy()。矩阵运算中 mul_elements 和 div_elements 是对元素的。

Permutations 置换 gsl_permutation.h
这是产生置换的基本数据结构,一般用 gsl_permutation_(c)alloc() 分配内存,gsl_permutation_init() 初始化为置换幺元,可以用 gsl_permutation_memcpy() 进行复制,gsl_permutation_free() 释放。访问置换元素可以用 gsl_permutation_get(),互换用 gsl_permutation_swap()。另外可以用 gsl_permutation_size() 获得置换大小,gsl_permutation_data() 获得指向置换的指针,gsl_permutation_valid() 验证是否为合法的 permutation。另外有一些置换的操作,如 gsl_permutation_reverse() 逆转,gsl_permutation_inverse() 求逆,依照字典序计算下一个/前一个有 gsl_permutation_next/prev()。将 permutation 应用到数组上可以用 gsl_permute,或者逆 psl_permute_inverse(),对 vector 可以 gsl_permute_vector(_inverse)(),几个置换可以相乘 gsl_permutation_mul()。类似的 permutation 也有输入输出函数。另外置换存在一种正则表达方式可以用 gsl_permutation_linear_to_canonical() 转换,可以计算一个 permutation 含有几个 cycle 等。

Combinations 组合 gsl_combination.h
和置换类似的结构,但是处理的是组合问题。

Sorting 排序 gsl_heapsort.h、gsl_sort_*.h
首先提供了一个 quick sort 的补充的 heapsort,gsl_heapsort() 和 gsl_heapsort_index()。排序数组 or vector 可以用 gsl_sort() 或者 gsl_sort_vector(),另外也有带索引的版本。求最小/大的 k 个元素,可以用 gsl_sort(_vector)_smallest/largest(_index)()。

BLAS Support 基本线性代数子程序支持 gsl_blas.h、gsl_cblas.h
BLAS 支持三个 level 的运算,level 1 是 vector 的,level 2 是 matrix-vector 的,level 3 是 matrix-matrix 的操作。操作对象的类型为 SDCZ 对应 float、double、float complex 和 double complex,矩阵的特性为 GE(一般)、GB(一般带状矩阵)、SY(对称)、SB(对称带状)、SP(对称,packed)、HE、HB、HP(Hermite)、TR、TB、TP(三角阵)。操作类型有 DOT(内积)、AXPY(a x + y)、MV(矩阵 x 向量)、SV(矩阵逆乘向量)、MM(矩阵相乘)、SM(矩阵的逆乘另外一个矩阵)。GSL 提供的命令形式为 gsl_blas_*。

Linear Algebra 线性代数 gsl_linalg.h
这部分包括了最常用的数值线性代数运算,如矩阵 LU 分解求解线性方程组(带 permutation,可以 inplace 等版本),QR 分解(包括选取列的),SVD,Cholesky 分解,实对称矩阵的对角化分解(本征分解),Hermite 矩阵的对角化分解,实矩阵的 Hessenberg 分解,实矩阵对的 Hessenberg 分解,双对角化(bidiagonalization),Householder 变换,Householder 变换求解线性方程组,三对角阵,balancing(通过相似变换使得行列的范数相当)。

Eigensystems 求解特征值 gsl_eigen.h
这部分包括实对称矩阵的特征值、Hermite 矩阵的特征值,以及非对称矩阵的特征值(利用 Schur 分解)以及对应的广义特征值问题求解的函数。一般需要 alloc 一个 workspace,然后调用对应的函数计算特征值、特征向量,最后 free 掉 workspace。另外还提供了对应的函数用于同时整理特征值与特征向量。

Fast Fourier Transform 快速 Fourier 变换 gsl_fft_*.h
快速 Fourier 变换这里分成了对复数、实数(更困难一些,需要保证逆变换获得是实数,使用的也是 halfcomplex 表达系数)两种处理。而对于数据为 2 的幂次的可以直接用 Cooley-Tuckey 算法,不是的话另外有一套算法(需要预先分配 workspace)。每套算法提供 forward(计算 Fourier 变换),inverse(逆变换),backward(不带规范化常数的逆变换)和 transform(通过参数选择 forward 还是 backward)。

Numerical Integration 数值积分 gsl_integration.h
函数命名方式是 gsl_integration_*(),Q 表示 quadrature routine,N 和 A(表示是否自适应),G 和 W(一般积分和带权值函数的积分),S 和 P(容易消解的奇点或者提供特别困难的点),I(无穷积分),O(振荡积分),F(Fourier 积分),C(Cauchy 主值)。积分里面设置停止条件是设置相对误差或者绝对误差。

Random Number Generation 随机数生成器 gsl_rsg.h
首先需要 gsl_rng_alloc() 一个对应的类型,然后 gsl_rng_set() 设置 seed,gsl_rng_free() 释放。同时还可以通过环境变量 GSL_RNG_TYPE 和 GSL_RNG_SEED 以及函数 gsl_rng_env_setup() 获取,然后通过设定对应的生成器就可以利用 gsl_rng_uniform() 产生 [0, 1) 的均匀分布,gsl_rng_uniform_pos() 产生 (0, 1) 的均匀分布,以及 gsl_rng_uniform_int() 产生指定范围内的均匀整数分布。另外可以通过 gsl_rng_name() 获得该生成器的名称,gsl_rng_get() 返回一个在 gsl_rng_min() 和
gsl_rng_max() 之间的随机数。如果需要更细致的处理生成器,还提供了一些函数用于处理它的状态 IO。另有一章详细介绍各种分布下随机数的生成情况。

Quasi Random Sequences 拟随机序列 gsl_qrng.h
与前一章不同的是不需要初始 seed,调用结构和前一章类似。

Random Number Distribution 随机数分布 gsl_randist.h
这里包含了绝大多数常用分布,命名规则如下 gsl_ran_dist(_),这里 dist 是分布名称,如 gaussian 等,后如果没有 _ 表示产生随机数,如果 _pdf 是密度,分布函数用了两种形式,一般是 cdf_dist_P 和 cdf_dist_Q 以及对应的逆 Pinv 和 Qinv。一共有下面几种分布,gaussian、gaussian_tail、bivariate_gaussian、exponential、laplace、exppow、cauchy、rayleigh、rayleigh_tail、landau、levy、levy_skew、gamma、flat、lognormal、chisq、fdist、tdist、beta、logistic、pareto、dir_2d、weibull、gumbel1、gumbel2、dirichlet。对于离散分布,有限个取值可以用 gsl_ran_discrete_preproc() 将分布密度列(或者差一个 scale factor)转换成为一个 gsl_ran_discrete_t 类型的结构,并传递给 gsl_ran_discrete() 产生随机数,gsl_ran_discrete_pdf() 产生分布列,产生的结构可以用 gsl_ran_discrete_free() 释放。另外提供了 poisson、bernoulli、binomial、multinomial、negative_binomial、pascal、geometric、hypergeometric、logarithmic。除了分布函数,还可以把指定序列随机打乱 gsl_ran_shuffle()、随机选元素 gsl_ran_choose()、选择一个子集 gsl_ran_sample()。

Statistics 统计 gsl_stats.h
主要提供统计函数,如求均值 gsl_stats_mean(),子样方差(无偏) gsl_stats_variance()、子样方差(已知期望,有偏) gsl_stats_variance_m(),标准差两个版本 std 和 std_m,与期望平方和 tss 和 tss_m,另外两个是 variance_with_fixed_mean 和 sd_with_fixed_mean。绝对偏差 absdev 和 absdev_m,skew 用 skew、skew_m_sd,峰度 kurtosis 和 kurtosis_m_sd,自相关性 lag1_autocorrelation 和 lag1_autocorrelation_m,协方差 covariance 和 covariance_m,相关系数 correlation,另外有对应的带权值版本在前面加上 w 即可。另外也提供了最大最小以及对应 index 的函数,计算中位数以及分位数的函数。

Histograms 直方图 gsl_hostogram*.h
分一维和两维,差异不大,主要把一维的增加新的一个变量,命名在 histogram 后面加 2d 即可。大致使用的方法是,首先 gsl_histogram_alloc() 分配空间,然后 gsl_histogram_set_ranges 设置节点(或者用 gsl_histogram_set_ranges_uniform() 设置均匀的节点),最后 gsl_histogram_free()。另外还提供了复制 gsl_histogram_memcpy() 以及自身复制 gsl_histogram_clone() 的函数。可以通过 gsl_histogram_increment() 增加元素到计数,也可以 gsl_histogram_accumulate() 增加任意权值(计数器用的实数),可以获得某个 bin 的权值 gsl_histogram_get(),或者某个 bin 上下界 gsl_histogram_get_range(),整个 histogram 的上下界 gsl_histogram_min/max(),bin 的数目 gsl_histogram_bins(),而 gsl_histogram_reset() 将整个 histogram 清零。gsl_histogram_find() 返回某个值所在的 bin。另有 max/min_val/bin 返回最大值或者出现的 bin,还有利用这个 histogram 计算 mean、sigma(标准差)、sum。另外两个 histogram 可以用 gsl_histogram_equal_bins_p() 看看是否可以使用 add/sub/mul/div 等运算,shift 可以让所有值 + 常数,scale 是乘。还有一些 IO 的函数。可以用 gsl_histogram 来创建一个 gsl_histogram_pdf,这个就和前面讲的随机数一样用。

N-tuples N 元组 gsl_ntuple.h
非常简单的数据结构,用于把数据写入/读出文件,提供的基本操作有 gsl_ntuple_create() 创建一个空文件(截断已存在),gsl_ntuple_open() 打开已存在文件,或者 gsl_ntuple_write() 将 ntuple 写入文件,或者从文件中读入 ntuple 数据 gsl_ntuple_read(),最后需要 gsl_ntuple_close() 关闭。可以把一个 ntuple 数据读入喂给 histogram 进行统计,这主要使用 gsl_ntuple_project() 函数。

Monte Carlo Integration 蒙特卡罗积分 gsl_monte_*.h
实现的是最基本的三种积分方法,在 gsl_monte.h 里面声明了积分函数的基本形式 gsl_monte_function,在 gsl_monte_plain.h 提供的是最简单均匀采样积分方法,首先 gsl_monte_plain_alloc() 分配 workspace,gsl_monte_plain_init() 初始化,然后 gsl_monte_plain_integrate() 积分,最后 gsl_monte_plain_free() 释放 workspace。在 gsl_monte_miser.h 里面使用的分层蒙特卡罗积分,可以用 gsl_monte_miser_state 结构控制算法细节。而 gsl_monte_vegas.h 是使用 impartance sampling,gsl_monte_vegas_state 控制算法细节。复杂的 MCMC 等这里并没有实现。

Simulated Annealing 模拟退火 gsl_siman.h
只有一个函数 gsl_siman_solve(),提供优化函数等信息即可使用。

Ordinary Differential Equations 常微分方程 gsl_odeiv.h
主要使用 gsl_odeiv_system 结构,需要提供方程标准形式的函数和偏导(即 Jacobi 矩阵)。另外和算法相关的是 stepping function,如 Runge-Kutta 方法等,也有自适应版本的,这种函数的目的是为了计算指定一个 step 下函数值。GSL 还提供了计算一个区间内函数变化(若干 step)的函数(evolve)。但是由于对常微分方程数值解不很了解,这里就略去吧。

Interpolation 插值 gsl_spline.h、gsl_interp.h
提供了三次样条和 Akima 样条。比较 low-level 的函数为用户提供了非常细致的控制,通过 gsl_interp_alloc() 分配需要的空间,选择适当的算法,gsl_interp_init() 初始化节点,最后 gsl_interp_free() 释放。为了搜索某个位置(以便计算函数值)可以用 gsl_interp_bsearch(),也可以使用 gsl_interp_accel 对象(先 init,然后 find 和 free)。另外提供了最常用的函数值、一阶导、二阶导和积分以及对应使用 gsl_interp_accel 的接口。high-level 的函数主要在 gsl_spline.h 里面提供。和 gsl_interp_* 系列相似。

Numerical Difference 差分 gsl_deriv.h
提供了中心差分 gsl_derive_central()、前向 gsl_deriv_forward()、后向 gsl_deriv_backward()。

Chebyshev Approximation 车比雪夫逼近 gsl_chebyshev.h
提供了 [-1, 1] 上一组正交多项式,这对应的是 1/sqrt(1-x^2) 为权的函数空间。首先用 gsl_cheb_alloc() 分配空间产生 gsl_cheb_series 结构,然后 gsl_cheb_init(),最后 gsl_cheb_free()。提供了计算函数值、函数值误差,导函数和积分。

Series Acceleration 级数加速 gsl_sum.h
提供了一个 Levin u-transform 的东西,没听说过。其意义在于减少求和项,提高计算精度。使用方式就是通过 gsl_sum_levin_u_alloc() 分配 workspace,继而通过 gsl_sum_levin_u_accel() 分配,最后 gsl_sum_levin_free()。如果不需要估计误差,则可以更快。

Wavelet Transform 小波变换 gsl_wavelet*.h
与 FFT 类似,但是没有 backward 类型,分一维和二维,有 daubechies、haar 和 bspline。

Discrete Hankel Transform 离散汉克尔变换 gsl_dht.h
与 FFT 类似,但是是对极坐标的,调用方式和 FFT 类似。

One-dimensional Root Finding 一维函数求零点 gsl_roots.h
有两种方式(基于搜索 gsl_root_fsolver 和基于导数 gsl_root_fdfsolver)。首先选取合适的 solver,命名方式都是 gsl_root_*solver_type,然后 alloc。之后可以用 gsl_root_*solver_set() 设定初始态,开始迭代使用 gsl_root_*solver_iterate(),也可以直接用 gsl_root_*solver_root() 求出根。另可以 gsl_root_fsolver_x_upper() 和 gsl_root_fsolver_x_lower() 返回控制根的区间。通过 gsl_root_test_*() 可以测试相对误差、残差。提供的算法有 bisection、falsepos 和 brent,利用梯度的有 newton、secant、steffenson。

One-dimensional Minimization 一维函数求极小 gsl_min.h
最小化在某种意义上就是求导函数的零点。因此调用方法和前一章极为类似。算法有 goldensection 和 brent。

Multi-dimensional Root Finding 多维函数求零点 gsl_multiroots.h
类似。算法有 hybridsj,hybridj,newton,gnewton。不用梯度的算法有 hybrids,hybrid,dnewton,broyden。

Multi-dimensional Minimization 多维函数求极小 gsl_multimin.h
类似。算法有 conjugate_fr、conjugate_pr、bfgs、bfgs2、steepest_descent、nmsimplex。

Least Square Fitting 最小二乘拟合 gsl_fit.h
分单变量和多变量。gsl_fit_linear() 和 gsl_fit_wlinear() 分别是线性和加权线性问题的单变量拟合(即线型回归),另外 gsl_fit_linear_est() 还估计误差。多元情形为 gsl_fit_mul()、gsl_fit_wmul() 与 gsl_fit_mul_linear()。对广义的 LSF 问题,需要使用 gsl_multifit_linear_alloc() 分配 workspace,最后释放,类似的函数有 gsl_multifit_linear 和 weighted 版本,另有 _svd 版本,使用 SVD 计算结果。

Nonlinear Least Square Fitting 非线性最小二乘拟合 gsl_multifit_nlin.h
与多维函数最小化类似。

Basic Splines 基础样条 gsl_bspline.h
先 gsl_bspline_alloc() 产生 workspace,然后 gsl_bspline_knots() 或者 gsl_bspline_knots_uniform() 设置节点,gsl_bspline_eval() 计算函数值,最后 gsl_bspline_free() 释放空间。

Physical Constants 物理常数 gsl_const_mksa.h
各种可能用到的物理常数,命名一般为 GSL_CONST_MKSA_*。

IEEE Floating Point Arithmetic 浮点算术 gsl_ieee_utils.h
提供了输出 float 和 double 的 gsl_ieee_printf_*,另外可以用 gsl_ieee_env_setup() 设置对应的计算环境。

相关程序:
  • GSL 的 C++ wrapper:GSLwrap
  • 一个用 GSL 写的 PCA 程序,和 mex 一起工作。

2008年7月29日星期二

bc

bc 是命令行下一个任意精度的计算器语言(可不是那个 bc 哦),包含有以下内容:
/usr/bin/bc
/usr/share/doc/bc/README
/usr/share/doc/bc/AUTHORS
/usr/share/doc/bc/copyright
/usr/share/doc/bc/examples/ckbook.b
/usr/share/doc/bc/examples/pi.b
/usr/share/doc/bc/examples/primes.b
/usr/share/doc/bc/examples/twins.b
/usr/share/doc/bc/changelog.gz
/usr/share/doc/bc/NEWS.gz
/usr/share/doc/bc/changelog.Debian.gz
/usr/share/menu/bc
/usr/share/man/man1
/usr/share/man/man1/bc.1.gz
结构非常的简单。既然说是一种语言,那么就对应有它的语法。bc 本身提供了一个交互式界面(-i 或者默认的情况),另外也允许把一些命令写入文件执行(作为命令参数)。Debian 带的 bc 是扩展之后的版本,如果希望使用 POSIX 标准下的 bc 可以用 -s,另外可以用 -l 读入数学库调用里面的函数。

bc 里面的数字有两个属性,一个是 length(表达该数字使用的位数),一个是 scale(该数字使用小数个数)。变量名命名规则和 C 语言类似,有几个重要的变量控制着 bc 的行为,比如 scale 表示输出的时候显示的小数点位数,ibase 和 obase 指定输入输出的进制(默认都是 10 进制),last 记录了上次计算结果。注释使用 /* 和 */ 对或者单行注释 #。使用的运算符和 C 类似,如四则运算、赋值、自增自减、逻辑运算等,另外控制结构比如 if、while、for、流程控制命令 break、continue、return 等也完全一致。

bc 提供了几个常用的表达,如 length()、scale() 求对应的长度、小数点后位数,read() 读入用户输入的数据,sqrt() 求平方根。print 和 printf 类似。halt 表示退出 bc。limits 显示系统的一些限制,quit 是退出 bc。另外 bc 允许自定义函数,格式是 define function-name( parameter list ) {},在函数体里面有 auto 定义的局部变量。函数可以为 void 类型,此时不返回值。

使用数学库,有正弦 s()、余弦 c()、反正切 a()、自然对数 l()、指数函数 e() 和 n 阶 Bessel 函数 j( n, x) 可以用。

2008年7月28日星期一

lftp

lftp 作为 Linux 下最常用的 ftp client 之一,一直是我见到的最好的命令行工具之一,比起 GUI 来说它有自己的很多优点。这是该包内东西:
/usr/bin/lftp
/usr/bin/lftpget
/usr/share/man/man1/lftp.1.gz
/usr/share/man/man1/lftpget.1.gz
/usr/share/lftp/import-ncftp
/usr/share/lftp/import-netscape
/usr/share/lftp/verify-file
/usr/share/lftp/convert-netscape-cookies
/usr/share/doc/lftp/BUGS
/usr/share/doc/lftp/FAQ
/usr/share/doc/lftp/README.debug-levels
/usr/share/doc/lftp/README.modules
/usr/share/doc/lftp/TODO
/usr/share/doc/lftp/copyright
/usr/share/doc/lftp/NEWS.gz
/usr/share/doc/lftp/README.gz
/usr/share/doc/lftp/changelog.Debian.gz
/usr/share/doc/lftp/changelog.gz
/etc/lftp.conf
我们看到有两个工具 lftp 和 lftpget,后者本身是一个 shell script 用来调用 lftp 下载。因此我们主要介绍 lftp 的用法。lftp 一般作为一个交互式程序来运行。它自己会屏蔽 SIGHANGUP 这类信号,如果在还有下载任务时退出或者出现意外断线什么的,这可以保证该进程不会退出。lftp 也不仅仅支持 ftp 协议,它还可以从 ftps、http、https、hftp、fish、sftp 和 file 这些协议下载文件。lftp 提供的交互环境和 shell 类似,下面介绍一些常用的命令:
  • !shell command 执行一个 shell 里面的命令
  • anon 使用匿名用户。
  • at time -- command 在指定时间执行命令,比如下载等等。
  • bookmark add name loc 增加一个地址到书签,bookmark del name 删掉一个书签,bookmark edit 编辑书签文件,bookmark list 列出书签,bookmark import 用于导入书签。
  • cache 用于管理 lftp 的缓存,如 cache stat 列出统计信息,cache on/off 打开关闭 cache,cache flush 将 cache 写入硬盘,cache size 设置 cache 大小,cache expire 设置移除 cache 时间。
  • cat 将远程文件内容输出到 stdout。
  • cd 切换远程路径,lcd 切换本地路径
  • chmod 改变远程文件属性。
  • close 关闭连接。
  • ls 和 cls 都是列出文件信息,但是前者是依照服务器反馈,后者会依照自己的格式。另外 nlist 仅仅列出文件名,不列其他的信息。
  • command 忽略 alias 执行命令。
  • debug 改变 debug level 并输出到指定文件。
  • echo,man page 里面居然写 guess what it does。
  • eval 一般都是用来执行某个命令,可以提供指定格式(-f)
  • exit,可加 bg 表示退出后强制在后台下载,top 是把登录 shell 也退出了,kill 是杀死未完成任务。
  • fg 就是 wait 的 alias,表示在前台等候前一个命令终止。
  • find 和 ls -R 类似,但是如果服务器不支持 ls -R 可以用 find。
  • get 和 put 是 ftp 里面的基本命令,用于下载或者上传单一一个文件。
  • glob 将一个 pattern 转换后传给一个命令,基本用法是 glob command pattern
  • jobs 列出现在执行的任务。
  • kill 杀死指定任务,或者 kill all 杀死所有的。
  • pwd 和 lpwd 显示远程和本地的当前工作目录。
  • mirror 用于同步远程和本地的文件/目录,可以从远程同步到本地,也可以从本地同步到远程(-R),可以用 -i 指定下载的文件或者 -x 排除某些文件。
  • module 加载模块。
  • mkdir 创建目录。
  • more 类似 cat 根据 PAGER 设定分页。
  • mput 和 mget 使用 wildcard 上传或者下载文件。
  • mrm 实际上是 glob rm 的 alias。
  • mv 重命名
  • open 连接某个站点。
  • pget 使用几个连接下载文件。
  • quote 直接发送协议里面的命令,如 http 请求等
  • reget 和 get -c 一样,reput 和 put -c 一样;rels、renlist 重新生成 cache。
  • rm 删除文件。rmdir 删除目录。
  • repeat 可以用于反复执行某个命令。
  • set 设置变量。
  • scache 列出 cached 的 session 或者切换 session。
  • sleep 指定时间并退出。
  • site 执行 site_cmd。
  • source 执行一个文件里面的命令。
  • user 设定登录用户和密码。
  • version 获取版本号。
  • zcat 和 zmore 是调用 zcat 和 zmore 显示压缩文件内容。

下面看看 lftp 的配置,一般系统配置文件放在 /etc/lftp.conf,用户自己的放在 ~/.lftprc 或者 ~/.lftp/rc。一般里面用 alias 指定一些常用的命令,set 设定某些变量值,debug 打开调试状态等。set -a 会显示所有的设置,这里仅仅写一些常用的变量,其他的请参考 man page:
  • bmk:save-passwords (boolean) 是否保存站点的登录密码。
  • cmd:move-background (boolean) 默认状态下退出是否进入后台。
  • cache:size (number) 设置 cache 大小。
  • dns:order (list of protocol names) 设置查询 DNS 顺序,默认是先 inet6 后 inet。
  • file:charset (string) 存盘文件名编码方式。
  • ftp:anon-pass 匿名用户的密码
  • ftp:passive-mode (boolean) 所谓 passive mode 就是客户端打开端口反向连接 server 传输。
  • ftp:port-range (from-to) 设置打开 PASV 模式使用的端口范围。
  • http:proxy 设置 http 的代理。
  • net:limit-rate (bytes per second) 限制下载速度。
  • net:reconnect-interval-max (seconds) 重连时间。
  • pget:default-n (number) 使用 pget 分割的块数。

tasksel

看起来很简单的工具,里面的内容:
/usr/bin/tasksel
/usr/lib/tasksel/tasksel-debconf
/usr/lib/tasksel/packages/list
/usr/lib/tasksel/tests/debconf
/usr/lib/tasksel/tests/new-install
/usr/lib/tasksel/tests/lang
/usr/share/doc/tasksel/README.gz
/usr/share/doc/tasksel/TODO
/usr/share/doc/tasksel/copyright
/usr/share/doc/tasksel/changelog.gz
/usr/share/man/man8/tasksel.8.gz
/usr/share/menu/tasksel
只要 tasksel --list-tasks 就可以看到一些设定好的 task,好像就是装 Debian 的几个基本的 task,不知道可以自定义些复杂的 task 不?如果需要某项可以 tasksel install/remove 安装或者卸载。

2008年7月18日星期五

manpages

一直不知道 manpages 里面是啥,发现基本全是文档,这里从里面比较有意思的地方节选一些出来。这是 manpages 的主页

sync
将文件同步到磁盘。比如 U 盘拔掉之前,sync 一下 umount 就结束了,否则 umount 会调用 sync。

tzselect
选择 time zone,根据用户输入信息输出一个可以设置为 TZ 变量的值。

intro (man 1)
介绍 user commands 和工具,如文件管理、shells、编译器、浏览器、文件图片浏览器、编辑器等。多数程序成功返回 0,失败返回非 0(一般是正数)。
intro (man 2)
介绍 system call,不过多数 system call 都用 C 或者其他的 lib wrapper 调用。多数成功返回 0,不成功返回负值。
intro (man 3)
库函数手册,比如 libc、libm 等。
intro (man 4)
介绍特殊文件,主要是 /dev/ 里面的。
intro (man 5)
介绍文件格式和协议,乃至一些 C 的结构。
intro (man 6)
介绍游戏,系统里面一些搞笑的小程序。
intro (man 7)
介绍习惯、字符集、标准文件系统布局。
intro (man 8)
多仅被超级用户使用的命令,管理命令,硬件相关的命令等。

uri, url, urn
介绍 Uniform Resource Identifier(包括 URLocation 和 URName)。基本格式就是 scheme://path 这种了。常见的有 http、ftp、gopher、mailto、news、telnet、file、man、info、whatis、ldap、wais 等。甚至还有 eMule 等的 scheme。

iso_(-)8859-(_)1...iso_8859-16, latin1-2
是讲述 iso 8859-9 编码。

ipv6, PF_INET6
讲述对应 socket 编程在 C 的结构体。

mq_overview
讲述如何使用 POSIX 消息队列,这是和 SVID 不同的一个,通过她可以让进程之间互相通信,几个重要函数是 mq_open 打开一个队列获得 message queue discriptor,通过 mq_send 和 mq_receive 收发信息,最后 mq_close 关闭该队列(另外还有一系列函数)。通信双方通过 /name 确定队列。连接时 -rt。

mailaddr
关于电子邮件地址的说明。

x25, PF_X25
关于 X.25 协议的 socket 结构。

feature_test_macros, ftm
为写出某些特点的程序写的测试 macros,见 /usr/include/features.h,比如要求是标准 ANSI C 的环境,可以用宏 __STRICT_ANSI__ 来测试,另外可以测试是否满足 SVID 等扩展版本,这在 GNU libc 里面有一些例子,因为 libc 允许根据这些宏判定某些函数是否被是用,通过这些测试可以避免不适当的引入某些函数。

regex, re_format
讲述的 POSIX.2 的正则表达式的基础语法。

spufs
是 PowerPC 上的文件系统的挂载命令。

undocumented
未收入 man page 的说明。

raw, SOCK_RAW
见前

LDP
关于 The Linux Documentation Project 的介绍,有官网 http://tldp.org

bootparam
如何设定 kernel 在 boot 时候的参数:一个 option 一共只能给 10 个参数,格式为 name=val1,val2...,如果 name 是一些已知的名字如 init、root 等会调用对应的 *_setup() 进行配置,否则当作环境变量进行处理。下面是一些常用的名字:init 指定启动后执行的第一个进程位置,一般来说会尝试 /sbin/init、/etc/init、/bin/init 和 /bin/sh,如果全部失败了就会导致 kernel panic;nfsaddrs 指定 NFS 的地址,用于网络启动;nfsroot 指定挂载 NFS 分区为网络启动的 root;no387 关闭对 math coprocessor 的支持;no-hlt 关闭对 HALT 指令的支持;root 指定挂载为 / 的设备;ro/rw 让 / 为只读或者可读可写;reserve=iobase,extent[,iobase,extent] 保留某些 I/O 端口不做 probe;mem 设定内存大小;panic=N 表示发生 kernel panic 后 N 秒重启;reboot=[warm|cold][,[bios|hard]] 设定 reboot 方式;nosmp 取消 SMP,maxcpus=N 设定最多使用的 CPU 个数;debug 打开调试信息;profile=N 打开 kernel profile 功能;swap=N1,N2,N3,N4,N5,N6,N7,N8 设定 swap 相关参数;buff=N1,N2,N3,N4,N5,N6 设定 buff 信息;load_ramdisk=N 设置是否使用 ramdisk;prompt_ramdisk 是否从软盘读入 ramdisk;ramdisk_size=N 设定 ramdisk 大小(单位 Kb);ramdisk_start=N 设定 ramdisk 的起始位置(在软盘上存在 kernel 和 ramdisk 的时候使用);noinitrd 不使用 initrd。另外还可以设定一些 SCSI 设备的参数。

missing
丢失的文档。

boot
讲述 boot 的过程。首先是机器上电,BIOS 自检,从 CMOS(其实叫 NVRAM 更好)读取配置,然后从 boot device 读入 os loader,将控制权交给 os loader。PC 上面一般放在 MBR 里面,由于 MBR 仅有 512 字节,且还含有 64 字节的分区表信息,所以 os loader 往往将自身的一部分放在 MBR 然后引导另一部分,同时根据引导 kernel 的参数将控制权交给 kernel。如果有 initrd 则会将其转换成为 ramdisk 并挂载成为临时的 /,然后执行 /linuxrc,最后挂载了 / 之后就可以执行 init 进程了。init 根据 /etc/inittab 决定运行级别,一些服务放在 /etc/rc?.d/ 里面,其实是到 /etc/init.d/ 里面脚本的连接。

tcp
讲述 tcp 的 C 接口。

netlink, PF_NETLINK, rtnetlink, NETLINK_ROUTE
讲述 PF_NETLINK 编程。

posixoptions
介绍了 POSIX 标准下的函数接口,一般可以用宏在编译时检测,也可以用 sysconf()、pathconf()、fpathconf() 和 confstr() 来检测。

netdevice
设定 interface 的 C 接口。

futek
关于快速用户空间互斥锁。

man(7)
其实是说如何写 man page,通过 groff 输出成为 ASCII 或者 PS。

packet, PF_PACKET
如何产生一个 PF_PACKET 的 C 接口。

mdoc
man page 的另外一种格式,也是通过 groff 转换的。

arp
介绍 arp 命令管理本地 MAC-IP 转换的表,如 arp -n 列出现在的 ARP 表,-d 删除,-s 添加表项。

ip(7)
介绍 IP 的 C 接口。

signal
介绍常用的信号以及 POSIX 信号。

socket
介绍 socket 的 C 接口。

glob
介绍 bash 通过 wildcard 匹配的规则。这个不是 RE,比较简单。

charsets
介绍最常用的字符集、编码方式等。

ascii
介绍 ascii 编码。

standards
介绍 Unix/Linux 里面各种 C 编程的标准。

hier
介绍 Linux 目录树。

koi8-r
是俄文常用编码。

locale(7)
介绍的是 locale 的 C 接口。

pthreads
介绍的是 POSIX threads 的 C 接口。

pty, pts, ptmx, tty(4), tty_ctl
介绍 pseudo-terminal 两种类型(Unix 98 和 BSD,前者使用较多)以及使用方式。pts 讲述 Unix 98 的 master 和 slave 关系,如何通过 C 接口实现。tty 是讲述 /dev/tty 设备。tty_ctl 是 tty 的 ioctl。

epoll
对 edge-triggered 或者 level-triggered 的 IO 事件响应的一种实现,和 poll 类似。

capabilities
这是对原有线程访问模型的一个增补(原来只要 UID 为 0 就无敌了),在 2.6.14 以后的内核中出现的,以后内核对这部分进行检查、并提供了对应的系统调用更改这些,问题是现在还没有获得文件系统的支持。

fifo
介绍 FIFO(这里是 named pipe) 的使用。

symlink
讲述符号连接操作的习惯相关的 C 函数。

complex
讲述 GNU libc 里面 complex.h。


time(7)
讲述各种可用的时钟。

icmp, IPPROTO_ICMP
讲述 ICMP 协议。

termio
是驱动 terminal 的一些东西,已经 obsolete,被 termios 代替。

suffixes
常见“扩展名”

hostname(7)
讲 hostname 解析。

path_resolution
讲述 Linux 如何解析一个路径名称。

operator
C 语言使用 operator 列表及优先级。

unicode
讲述 unicode。

sem_overview
讲述 POSIX semaphore(用于同步)。

ddp
Linux 下 AppleTalk 协议的 C 实现。

unix, PF_LOCAL, AF_LOCAL, PF_UNIX
讲述 unix socket(PF_UNIX)。

man-pages
写 man page 的惯例。

units
介绍计算机上常用的关于大小的前缀,如 kb mb gb 等等。

environ
讲述 C 程序传递 argc、argv 之外的 environ。

credentials
讲述用户、进程的标识。

inotify
讲述监督文件、目录等文件系统事件的 C 接口程序。

utf-8, utf8
讲述 utf-8 编码。

udp
讲述 udp 协议的 C 接口。

shm_overview
讲述 POSIX shared memory(共享内存)。

svipc
讲述的是 SVID 下 IPC 实现机理。

pipe
讲述的是 pipe 和 FIFO 的使用。

mem, kmem, port
介绍 /dev/mem、/dev/kmem 和 /dev/port,mem 一般是物理内存,而 kmem 是内核虚拟内存,port 用于访问物理端口。

random, urandom
介绍 /dev/random 和 /dev/urandom,它们维护一个 entropy pool,根据这个产生随机序列,前者在 entropy 足够高时返回,否则 block,而后者立即返回,因此需要比较高质量的随机序列时应多用 /dev/random。一般用 dd 从这些设备获得需要的随机数。

console_ioctl
设定 console 的 ioctl 参数。

ttyS, ttys
讲述 /dev/ttyS 设备(串口)。

hd(4)
讲述 /dev/hda 到 /dev/hdd 这四个 IDE 硬盘设备。

mouse(4)
讲述 ps/2 鼠标各个 pin 的作用,相关的协议。

st
讲述 SCSI 磁带的 C 语言接口。

full
讲述 /dev/full 设备,如果写可以触发 disk full,读只能读出 \0。

dsp56k
是 Motorola dsp56k 设备的 ioctl。

lp(4)
是 line printer device 的 ioctl。

sk98lin
是讲述 Marvell 和 SysKonnect G 以太网网络适配器的模块。

sd
讲述 SCSI 设备的 ioctl。

initrd
是 /dev/initrd 设备,对应的是 boot loader 加载的 initrd 的 ram disk。

wavelan
是 NCR、AT&T、Lucent WaveLAN ISA 和 Digital (DEC) RoamAbout DS 无线网卡适配器的模块说明。

ram
是 /dev/ram 设备。

rtc
是 real-time clock 的 C 接口和 ioctl。

null, zero
讲述 /dev/null 和 /dev/zero 设备。

console_codes
介绍 Linux console 里面的控制字符等。

vcs 和 vcsa
是虚拟 console 内存,对应 /dev/vcs*。

hosts.equiv
介绍 /etc/hosts.equiv 文件,这是控制 r* 系列命令的登录权限的文件。

mailname
介绍 /etc/mailname 文件,写的是系统对外可见的邮件名。

motd
介绍 /etc/motd,就是登录后显示每日的消息。

tzfile
介绍 tzfile.h 里面关于时区的信息。

securetty
介绍 /etc/securetty,也就是系统认为是安全的 tty,这可以限制 root 通过不安全的途径登录。

rpc
介绍 /etc/rpc,也就是 remote procedure call(远程过程调用),里面记录了 rpc 号以及对应的服务。

elf
是介绍 ELF 文件格式的 C 接口(elf.h)。

shells
介绍 /etc/shells 文件,里面是所有合法的 shells,包括路径等,这使得 chsh 能安全的工作。

host.conf
配置如何解析主机名,即 resolver library。

proc
介绍 proc 文件系统。

resolv.conf, resolver
配置 DNS 的文件,但是现在多用动态方式生成。

group
组信息,介绍 /etc/group 文件。

acct
介绍 sys/acct.h 的用法,用于进程 accounting(内核会在进程结束后写该进程的一些相关信息到某文件)。

locale(5)
解释 locale 是怎么用的(不是解释这个命令)。

nsswitch.conf
用来查询用户帐号信息,如选择 /etc/passwd、nis 或者别的什么。

services
讲述文件 /etc/services,这在 C 程序里面可以用一些对应的命令获得查询。

slabinfo
讲述 /proc/slabinfo,这个文件是 kernel 管理的 slab 的统计信息(常用的一些如 buffer heads、inode 等)。

charmap
charmap 就是用于定义哪些字符属于某个 charset 的文件。

hosts
讲述/ etc/hosts 文件。

utmp, utmpx, wtmp
记录用户登录信息的文件,也就是 /var/run/utmp 的用法。

nologin
介绍 /etc/nologin 拒绝用户登录的文件。

core
介绍 core dump 信息怎么用于调试。

filesystems, fs
介绍常用的 file systems。

termcap
介绍 /etc/termcap,描述了每个 term 的特性。

dir_colors
通常 ls 命令依据 LS_COLOR 设定颜色,这通过 dircolors 命令设定。用户可以根据自己的爱好定义。

issue
讲述 /etc/issue,即在出现提示符前出现的文件。

networks
讲述 /etc/networks,即网络名和对应地址的映射。

protocols
讲述 /etc/protocols 文件,即一些协议对应的网络端口以及别名。

motd.tail
在 debian 里面这是 bootmiscs.sh 生成 motd 的源程序,应该修改它获得永久的效果。

ld-linux, ld-linux-so
这是 Linux 的动态库连接程序,一方面会把需要的 so 文件载入内存,另一方面修改进程相关内容完成动态连接。

相关程序:
sync 来自 coreutils,在 man 1 里面也有。
tzselect 来自 libc6,在 man 1 里面也有。

2008年7月17日星期四

e2fsprogs

这是关于 EXT2/3 文件系统的程序集合,
/etc/mke2fs.conf
/sbin
/sbin/resize2fs
/sbin/fsck.ext2
/sbin/mkfs.ext2
/sbin/e2fsck
/sbin/findfs
/sbin/fsck.ext4dev
/sbin/blkid
/sbin/logsave
/sbin/fsck.ext3
/sbin/mke2fs
/sbin/e2image
/sbin/tune2fs
/sbin/e2undo
/sbin/mkfs.ext4dev
/sbin/e2label
/sbin/mkfs.ext3
/sbin/mkfs.ext4
/sbin/dumpe2fs
/sbin/fsck
/sbin/fsck.ext4
/sbin/debugfs
/sbin/badblocks
/usr/bin/lsattr
/usr/bin/chattr
/usr/share/e2fsprogs
/usr/share/e2fsprogs/initrd.ext3-add-journal
/usr/sbin
/usr/sbin/filefrag
/usr/sbin/mklost+found
/usr/lib
/usr/lib/e2initrd_helper
略去其中其他的帮助文档。以下是各个命令的功能介绍:
  • resize2fs 是用于调整 EXT2/3 文件系统的大小,离线的设备可以调整,如果已经 mount 的话,ext3 在 2.6 的内核里面已经支持在线调整了。值得注意的是,该命令并不调整分区大小,因此一般需要通过 fdisk 将后面分区删除,然后才能 resize2fs dev size;缩小分区时是 resize2fs 然后 fdisk。
  • fsck.ext2 是 ext2/3 文件系统查错程序,和 e2fsck 一样功能。。
  • mkfs.ext2 创建 ext2/3 文件系统,和 mk2efs 一样功能。
  • findfs 通过 LABEL 或者 UUID 获得设备名。
  • fsck.ext4dev 和 mkfs.ext4dev 是 ext4 文件系统的工具,只是现在尚未完全完成。
  • blkid 用于搜索显示 block device 相关的信息,如是否为 swap,UUID 和 LABEL 等。如
    $ sudo blkid /dev/sda1
    /dev/sda1: UUID="6E0C10D80C109D61" TYPE="ntfs"
  • logsave 可以将一个命令的输出写到指定的文件中,其不同之处在于,如果该文件不可写,则写入在内存直到该文件可写;比如启动时内核输出信息一般应计入 /var/log,但是 /var 分区可能尚未挂载。
  • fsck.ext3 和 mkfs.ext3 是 ext3 文件系统的查错、创建程序,本质上和 ext2 版本一样。
  • e2image 用于从一个 ext2/3 分区中提取关键性信息产生一个 image 文件,该文件有助于分析损坏的文件系统,一般是提供给 dumpfs 和 debugfs 命令(通过 -i 选项)。
  • tune2fs 是用来调整 ext2/3 文件系统的一些特定功能,这些功能多数在 mkfs 的时候可以指定,这里详细的介绍一下:-c 最大挂载次数(满足后会 fsck,0 或者 -1 则忽略),-C 设定挂载次数计数器,-e 出错处理方式(如 continue,remount-ro 或者 panic),-E 设置扩展选项(主要是 RAID 和 ext4 的一些属性),-f 强制执行命令即便出错,-g 设定用户组可以使用保留的空间,-i 设定文件系统检查间隔(即使没达到挂载次数的限制),-j 打开 journal(即 ext3 文件系统),-J 设定 journal 的选项(size 指定大小,device 设定外部保存 journal 的设备),-l 列出 super block,-L 设定 LABEL,-m 设定保留空间的百分比(默认 5),-M 设定最后被挂载的目录,-o 另外一些挂载选项(debug 调试功能打开,bsdgroups 使用 bsd 的行为,user_xattr 使用用户扩展属性,acl 使用 POSIX acl,uid16 使用老式 16bit 的 uid,journal_data 不仅仅对 meta data 做日志也对数据本身作,journal_data_ordered 和 journal_data_writeback 是设定 data 还是 metadata 首先写入日志),-O 设定一些文件系统的特性(large_file 允许大于 2 Gb 文件,dir_index 使用 B-tree 加速,filetype 储存文件类型信息,has_journal 和前面 -j 一样,sparse_super 限制备份 super block 的数目,resize_inode 保留一定的空间以便 inode 增加,uninit_bg 打开可减少 fsck 时间;这部分应用后应该 fsck 使得文件系统保持一致性),-r 保留 super block 数目,-T 上次 fsck 时间,-u 设定使用保留空间的用户,-U 设定 UUID。
  • e2undo 将重放 ext2/3/4 文件系统的 undo log。
  • e2label 设定 LABEL。
  • dumpe2fs 将会把 super block 上的信息 dump 到 stdin。
  • fsck 文件系统检查一般性的命令。
  • debugfs 是 ext2 文件系统交互式除错工具,啊,甚用。
  • badblocks 对指定的设备检查坏掉的块。
  • lsattr 和 chattr 是对 ext2/3/4 文件系统特有的属性进行查阅和更变。chattr 和 chmod 类似,可以用 +-= 设置对应的属性位。A 在被访问是不更改 atime,a 进允许 append(只有 root 才可能设置),c 自动被压缩,D 对目录表示写入改动立即被同步(dirsync),d 表示不被 dump 等程序备份,E 表明出现了压缩错误,I 表明使用了 hashed tree 加速索引,i 说明该文件不能被任何形式的更改,j 和前面 journal_data* 类似,s 表示会进行安全删除(先清 0),S 对文件表示写入等操作立即同步,T 对目录表示是?Orlov block allocator,完全谬听说过,t 表明该文件不会产生占据半个 block 与其他文件共享的碎片,u 表明删除后文件内容不会丢失,X、Z 都是实验性和压缩文件相关的属性。
  • filefrag 报告某指定文件碎片情况。
  • mklost+found 建立 lost+found 目录,并预留空间。

2008年7月15日星期二

x11-utils

该包内含有:
/usr/share/doc/x11-utils/copyright
/usr/share/doc/x11-utils/changelog.gz
/usr/share/man/man1/listres.1.gz
/usr/share/man/man1/luit.1.gz
/usr/share/man/man1/viewres.1.gz
/usr/share/man/man1/xdpyinfo.1.gz
/usr/share/man/man1/xdriinfo.1.gz
/usr/share/man/man1/xev.1.gz
/usr/share/man/man1/xfd.1.gz
/usr/share/man/man1/xfontsel.1.gz
/usr/share/man/man1/xkill.1.gz
/usr/share/man/man1/xlsclients.1.gz
/usr/share/man/man1/xlsfonts.1.gz
/usr/share/man/man1/xmessage.1.gz
/usr/share/man/man1/xprop.1.gz
/usr/share/man/man1/xvinfo.1.gz
/usr/share/man/man1/appres.1.gz
/usr/share/man/man1/editres.1.gz
/usr/share/man/man1/xlsatoms.1.gz
/usr/share/man/man1/xwininfo.1.gz
/usr/share/menu/x11-utils
/usr/bin/appres
/usr/bin/editres
/usr/bin/listres
/usr/bin/luit
/usr/bin/viewres
/usr/bin/xdpyinfo
/usr/bin/xdriinfo
/usr/bin/xev
/usr/bin/xfd
/usr/bin/xfontsel
/usr/bin/xkill
/usr/bin/xlsatoms
/usr/bin/xlsclients
/usr/bin/xlsfonts
/usr/bin/xmessage
/usr/bin/xprop
/usr/bin/xvinfo
/usr/bin/xwininfo
/etc/X11/app-defaults
/etc/X11/app-defaults/Editres
/etc/X11/app-defaults/Editres-color
/etc/X11/app-defaults/Viewres
/etc/X11/app-defaults/Xfd
/etc/X11/app-defaults/XFontSel
/etc/X11/app-defaults/Xmessage
/etc/X11/app-defaults/Xmessage-color
下面逐一介绍,
  • appres、editres、listres 和 viewres 是处理 X resource 的工具,appres 可以显示某一个程序或者子项目的相关 resource,listres 显示所有 widget 的 resource,editres 和 viewres 是显示 resource 的 GUI。
  • luit 被设计为任意程序与一个 utf-8 虚拟终端交互的 filter,已经不大用了,现在鼓励直接让程序生成 utf-8。
  • xdpyinfo 显示 X server 的信息,如使用了什么 extensions,分辨率之类的。
  • xdriinfo 显示 DRI 信息,不知道为啥 NVIDIA 的显卡上面都说 libGL 太老了 @@...
  • xev 可以为指定的窗口(-id)或者创建一个新窗口显示对应接受的 events,多用于调试 GUI。
  • xfd 显示某一个字体所有字符,可用 -fn 指定(X core font)字体名或者 -fa 指定 Xft 字体名。
  • xfontsel 是一个显示各个字体样例的程序。
  • xkill 是杀掉 X clients 的一个程序,需要用 -id 指定 resource,或者不指定会让用户用鼠标点击。
  • xlsatoms 列出 X server 端 atom,似乎跟 X server 有关系,但是不知道是些啥 -,-b
  • xlsclients 列出连在某个 X server 上的 X clients。
  • xlsfonts 列出所有 X core fonts。
  • xmessage 设计的目的和 echo 类似,显示在屏幕上一个窗口,可以自定义文字,按钮和返回值。
  • xprop 显示或更改指定 X client 的 X server 属性。
  • xvinfo 显示 X-video extension 的信息。
  • xwininfo 显示对应 window 的信息。

这里就一些细节进一步讨论。

2008年7月7日星期一

x11-xserver-utils

这是一组 X 里有用的命令集合,比较底层,包括
/usr/share/doc/x11-xserver-utils/copyright
/usr/share/doc/x11-xserver-utils/changelog.gz
/usr/share/man/man1/sessreg.1.gz
/usr/share/man/man1/showrgb.1.gz
/usr/share/man/man1/xcmsdb.1.gz
/usr/share/man/man1/xhost.1.gz
/usr/share/man/man1/xmodmap.1.gz
/usr/share/man/man1/xrandr.1.gz
/usr/share/man/man1/xrdb.1.gz
/usr/share/man/man1/xset.1.gz
/usr/share/man/man1/xsetmode.1.gz
/usr/share/man/man1/xsetpointer.1.gz
/usr/share/man/man1/xsetroot.1.gz
/usr/share/man/man1/xstdcmap.1.gz
/usr/share/man/man1/xtrap.1.gz
/usr/share/man/man1/xtrapin.1.gz
/usr/share/man/man1/xtrapinfo.1.gz
/usr/share/man/man1/xtrapout.1.gz
/usr/share/man/man1/xtrapproto.1.gz
/usr/share/man/man1/xtrapreset.1.gz
/usr/share/man/man1/xtrapstats.1.gz
/usr/share/man/man1/iceauth.1.gz
/usr/share/man/man1/xgamma.1.gz
/usr/share/man/man1/xrefresh.1.gz
/usr/share/man/man1/xtrapchar.1.gz
/usr/share/man/man1/xvidtune.1.gz
/usr/share/menu/x11-xserver-utils
/usr/bin/iceauth
/usr/bin/sessreg
/usr/bin/showrgb
/usr/bin/xcmsdb
/usr/bin/xgamma
/usr/bin/xhost
/usr/bin/xmodmap
/usr/bin/xrandr
/usr/bin/xrdb
/usr/bin/xrefresh
/usr/bin/xset
/usr/bin/xsetmode
/usr/bin/xsetpointer
/usr/bin/xsetroot
/usr/bin/xstdcmap
/usr/bin/xtrapchar
/usr/bin/xtrapin
/usr/bin/xtrapinfo
/usr/bin/xtrapout
/usr/bin/xtrapproto
/usr/bin/xtrapreset
/usr/bin/xtrapstats
/usr/bin/xvidtune
/etc/X11/app-defaults/Xvidtune
我们一个一个来介绍每个命令的用途。如果需要了解 X window 系统结构,可以参看这里
  • iceauth 和 xauth 类似,但是是作为 inter-client exchange 协议下的认证文件 .ICEauthority 的操纵程序。
  • sessreg 用于记录 X session 的会话记录到 utmp(记录登录登出)。
  • showrgb 显示系统已知颜色对应的 rgb。
  • xcmsdb(X color management system)用于加载、查询 X 的 device profile,如将 CIEXYZ 转换成为 RGB 的方法、gamma 信息。
  • xgamma 用于获得或者更改 X 显示的 gamma 值。
  • xhost 是一种 X server 的验证机制,是基于主机名/地址的,语法为 xhost + 开放给所有人,xhost - 仅仅允许 list 里面的主机,xhost +hostname 添加到 list 而 xhost -hostname 删去。
  • xmodmap 用于显示或者修改键盘或者鼠标映射,如 -pm 显示 modifier(如 Ctrl、Shift 等)、-pk 显示 keymap。可以通过 -e 执行一个命令或者使用一个文件作为命令序列输入。
  • xrandr 是 X 的一个 extention RandR 的命令行接口,用于设定一个 X 的大小、方向(旋转或者镜像)。ms 现在 NVIDIA 的驱动不大支持 xrandr,不爽... 一般用法为 xrandr -q 获得已有的输出设备支持的分辨率和刷新率,然后可以选择设定这些值,并且可以设定屏幕的朝向,如用 --output 屏幕 --reflect x 产生镜像翻转。
  • xrdb 是用于读入 X resource 的工具,X resource 一般存放在 .Xdefaults 里面,放有某些应用程序需要的一些配置,如 Emacs 的字体等等。这个我们会在后面对 X resource 的管理做出专门的讨论。
  • xrefresh 可以用来刷新一个 X screen,或者该 screen 的某一个部位。
  • xset 是一个强大的设置工具,如 b 设置 bell 的声音大小,bc 或者 -bc 设置或者关闭一个 bug compatability 模式,+/-dpms 是 enery star 的功能,fp 可以指定 X server 的 font path(避免修改系统文件 /etc/X11/xorg.conf),led 设定键盘上 LED 指示灯的状态,m 或者 mouse 设定鼠标灵敏程度(加速),r 控制按键自动重复输入(可以选择打开或者关闭对某些键的设置),s 设置 screen saver 的特性,q 显示已有配置。
  • xsetmode 设置输入装置的 mode 为绝对或者相对。
  • xsetpointer 设置 X 主要的 pointer 设备。
  • xsetroot 用于设定 X root window 的性质,如使用光标,使用 bitmap 作为背景,背景色等。
  • xstdcmap 用于设定 X standard color map,不知道有啥用...
  • xtrap* 命令是 X 的 XTrap extension 系列命令,似乎是为了方便 the capturing of server protocol and synthesizing core input events,这是啥 -,-bb
  • xvidtune 用于调整视频模式,如显示偏了,或者大了小了。

这里简单的叙述一下 xmodmap 的用法,keycode 就是按键的编号(数字),keysymname 是按键的符号名称。xmodmap 常用的命令有 keycode NUMBER = KEYSYMNAME 将某个 keycode 映射成为某 keysym。注意 KEYSYMNAME 可以有 8 项表示在有没有 modifier 情况下的结果,如 -pk 的输出
     10     0x0031 (1) 0x0021 (exclam)
11 0x0032 (2) 0x0040 (at)
12 0x0033 (3) 0x0023 (numbersign)
可见按键 1、2、3 是如何被映射的。keycode any = KEYSYMNAME 将未进行映射的 keycode 映射。keysym KEYSYMNAME = KEYSYMNAME 将 keysym 映射成为 keysym,比如要按下 A 出来 B,可以写 keysym a = b,注意中间的空格是不能省略的。clear MODIFIERNAME 清除掉某个 modifier,add MODIFIERNAME = KEYSYMNAME 添加一个 modifier,remove MODIFIERNAME = KEYSYMNAME 去掉一个 modifier,pointer = NUMBER 可以设置三个按键的作用,使用 pointer = default 恢复默认值。


注:
  • 为了不影响现有 X 的正常配置,进行某些实验时,建议另外打开一个 X,如 startx -- :1。

util-linux

该包中含有大量最常用的命令,集中在 /sbin、/usr/bin 和 /usr/sbin 中:
  • mkswap,用于在一个设备或者文件中创建 swap 分区。创建后需要通过 swapon 打开。分区类型为 0x82,不要和 Solaris 使用的分区类型混淆(也是 0x82)。
  • isosize 用于输出一个 iso9660 设备或者镜像文件的文件系统长度。
  • hwclock 用于访问硬件时钟,即 bios 内置时钟,可以同步该时钟和系统时钟(内核维护的时钟)。
  • mkfs.bfs 创建 SCO 的 BFS 文件系统。
  • fsck.cramfs 对 cramfs 文件系统进行检查。
  • mkfs.minix 创建 minix 文件系统。
  • blockdev 设置或显示 block device 的 ioctls,如读写属性,扇区大小,重新读入分区表或者 flush buffer。
  • cfdisk 分区程序,和 fdisk 不一样之处是用 curse/slang 库写的, TUI 要更好用一些。
  • fdisk 分区程序,没啥好说的,-l 会显示所有设备。
  • getty,作为守候某个线路如终端、串口的程序,将会为用户打开 login 提供登录。后面详细介绍。
  • mkfs.cramfs 创建 cramfs 文件系统,由于 cramfs 是压缩 ROM(Read-Only Memory)文件系统,只读,常用作 initrd 镜像文件,使用 zlib 压缩,最大文件不能超过 16Mb,文件系统最大只能稍微超过 256Mb(最后一个文件在 256Mb 块前开始,并可以扩展到 256Mb 以外)。因此该命令基本格式是 mkfs.cramfs dir img。
  • pivot_root 和 chroot 类似,但是目的不同,pivot_root 不同实现也不一样,pivot_root 把老的 / 挂在新 / 的子目录下,但是可能当前 / 没有更新(和实现相关),因此后面需要再次 chroot 进入新的 root。
  • sfdisk 也是一个维护分区的工具,比较不同的是可以调整分区大小,但是不能处理较大的分区(可用 GNU parted)。
  • ctrlaltdelete,设置按下 Ctrl-Alt-Del 的行为,分 hard 和 soft,前者不进行 sync 等前期操作,比较危险。
  • raw 将一个 character 设备绑定到一个 block 设备,这样可以用访问前者的方式访问后者,现在已经不多用了,推荐直接用 O_DIRECT 方式打开 block 设备。
  • fsck.minix 是 minix 文件系统查错程序。
  • mkfs 是创建文件系统的统一接口。通过 -t 指定类型,其余的和 mkfs.* 类型一致即可。
  • dmesg 可以显示内核在 boot 时候的信息,还可以清除(-c)kernel ring buffer,设置大小(-s)和级别(-n)。
  • more 标准分页阅读程序,建议用 less。
  • tailf 和 tail -f 类似,可以跟着文件的增长显示最后的几行,但是不像后者会在不增长时访问文件,因此不会更新该文件的 access timestamp。
  • fdformat,软盘低级格式化,ms 谬几个人用软盘了吧...
  • rtcwake 进入系统休眠状态,并设定重新醒来时间,这个将在后面休眠的专题里面讨论一下。
  • cytune 用于调整 Cyclades-Z 多端口串口卡的驱动参数。
  • tunelp 设定打印机(lp 设备)的参数,不过现在似乎直接用 cups 的人更多了吧 :-p
  • readprofile 读取 kernel profile,但是 kernel 必须打开 profile(boot 时加 profile=? 的参数)。
  • rdev 也是一个不被鼓励使用的命令,因为多数功能在非 i386 的系统上已经不能使用,取而代之的是直接用 boot loader 设定类似的参数,该命令和 rootflags、ramsize、vidmode 用于显示或者设定根分区、RAM disk 和视频模式的信息。
  • ldattach 将一个 line discipline 关联到串口设备,这样通过访问串口输入输出和在对应设备上是一个效果,如 TTY、SLIP、MOUSE、PPP 等。
  • chkdupexe 搜索 PATH 发现重名命令或者断掉的符号连接。
  • line 读入一行,与 read(bash 内部命令)类似。
  • rev 将输入每行翻转。
  • setterm 设定 term 性质,如 setterm -reset 和 reset 类似,光标显示与否(-cursor)等等。
  • partx 为给定的 block 设备指定分区表类型方便 kernel 分析该设备上的分区。和 fdisk 不同的是,可以使用该程序“告诉”内核添加分区或者删除,但是不写入到改设备上。
  • chrt 设定某进程 real-time 属性,好像 GNU libc 的文档有相关的论述。
  • taskset 可以将某个进程绑定到指定的 CPU 上。
  • ipcrm 是 IPC 管理,移除 message queue、semaphore 或者 shared memory。
  • ionice 设置一个程序的 IO 优先级别。
  • addpart/delpart 添加删除分区。
  • setsid 设置某程序在新的 session 中执行。
  • pg,感觉和 more 一样 @@
  • ipcs,显示 IPC 信息。
  • getopt,和 C 里面 getopt 函数类似,用于 parse 程序输入的参数。这里有例子。
  • flock,处理文件锁,如 -s 共享锁,-e 排除锁,-n 非阻塞式(fail 即返回),-u 开锁等。
  • whereis 显示程序位置。
  • mcookie 产生 magic cookie 的小程序。
  • namei,显示一个 path 上每个点的类型,如目录、设备还是别的。
  • ddate 将 Gregorian date 转换称为 Discordian date。
  • linux32/linux64/i386 设定对应结构下的环境变量。

这里我们看看一些重要的应用。比如一般在 /etc/inittab 里面有打开终端的命令,这也是一般在文本模式下看到的东西,
1:2345:respawn:/sbin/getty 38400 tty1
2:23:respawn:/sbin/getty 38400 tty2
3:23:respawn:/sbin/getty 38400 tty3
4:23:respawn:/sbin/getty 38400 tty4
5:23:respawn:/sbin/getty 38400 tty5
6:23:respawn:/sbin/getty 38400 tty6

# Example how to put a getty on a serial line (for a terminal)
#
#T0:23:respawn:/sbin/getty -L ttyS0 9600 vt100
#T1:23:respawn:/sbin/getty -L ttyS1 9600 vt100

# Example how to put a getty on a modem line.
#
#T3:23:respawn:/sbin/mgetty -x0 -s 57600 ttyS3


相关文件:
ncurses-bin: reset
parted: parted

xauth

xauth 是一个很有意思的程序,也许平时不会直接用到,但是很多程序会默默的使用它为你工作,比如前面的 ssh。

提到 xauth 就不可避免的涉及到 X 的工作原理,这里仅仅讨论认证部分。比较傻瓜且很不安全的方式就是用 xhost,比较聪明的方式还是用 xauth。这里讨论后者,在后面提到前者的时候我们会将它们比较。xauth 认证靠一串 128bit 的数字,所谓的 magic cookie,正式名称为 MIT-MAGIC-COOKIE-1。这串数字由 X server 产生,一般一个 X client 需要访问 X server 根据 -display 或者 DISPLAY 变量给出的地址,查询本地 XAUTHORITY 文件(一般是 ~/.Xauthority)获得对应 magic cookie,这样才会被授权访问 X server。在 X11R6.3 以后还加入了一个新特性,就是 X11 服务器可以 on-the-fly 生成 magic cookie,并标注某些 trusted,某些为 untrusted,这样给不同的 Xclient 以不同的 cookie,就可以防止某些 X client 程序盗取键盘按键序列等敏感信息。

一般来说 X server 启动的时候会产生 magic cookie,我们只需要将合适的 cookie 分发到需要调用 X clients 的主机上,那些主机的 X clients 就可以出现在 X server 上了。比较常用的 magic cookie 的生成程序来自于 mcookie。

xauth 就是用来操纵 XAUTHORITY 文件的程序,使用它会方便分发 magic cookie。一方面可以直接用 xauth command 来执行相关的命令,另一方面也可以在命令行上通过 xauth 进入交互环境。命令不多,有 n 开头和非 n 开头的命令,n 表示输出用数字,在某些情况更加合适一些,如某些传输情况。由于 XAUTHORITY 文件访问可能被锁定,所以有 -b 选项尝试解锁,-i 选项忽视锁。下面是常用命令,
  • add displayname protocolname hexkey:添加一个 display 和对应的 magic key,中间的 protocolname 可以用 . 表示 magic cookie。
  • generate displayname protocolname [trusted|untrusted]:和 add 不同在于是自动连接 X server 获得 magic cookie。
  • [n]extract filename displayname:把指定 displayname 的 magic cookie 写入指定文件,如果文件名为 - 则是标准输出。
  • [n]list [displayname...]:显示 XAUTHORITY 里面的 magic cookies。
  • [n]merge [filename...]:把 filename 和现在的融合在一起。
  • remove displayname:删除某项。
  • source filename:执行 xauth 命令序列
  • info:显示相关信息
  • exit:保存并退出。
  • quit:不保存但退出。

我们可以分析一下 ssh 如何实现 X11 forwarding,首先设置 DISPLAY 变量,并将其关联到自己的 tunnel,然后需要把远程主机 XAUTHORITY 更改:
if read proto cookie && [ -n "$DISPLAY" ]; then
if [ ‘echo $DISPLAY | cut -c1-10‘ = ’localhost:’ ]; then
# X11UseLocalhost=yes
echo add unix:‘echo $DISPLAY |
cut -c11-‘ $proto $cookie
else
# X11UseLocalhost=no
echo add $DISPLAY $proto $cookie
fi | xauth -q -
fi
可见,如果是 localhost 开始(已经使用了 ssh)取 localhost: 后面的数字前面加上 unix:,否则直接使用。这个符合语句通过 echo 把命令显示并由管道输入给 xauth。有些不使用 ssh 的环境,如 telnet 或者 rsh,同时 home 又不公用,就需要一边 xauth list 一边 xauth merge 了。

相关程序:
xhost 来自于 x11-server-utils。
mcookie 来自于 util-linux。

2008年7月5日星期六

openssh

Linux 中最常用的几个包,openssh 怕是其中最常用的远程登录、传输文件和穿透网络的工具了。这里主要介绍 openssh-server 和 openssh-client。

ssh 就是 secure shell 的缩写,当初设计目的是为了避免使用具有安全隐患的 telnet 服务。众所周知,telnet 协议下所有数据是明文传输的,这意味着如果有用户想通过网络访问某台主机,他的用户名和密码都将可能被网络上别有用心的人捕获到。类似的传统的 rsh 系列,仅仅通过 .rhost 文件认证,数据也是明文传输,这会极大的考验系统管理的安全性。ssh 的出现就是为了替代 telnet 和 rsh,但是同时它做得更好。openssh 是 ssh 协议的一个实现,它提供了服务器和客户端程序,并在多个类 Unix 环境下都可以编译执行。Windows 里面比较常见的 ssh 客户端是 PuTTY

我们先要了解一下 ssh 实现的大致思想。ssh 服务器和客户端支持对称和不对称加密算法,它们通过密钥交换使得可以用对方的公钥加密一个具有时效性的随机产生对称加密密钥作为两者通信信道的加密手段,同时还支持用户通过传统密码认证登录系统,也支持使用不对称密钥认证。由于加密隧道的存在,这也使得我们可以利用这个把 X11 client 的请求 forward 到客户端,这样实现远程启动图形界面的程序;当然,隧道还可以用于传输文件;另外一个重要作用是加密隧道为我们穿透私有网络提供了桥梁。

下面我们看看 openssh-server 里面的东西:
/usr/sbin/sshd
/usr/lib/openssh/sftp-server
/usr/share/man/man5/sshd_config.5.gz
/usr/share/man/man8/sftp-server.8.gz
/usr/share/man/man8/sshd.8.gz
/usr/share/doc/openssh-client
/var/run/sshd
/etc/init.d/ssh
/etc/network/if-up.d/openssh-server
/etc/pam.d/sshd
/etc/default/ssh
/usr/lib/sftp-server
/usr/share/man/man5/authorized_keys.5.gz
/usr/share/doc/openssh-server
可见 server 程序是 sshd,配置文件是 /etc/ssh/sshd_config。第一次运行 sshd 的时候会产生服务器的密钥,也放在/ etc/ssh 目录下,一般是 RSA 和 DSA 密钥两对(一个公钥、一个私钥)。sshd 每接受一个连接会 fork 出来一个进程处理对应的请求,当接受到 SIGUP 的信号会重新读取自己的配置文件。sshd 的命令行参数请见 man page,这可以方便定制从 /etc/init.d/ssh 启动的参数。

在 ssh 协议 1 里面,服务器仅支持 RSA,它产生一个一般只有 768bit 的额外密钥(服务器打开的时候就产生,并且使用过一定时间,如每小时,后就会重新生成,不保存在磁盘上)。当客户端连接的时候,服务器将自己的 RSA 公钥和这个额外的密钥一起发送给对方,客户端收到后通过比较自己知道的对方 RSA 公钥和发送过来的 RSA 公钥确认的确是目的主机,然后产生一个 256bit 随机数,把该随机数用对方的 RSA 公钥和额外密钥加密发回到服务器,服务器解开此随机数后就可以和客户端使用该随机数作为对称加密的密钥了,如 Blowfish、3DES 。而在 ssh 协议 2 里面,密钥交换是通过 Diffie-Hellman 方法,会话的完整性通过数字签名算法(如 md5、sha 等保证)。

完成这部分后就是进行常规的用户认证工作,这部分现在多交给 PAM 完成。登录后,sshd 将会做如下事情,
  1. 如果从 tty 登录,没有声明执行的命令,则显示上次登录时间、motd(根据 ~/.hushlogin 决定)。
  2. 记录登录时间。
  3. 如果有 /et/nologin 则显示并退出,root 除外。
  4. 将权限变更到普通用户。
  5. 建立基本环境。
  6. 执行 ~/.ssh/environment,根据配置文件是否允许用户自定义。
  7. 切换到用户目录。
  8. 执行 ~/.ssh/rc 或者 /etc/ssh/sshrc。
  9. 执行 shell。
SSHRC 存在的目的是为了允许登录前准备一些东西,比如用户的主目录什么的,另外 X11 forwarding 功能的实现也是在这一步,通过 xauth 认证。另外有 ~/.ssh/authorized_keys 这个文件是所有允许使用公钥认证的列表,其格式对协议 1 为 options, bits, exponent, modulus, comment,协议 2 为 options, keytype, base64-encoded key, comment,其中 options 不允许插入空格(除非引号内),可以包括 command="commands"(默认为 SSH_ORIGINAL_COMMAND 变量),environment="NAME=VALUE"(设置环境变量),from="pattern list"(设置访问地址范围),no-agent-forwarding(禁止 agent forwarding),no-port-forwarding(禁止 port forwarding),no-pty(不打开 pty),no-user-rc(不使用 ~/.ssh/rc),no-X11-forwarding(取消 X11 forwarding),permiteopen="host:port"(限制 -L 打开的本地端口),tunnel="n"(创建一个 tun 设备)。options 之间用逗号隔开。SSH_KNOWN_HOSTS 在 /etc/ssh 和 ~/.ssh/known_hosts ,一般用空格分开下面的域 hostnames, bits, exponent, modulus, comment。hostnames 一般有明文记录的,现在多数默认是存 hash 值,这使得每一个 host 对应的公钥信息记录在本地,一旦对方密钥不符合可以拒绝连接。在 /etc/ssh/moduli 文件中储存的是 Diffie-Hellman 算法的相关分组信息。

配置文件格式很简单,如 Port 指定端口,ListenAddress 指定监听地址(有多个地址的主机),Protocol 指定版本(现在多为 2),HostKey 指定密钥位置,前面所说的几种 forwarding 可以在此禁止,一般禁止使用 ~/.rhosts 和 ~/.shosts 这些认证方式,还可以选择是否允许密码或者密钥。

对于 openssh-client 而言,东西多很多,
/usr/bin/ssh-add
/usr/bin/ssh-agent
/usr/bin/ssh-keyscan
/usr/bin/ssh
/usr/bin/ssh-vulnkey
/usr/bin/ssh-argv0
/usr/bin/ssh-keygen
/usr/bin/scp
/usr/bin/sftp
/usr/bin/ssh-copy-id
/usr/lib/openssh/ssh-keysign
/usr/share/man/man5/ssh_config.5.gz
/usr/share/man/man5/moduli.5.gz
/usr/share/man/man8/ssh-keysign.8.gz
/usr/share/man/man1/ssh-agent.1.gz
/usr/share/man/man1/ssh-keyscan.1.gz
/usr/share/man/man1/ssh-add.1.gz
/usr/share/man/man1/ssh-vulnkey.1.gz
/usr/share/man/man1/sftp.1.gz
/usr/share/man/man1/ssh-argv0.1.gz
/usr/share/man/man1/ssh.1.gz
/usr/share/man/man1/ssh-copy-id.1.gz
/usr/share/man/man1/scp.1.gz
/usr/share/man/man1/ssh-keygen.1.gz
/usr/share/lintian/overrides/openssh-client
/usr/share/doc/openssh-client/README.Debian.gz
/usr/share/doc/openssh-client/OVERVIEW.gz
/usr/share/doc/openssh-client/NEWS.Debian.gz
/usr/share/doc/openssh-client/README.dns
/usr/share/doc/openssh-client/README.compromised-keys.gz
/usr/share/doc/openssh-client/README.tun.gz
/usr/share/doc/openssh-client/copyright
/usr/share/doc/openssh-client/changelog.gz
/usr/share/doc/openssh-client/changelog.Debian.gz
/usr/share/doc/openssh-client/README
/usr/share/doc/openssh-client/faq.html
/etc/ssh/ssh_config
/etc/ssh/moduli
/usr/bin/slogin
/usr/share/man/man1/slogin.1.gz
这里主要解释每一个小模块的作用,如 ssh 是客户端命令行程序,scp 用于把本地和远程主机上文件进行复制,sftp 提供了一个类似于 ftp 的 TUI,ssh-keygen 用于产生密钥,ssh-agent 也就是所谓的 agent(多用于多主机之间的穿梭,避免将私钥放置到不可靠主机上),ssh-add 用于向 agent 添加一个需要管理的密钥,ssh-keyscan 用于收集公钥(主要用于建立 SSH_KNOWN_HOSTS 文件)。系统客户端配置文件在 /etc/ssh/ssh_config 而个人配置文件在 ~/.ssh/config。

关于 ssh 的应用非常多,这里仅仅提一点思路,具体调用参数请参考 man page:
  • 对于具有多个网络设备的主机,可以用 -b 选择合适的地址进行连接。
  • 如果直接 ssh user@host 则会登录,如果 ssh user@host command 则执行命令后退出。
  • 通过管道可以把一台机器上的输出导入到另一台机器上,如 tar cv DIR | ssh host "cat >DIR.tar" 的作用就是把本地 DIR 目录做成一个 tar ball,输出到标准输出(因为 tar 没有 f 选项),管道把这个命令的输出与后面的输入连接,我们知道 cat 就是把标准输入显示到标准输出,其输出重定向 > 使得最后写入到文件 DIR.tar 中。
  • ssh 能很方便的把 X11 client 程序的请求 forward 到本地,因此只要本地打开了 X server,则可以显示远程 X client,前面 sshd_config 中我们看到 X11DisplayOffset 10,这使得连接到该主机的 ssh 客户端的 DISPLAY 变量指向 localhost:10+,这里的 localhost 指 client 所在主机,后面 10+ 指从 10 开始计数,当有多个 client 连接时,这个计数器会增加。
  • 通过 ssh 可以建立隧道序列,如从 A 到 B 建立 ssh 连接,然后从 B 连接到 C,这时只要每个连接都打开了 X11 forwarding,那么在 C 上运行 X11 程序,X11 client 的请求将会从 C -> B -> A 最终显示在 A 上,这对一般的隧道也是如此。隧道的串联极大的增强了 ssh 的穿透性。
  • 端口映射很有用,-L [bind_address:]port:host:hostport 将本地打开一个端口,映射到 host:hostport,这有什么用呢?比如本地是 A,远程是 B,那么映射的 host:hostport 是 B 可以访问的,但 A 没有直接访问的权限(如私有网络等)。这样 A 通过访问本地 port 就相当于访问了 host:hostport。类似还有一个 -R [bind_address:]port:host:hostport,这会在远程主机上打开 port 端口,将其请求转到本地网络上的 host:hostport。这里有一个比较复杂的例子
  • 方便开设代理服务器。要知道上面的办法可以应付一些问题,如 ssh、telnet 端口的映射,但是对于比较特殊的如 ftp 等就无能为力了,这主要是因为 ftp 分控制信道端口和实际数据传输端口,仅仅打开一个端口进行映射是行不通的,同时也不可能预知究竟会用哪个端口。-D [bind_address:]port 将会在本地打开一个 SOCKS 代理,这时只需要将本地的程序设置使用该代理地址(如 127.0.0.l:port),ssh 将会自动开设需要的端口。默认情况这个端口只有本地能访问,可以用 -g 向其他机器打开使用权限。
  • -e 设置逃脱键,怎么逃脱?如 A -> B,建立连接后,shell 的控制字符 C-z 被远程 shell 拦截,因此如果需要 suspend 该连接直接 C-z 是没有作用的,默认的 escape 字符是 ~,按 ~C-z 可以达到该目的。其他的如 ~# 列出所有的连接,~C 获得命令行(添加 port forwarding 等)
  • 建立 tun,-w local_tun[:remote_tun],这使得本地出现一个 tun 设备,通过更改路由,就可以实现最简单的 VPN 了。需要 root 权限。
  • 常用选项在 ~/.ssh/config 里面写,如打开 X11 forwarding 或者 agent forwarding 等,参考 man page 里面哪些选项可以用。

下面介绍如何使用密钥,最直接就是 ssh-keygen 产生对应的密码了,一般使用 -t 指明密钥类型,如 rsa 或者 dsa,为主机产生的密钥不应带有口令,如果不希望每次输入口令,可以空缺下来。-H 会把 SSH_KNOWN_HOSTS 的主机名 hash 掉。-p 修改原来的口令,如果忘掉了口令就只能重新产生并覆盖了。有一些比较有意思的应用是 ssh 和 cvs 或者 subversion 联合起来,使用密钥而不是密码可以极大的减少每次输入密码的痛苦,不过这也将管理密码的问题转移到了密钥上。

一般说来,密钥放在自己可以处理的地方,如自己有完全控制能力的笔记本,而不放在比较开放的环境,自己没有 root
的控制权或者有多人拥有这种权利。这产生了一个严重的问题就是会限制密钥的应用范围。ssh-agent 的出现算是缓解了这个矛盾。使用 ssh-agent 的基本方法是在启动别的程序之前首先启动它,比如可以在 X 的 .xinitrc 里面用它启动 WM,这样 ssh-agent 会为后面所有的程序设置好几个环境变量,ssh 执行的时候会优先查看这些变量寻找对应的 ssh-agent,只要通过 ssh-add 把需要的密钥加入到 ssh-agent 就可以万事无忧了。某些桌面环境,如 GNOME 会自动启用 ssh-agent,我们所要做的可能就是 ssh-add 一下。下面是一个典型的应用实例,
$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-IIXzU30554/agent.30554; export SSH_AUTH_SOCK;
SSH_AGENT_PID=30555; export SSH_AGENT_PID;
echo Agent pid 30555;

这种情况下这些环境变量必须手工设定,把程序输出复制一下就可以了。然后可以通过 ssh-add -l 查看已经加入的密钥,如果没有则通过 ssh-add 添加。之后通过 ssh B,从本地到 B(注意 B 的 ~/.ssh/authorized_keys 需要加入对应的公钥),再从 B 到 C(C 的 ~/.ssh/authorized_keys 需要配置),但是 B 上不需要有 A 上的私钥。这是因为登录 B 后 ssh 把 A 上 ssh-agent 通讯的 sock 通过环境变量带到 B,从 B 带入 C,当 C 上主机要求密钥认证时经过该地址和 A 上的 ssh-agent 协商即可。

为了方便把本地的 rsa 公钥安装到远程机器上,一般可以用 ssh-copy-id 命令,其实手工编辑对应的 authorized_keys 也是可以的。有一些密钥已经被认为十分脆弱,ssh-vulnkey 可以检测出来,如可以用 ssh-keyscan 获得对应的 RSA 公钥通过管道灌给 ssh-vulnkey。ssh-argv0 是这样用的,把主机名 ln -s /usr/bin/ssh-argv0 FucQ,然后该连接放到 PATH 中就可以直接输入主机名进行 ssh 连接了。还有两个包 openssh-blacklist 和 openssh-blacklist-extra 含有出现过问题的 ssh 公钥,供 ssh-vulnkey 使用。