qishun's profile躺在角落的孤独者PhotosBlogLists Tools Help

Blog


    October 21

    Glibc 安装指南(适用于2.3.6/2.4/2.5/2.6)

    由于论坛排版效果不理想,而且我也只在我的个人空间对文章进行后继更新,所以建议直接到我的空间查看:
    《Glibc Binutils GCC 配置选项简介》
    http://lamp.linux.gov.cn/Linux/Glibc...s-Install.html
    -------------------------------------------------------------------------------
    版权声明
    本文作者是一位自由软件爱好者,所以本文虽然不是软件,但是本着 GPL 的精神发布。任何人都可以自由使用、转载、复制和再分发,但必须保留作者署名,亦不得对声明中的任何条款作任何形式的修改,也不得附加任何其它条件。您可以自由链接、下载、传播此文档,但前提是必须保证全文完整转载,包括完整的版权信息和作译者声明。

    其他作品
    本文作者十分愿意与他人共享劳动成果,如果你对我的其他翻译作品或者技术文章有兴趣,可以在如下位置查看现有作品的列表:
    金步国作品列表

    BUG报告,切磋与探讨
    由于作者水平有限,因此不能保证作品内容准确无误,请在阅读中自行鉴别。如果你发现了作品中的错误,请您来信指出,哪怕是错别字也好,任何提高作品质量的建议我都将虚心接纳。如果你愿意就作品中的相关内容与我进行进一步切磋与探讨,也欢迎你与我联系。联系方式:Email: csfrank@citiz.net ; QQ: 70171448 ; MSN: csfrank122@hotmail.com

    ==============================================

    此文是我在写作《DIY一个实用的 Mini-LAPP 服务器》过程中整理的资料,考虑到Glibc的核心地位,因此特地把这部分内容抽取出来单独成文,以供 LFS 玩家参考。此部分内容来自于源码树下的 configure INSTALL FAQ 三个文件。

    编译前的预备知识与要点提示

    Glibc-2.3.6 建议使用 GCC-4.0 编译,Glibc-2.4/2.5 建议使用 GCC-4.1 编译,Glibc-2.6 建议使用 GCC-4.2 编译。所有这些版本最低要求使用 GCC-3.4 编译。

    编译 Glibc 时使用的内核头文件版本可以比实际运行 Glibc 的内核版本高。如果实际运行的内核版本比头文件版本高,那么新内核的新特性将无法使用。更多细节可以查看[八卦故事]内核头文件传奇的跟帖部分。

    不要在运行中的系统上安装 Glibc,否则将会导致系统崩溃,至少应当将新 Glibc 安装到其他的单独目录,以保证不覆盖当前正在使用的 Glibc 。

    Glibc 不能在源码目录中编译,它必须在一个额外分开的目录中编译。这样在编译发生错误的时候,就可以删除整个编译目录重新开始。

    在运行 configure 脚本时可以设置 CC CFLAGS LDFLAGS 环境变量来优化编译。语法:configure [OPTION]... [VAR=VALUE]...

    需要注意的是有些测试项目假定是以非 root 身份执行的,因此我们强烈建议你使用非 root 身份编译和测试 Glibc 。

    配置选项
    下列选项皆为非默认值[特别说明的除外]

    --exec-prefix
    --bindir
    --libdir
    --libexecdir
    --infodir
    --datadir
    --mandir
    --program-prefix
    --program-suffix
    --program-transform-name
    --host
    --build
    --target
    --srcdir
    --cache-file
    --no-create
    --silent
    --version
    这些选项的含义基本上通用于所有软件包,这里就不特别讲解了。
    --prefix=PREFIX
    安装目录,默认为 /usr/local
    Linux文件系统标准要求基本库必须位于 /lib 目录并且必须与根目录在同一个分区上,但是 /usr 可以在其他分区甚至是其他磁盘上。因此,如果指定 --prefix=/usr ,那么基本库部分将自动安装到 /lib 目录下,而非基本库部分则会自动安装到 /usr/lib 目录中。但是如果保持默认值或指定其他目录,那么所有组件都间被安装到PREFIX目录下。
    --enable-add-ons[=DIR1,DIR2,...]
    编译DIR1,DIR2,...中的附加软件包。其中的 "DIR"是附加软件包的目录名。未指定列表或指定为"yes"则编译所有源码树根目录下找到的附加软件包。Glibc-2.4/2.5/2.6默认值为 "yes",而 Glibc-2.3.6 默认为--disable-add-ons
    --enable-bind-now
    在 DSO 载入时就进行重定位,而不是在调用时重定位。
    --enable-bounded
    启用使用运行时边界检查(比如数组越界),这样会降低运行效率,但能防止某些溢出漏洞。
    --enable-check-abi
    在"make check"时执行"make check-abi"。[提示]在我的机器上 enable 之后始终导致 make check 失败。
    --disable-force-install
    不强制安装当前新编译的版本(即使已存在的文件版本更新)。
    --disable-hidden-plt
    不隐藏内部的函数调用以避免 PLT 。[建议不要明确设置此选项]
    --enable-kernel=VERSION
    VERSION 的格式是 X.Y.Z,表示编译出来的 Glibc 支持的最低内核版本。VERSION 的值越高(不能超过内核头文件的版本),加入的兼容性代码就越少,库的运行速度就越快。
    --enable-oldest-abi=ABI
    启用老版本的应用程序二进制接口支持。ABI 是老 Glibc 的版本号。默认值大部分情况下为 --disable-oldest-abi ,建议明确指定为 --disable-oldest-abi
    --enable-omitfp
    编译时忽略帧指示器(使用 -fomit-frame-pointer 编译),并采取一些其他优化措施。忽略帧指示器可以提高运行效率,但是调试将变得不可用,并且可能生成含有 bug 的代码。使用这个选项还将导致额外编译带有调试信息的非优化版本的静态库(库名称以"_g"结尾)。
    --disable-profile
    禁用 profiling 信息相关的库文件编译。Glibc-2.3.6 默认为 enable,Glibc-2.4/2.5/2.6 默认为disable 。
    --enable-stackguard-randomization
    在程序启动时使用一个随机数初始化 __stack_chk_guard ,主要用来抵抗恶意攻击。
    --disable-sanity-checks
    真正的禁用线程(仅在特殊环境下使用该选项)。
    --enable-static-nss
    编译静态版本的NSS(Name Service Switch)库。不推荐这样做,因为连接到静态NSS库的程序不能动态配置以使用不同的名字数据库。
    --disable-shared
    不编译共享库(即使平台支持)。在支持 ELF 并且使用 GNU 连接器的系统上默认为 enable 。
    --disable-versioning
    不在共享库对象中包含符号的版本信息。这样可以减小库的体积,但是将不兼容依赖于老版本 C 库的二进制程序。[提示]在我的机器上使用此选项总是导致编译失败。
    --with-binutils=DIR
    强制指定编译时使用的 Binutils(as,ld) 的位置。
    --with-cpu=CPU
    在 gcc 命令行中加入"-mcpu=CPU"。鉴于"-mcpu"已经被反对使用,所以建议不要设置该选项,或者设为 --without-cpu 。
    --without-cvs
    不访问CVS服务器。推荐使用该选项,特别对于从CVS下载的的版本。
    --with-elf
    指定使用 ELF 对象格式,建议在支持 ELF 的 Linux 平台上使用此选项明确指定。
    --with-gd=DIR
    --with-gd-include=DIR
    --with-gd-lib=DIR
    强制指定 libgd 的安装目录(DIR/include和DIR/lib)。后两个选项分别指定包含文件和库目录。
    --with-gmp=DIR
    强制指定 gmp 的安装目录。
    --without-fp
    仅在硬件没有浮点运算单元并且操作系统没有模拟的情况下使用。x86 与 x86_64 的 CPU 都有专门的浮点运算单元。而且 Linux 有 FPU 模拟。简单的说,不要 without 这个选项!因为它会导致许多问题!
    --with-headers=DIR
    指定内核头文件的所在目录。
    --without-selinux
    禁用 SELinux 支持。
    --without-tls
    禁止编译支持线程本地存储(TLS)的库。使用这个选项将导致兼容性问题,建议不要明确指定该选项。
    --without-__thread
    即使平台支持也不使用TSL特性。建议不要明确指定该选项。
    --with-xcoff
    使用XCOFF对象格式(主要用于windows)。

    编译与测试

    使用 make 命令编译,使用 make check 测试。如果 make check 没有完全成功,就千万不要使用这个编译结果。需要注意的是有些测试项目假定是以非 root 身份执行的,因此我们强烈建议你使用非 root 身份编译和测试。

    测试中需要使用一些已经存在的文件(包括随后的安装过程),比如'/etc/passwd','/etc/nsswitch.conf'之类。请确保这些文件中包含正确的内容。

    安装与配置

    使用 make install 命令安装。比如:make install LC_ALL=C

    如果你打算将此 Glibc 安装为主 C 库,那么我们强烈建议你关闭系统,重新引导到单用户模式下安装。这样可以将可能的损害减小到最低。

    安装后需要配置 GCC 以使其使用新安装的 C 库。最简单的办法是使用恰当 GCC 的编译选项(比如'-Wl,--dynamic-linker=/lib/ld-linux.so.2')重新编译 GCC 。然后还需要修改 specs 文件(通常位于'/usr/lib/gcc-lib/TARGET/VERSION/specs'),这个工作有点像巫术,调整实例请参考 LFS 中的两次工具链调整。

    可以在 make install 命令行使用'install_root'变量指定安装实际的安装目录(不同于 --prefix 指定的值)。这个在 chroot 环境下或者制作二进制包的时候通常很有用。'install_root'必须使用绝对路径。

    被'grantpt'函数调用的辅助程序'/usr/libexec/pt_chown'以 setuid 'root' 安装。这个可能成为安全隐患。如果你的 Linux 内核支持'devptsfs'或'devfs'文件系统提供的 pty slave ,那么就不需要使用 pt_chown 程序。

    安装完毕之后你还需要配置时区和 locale 。使用 localedef 来配置locale 。比如使用'localedef -i de_DE -f ISO-8859-1 de_DE'将 locale 设置为'de_DE.ISO-8859-1'。可以在编译目录中使用'make localedata/install-locales'命令配置所有可用的 locale ,但是一般不需要这么做。

    时区使用'TZ'环境变量设置。tzselect 脚本可以帮助你选择正确的值。设置系统全局范围内的时区可以将 /etc/localtime 文件连接到 /usr/share/zoneinfo 目录下的正确文件上。比如对于中国人可以'ln -s /usr/share/zoneinfo/PRC /etc/localtime'。

    编译优化提示

    由于 Glibc 是系统的两大核心之一(还有一个是内核),虽然 LFS 指导书反对优化编译,但很多玩家觉得不优化编译心有不甘。因此,下面有几个基于 gcc-4.0.4 + Binutils-2.17 + Linux-Libc-Headers-2.6.12.0 环境的实践提示。

    能够通过 make check 的优化设置:

    CPPFLAGS='-DNDEBUG'
    CFLAGS='-O3 -finline-limit=400 -fomit-frame-pointer -falign-functions=32 -pipe -fno-bounds-check -march=pentium3 -maccumulate-outgoing-args -fforce-addr -fmerge-all-constants -fgcse-sm -fgcse-las -minline-all-stringops -ftree-loop-linear -fivopts -ftree-vectorize -fprefetch-loop-arrays -fweb -frename-registers -fbranch-target-load-optimize'
    LDFLAGS='-s -Wl,-O1,--sort-common,-s,--enable-new-dtags,--as-needed'
    [提示]建议AMD64打开 -frename-registers ; -freg-struct-return 虽然能通过测试但是却会导致GCC的测试程序出现"FAIL: gcc.dg/struct-ret-libc.c execution test"因此该优化选项未包含在其中。此外, -fbranch-target-load-optimize -fbranch-target-load-optimize2 不能同时使用。

    不能通过编译或测试的 CFLAGS :-fvisibility=hidden -mfpmath=sse -malign-double -m128bit-long-double -mregparm=3 -msseregparm -ftracer --param max-gcse-passes=2 --param max-gcse-memory=100M -Wa,-R

    与 CPU L1/L2 cache 有关的提示[对于AMD,cache是L1(皆为128K)+L2(256,512,1M,2M)的大小;对于Intel,cache是L2的大小]:
    cache <= 512K 推荐使用 -finline-limit=200 -falign-functions=16
    512K < cache <= 1M 推荐使用 -finline-limit=400 -falign-functions=32
    cache > 1M 推荐使用 -finline-limit=600 -falign-functions=64

    shell保留字和特殊变量


    保留字符及其含义

      $#     传递到脚本的参数个数
      $*     以一个单字符串显示所有向脚本传递的参数。与位置变量不同,此选项参数可超过9个
      $$     脚本运行的当前进程ID号(Process Identifier Number, PID)
      $!     后台运行的最后一个进程的进程ID号
      $@     与$*相同,但是使用时加引号,并在引号中返回每个参数
      $-     显示shell使用的当前选项,使用set及执行时传递给shell的标志位
      $?  显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
      $0     脚本名称
      $1..$9 第N个参数

    $  shell变量名的开始,如$var
    | 管道,将标准输出转到下一个命令的标准输入
    # 注释开始
    & 在后台执行一个进程
    ? 匹配一个字符
    * 匹配0到多个字符(与DOS不同,可在文件名中间使用,并且含.)
      >file  输出重定向
    `command` 命令替换,如 filename=`basename /usr/local/bin/tcsh`
    >>file    输出重定向,append

    转义符及单引号:
    $echo "$HOME $PATH"
      /home/hbwork /opt/kde/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:
    $echo '$HOME $PATH'
      $HOME $PATH
    $echo \$HOME $PATH
      $HOME /opt/kde/bin:/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/home/hbwork/bin
    其他:
      dir=ls
      $dir
      alias dir ls
      dir

    ${#var} #计算变量值的长度

    -d file   #当file是一个目录时,返回True
    -f file   #当file是一个普通文件时,返回True
    -r file   #当file是一个刻读文件时,返回True
    -s file   #当file文件长度大于0时,返回True
    -w file   #当file是一个可写文件时,返回True
    -x file   #当file是一个可执行文件时,返回True

    -r file   #当file是一个可读文件时,返回True
    -w file   #当file是一个可写文件时,返回True
    -x file   #当file是一个可执行文件时,返回True
    -e file   #当file存在时,返回True
    -o file   #当file文件的所有者是当前用户时,返回True
    -z file   #当file长度为0时,返回True
    -f file   #当file是一个普通文件时,返回True
    -d file   #当file是一个目录时,返回True

    Glibc 安装指南(适用于2.3.6/2.4/2.5/2.6)

    由于论坛排版效果不理想,而且我也只在我的个人空间对文章进行后继更新,所以建议直接到我的空间查看:
    《Glibc Binutils GCC 配置选项简介》
    http://lamp.linux.gov.cn/Linux/Glibc...s-Install.html
    -------------------------------------------------------------------------------
    版权声明
    本文作者是一位自由软件爱好者,所以本文虽然不是软件,但是本着 GPL 的精神发布。任何人都可以自由使用、转载、复制和再分发,但必须保留作者署名,亦不得对声明中的任何条款作任何形式的修改,也不得附加任何其它条件。您可以自由链接、下载、传播此文档,但前提是必须保证全文完整转载,包括完整的版权信息和作译者声明。

    其他作品
    本文作者十分愿意与他人共享劳动成果,如果你对我的其他翻译作品或者技术文章有兴趣,可以在如下位置查看现有作品的列表:
    金步国作品列表

    BUG报告,切磋与探讨
    由于作者水平有限,因此不能保证作品内容准确无误,请在阅读中自行鉴别。如果你发现了作品中的错误,请您来信指出,哪怕是错别字也好,任何提高作品质量的建议我都将虚心接纳。如果你愿意就作品中的相关内容与我进行进一步切磋与探讨,也欢迎你与我联系。联系方式:Email: csfrank@citiz.net ; QQ: 70171448 ; MSN: csfrank122@hotmail.com

    ==============================================

    此文是我在写作《DIY一个实用的 Mini-LAPP 服务器》过程中整理的资料,考虑到Glibc的核心地位,因此特地把这部分内容抽取出来单独成文,以供 LFS 玩家参考。此部分内容来自于源码树下的 configure INSTALL FAQ 三个文件。

    编译前的预备知识与要点提示

    Glibc-2.3.6 建议使用 GCC-4.0 编译,Glibc-2.4/2.5 建议使用 GCC-4.1 编译,Glibc-2.6 建议使用 GCC-4.2 编译。所有这些版本最低要求使用 GCC-3.4 编译。

    编译 Glibc 时使用的内核头文件版本可以比实际运行 Glibc 的内核版本高。如果实际运行的内核版本比头文件版本高,那么新内核的新特性将无法使用。更多细节可以查看[八卦故事]内核头文件传奇的跟帖部分。

    不要在运行中的系统上安装 Glibc,否则将会导致系统崩溃,至少应当将新 Glibc 安装到其他的单独目录,以保证不覆盖当前正在使用的 Glibc 。

    Glibc 不能在源码目录中编译,它必须在一个额外分开的目录中编译。这样在编译发生错误的时候,就可以删除整个编译目录重新开始。

    在运行 configure 脚本时可以设置 CC CFLAGS LDFLAGS 环境变量来优化编译。语法:configure [OPTION]... [VAR=VALUE]...

    需要注意的是有些测试项目假定是以非 root 身份执行的,因此我们强烈建议你使用非 root 身份编译和测试 Glibc 。

    配置选项
    下列选项皆为非默认值[特别说明的除外]

    --exec-prefix
    --bindir
    --libdir
    --libexecdir
    --infodir
    --datadir
    --mandir
    --program-prefix
    --program-suffix
    --program-transform-name
    --host
    --build
    --target
    --srcdir
    --cache-file
    --no-create
    --silent
    --version
    这些选项的含义基本上通用于所有软件包,这里就不特别讲解了。
    --prefix=PREFIX
    安装目录,默认为 /usr/local
    Linux文件系统标准要求基本库必须位于 /lib 目录并且必须与根目录在同一个分区上,但是 /usr 可以在其他分区甚至是其他磁盘上。因此,如果指定 --prefix=/usr ,那么基本库部分将自动安装到 /lib 目录下,而非基本库部分则会自动安装到 /usr/lib 目录中。但是如果保持默认值或指定其他目录,那么所有组件都间被安装到PREFIX目录下。
    --enable-add-ons[=DIR1,DIR2,...]
    编译DIR1,DIR2,...中的附加软件包。其中的 "DIR"是附加软件包的目录名。未指定列表或指定为"yes"则编译所有源码树根目录下找到的附加软件包。Glibc-2.4/2.5/2.6默认值为 "yes",而 Glibc-2.3.6 默认为--disable-add-ons
    --enable-bind-now
    在 DSO 载入时就进行重定位,而不是在调用时重定位。
    --enable-bounded
    启用使用运行时边界检查(比如数组越界),这样会降低运行效率,但能防止某些溢出漏洞。
    --enable-check-abi
    在"make check"时执行"make check-abi"。[提示]在我的机器上 enable 之后始终导致 make check 失败。
    --disable-force-install
    不强制安装当前新编译的版本(即使已存在的文件版本更新)。
    --disable-hidden-plt
    不隐藏内部的函数调用以避免 PLT 。[建议不要明确设置此选项]
    --enable-kernel=VERSION
    VERSION 的格式是 X.Y.Z,表示编译出来的 Glibc 支持的最低内核版本。VERSION 的值越高(不能超过内核头文件的版本),加入的兼容性代码就越少,库的运行速度就越快。
    --enable-oldest-abi=ABI
    启用老版本的应用程序二进制接口支持。ABI 是老 Glibc 的版本号。默认值大部分情况下为 --disable-oldest-abi ,建议明确指定为 --disable-oldest-abi
    --enable-omitfp
    编译时忽略帧指示器(使用 -fomit-frame-pointer 编译),并采取一些其他优化措施。忽略帧指示器可以提高运行效率,但是调试将变得不可用,并且可能生成含有 bug 的代码。使用这个选项还将导致额外编译带有调试信息的非优化版本的静态库(库名称以"_g"结尾)。
    --disable-profile
    禁用 profiling 信息相关的库文件编译。Glibc-2.3.6 默认为 enable,Glibc-2.4/2.5/2.6 默认为disable 。
    --enable-stackguard-randomization
    在程序启动时使用一个随机数初始化 __stack_chk_guard ,主要用来抵抗恶意攻击。
    --disable-sanity-checks
    真正的禁用线程(仅在特殊环境下使用该选项)。
    --enable-static-nss
    编译静态版本的NSS(Name Service Switch)库。不推荐这样做,因为连接到静态NSS库的程序不能动态配置以使用不同的名字数据库。
    --disable-shared
    不编译共享库(即使平台支持)。在支持 ELF 并且使用 GNU 连接器的系统上默认为 enable 。
    --disable-versioning
    不在共享库对象中包含符号的版本信息。这样可以减小库的体积,但是将不兼容依赖于老版本 C 库的二进制程序。[提示]在我的机器上使用此选项总是导致编译失败。
    --with-binutils=DIR
    强制指定编译时使用的 Binutils(as,ld) 的位置。
    --with-cpu=CPU
    在 gcc 命令行中加入"-mcpu=CPU"。鉴于"-mcpu"已经被反对使用,所以建议不要设置该选项,或者设为 --without-cpu 。
    --without-cvs
    不访问CVS服务器。推荐使用该选项,特别对于从CVS下载的的版本。
    --with-elf
    指定使用 ELF 对象格式,建议在支持 ELF 的 Linux 平台上使用此选项明确指定。
    --with-gd=DIR
    --with-gd-include=DIR
    --with-gd-lib=DIR
    强制指定 libgd 的安装目录(DIR/include和DIR/lib)。后两个选项分别指定包含文件和库目录。
    --with-gmp=DIR
    强制指定 gmp 的安装目录。
    --without-fp
    仅在硬件没有浮点运算单元并且操作系统没有模拟的情况下使用。x86 与 x86_64 的 CPU 都有专门的浮点运算单元。而且 Linux 有 FPU 模拟。简单的说,不要 without 这个选项!因为它会导致许多问题!
    --with-headers=DIR
    指定内核头文件的所在目录。
    --without-selinux
    禁用 SELinux 支持。
    --without-tls
    禁止编译支持线程本地存储(TLS)的库。使用这个选项将导致兼容性问题,建议不要明确指定该选项。
    --without-__thread
    即使平台支持也不使用TSL特性。建议不要明确指定该选项。
    --with-xcoff
    使用XCOFF对象格式(主要用于windows)。

    编译与测试

    使用 make 命令编译,使用 make check 测试。如果 make check 没有完全成功,就千万不要使用这个编译结果。需要注意的是有些测试项目假定是以非 root 身份执行的,因此我们强烈建议你使用非 root 身份编译和测试。

    测试中需要使用一些已经存在的文件(包括随后的安装过程),比如'/etc/passwd','/etc/nsswitch.conf'之类。请确保这些文件中包含正确的内容。

    安装与配置

    使用 make install 命令安装。比如:make install LC_ALL=C

    如果你打算将此 Glibc 安装为主 C 库,那么我们强烈建议你关闭系统,重新引导到单用户模式下安装。这样可以将可能的损害减小到最低。

    安装后需要配置 GCC 以使其使用新安装的 C 库。最简单的办法是使用恰当 GCC 的编译选项(比如'-Wl,--dynamic-linker=/lib/ld-linux.so.2')重新编译 GCC 。然后还需要修改 specs 文件(通常位于'/usr/lib/gcc-lib/TARGET/VERSION/specs'),这个工作有点像巫术,调整实例请参考 LFS 中的两次工具链调整。

    可以在 make install 命令行使用'install_root'变量指定安装实际的安装目录(不同于 --prefix 指定的值)。这个在 chroot 环境下或者制作二进制包的时候通常很有用。'install_root'必须使用绝对路径。

    被'grantpt'函数调用的辅助程序'/usr/libexec/pt_chown'以 setuid 'root' 安装。这个可能成为安全隐患。如果你的 Linux 内核支持'devptsfs'或'devfs'文件系统提供的 pty slave ,那么就不需要使用 pt_chown 程序。

    安装完毕之后你还需要配置时区和 locale 。使用 localedef 来配置locale 。比如使用'localedef -i de_DE -f ISO-8859-1 de_DE'将 locale 设置为'de_DE.ISO-8859-1'。可以在编译目录中使用'make localedata/install-locales'命令配置所有可用的 locale ,但是一般不需要这么做。

    时区使用'TZ'环境变量设置。tzselect 脚本可以帮助你选择正确的值。设置系统全局范围内的时区可以将 /etc/localtime 文件连接到 /usr/share/zoneinfo 目录下的正确文件上。比如对于中国人可以'ln -s /usr/share/zoneinfo/PRC /etc/localtime'。

    编译优化提示

    由于 Glibc 是系统的两大核心之一(还有一个是内核),虽然 LFS 指导书反对优化编译,但很多玩家觉得不优化编译心有不甘。因此,下面有几个基于 gcc-4.0.4 + Binutils-2.17 + Linux-Libc-Headers-2.6.12.0 环境的实践提示。

    能够通过 make check 的优化设置:

    CPPFLAGS='-DNDEBUG'
    CFLAGS='-O3 -finline-limit=400 -fomit-frame-pointer -falign-functions=32 -pipe -fno-bounds-check -march=pentium3 -maccumulate-outgoing-args -fforce-addr -fmerge-all-constants -fgcse-sm -fgcse-las -minline-all-stringops -ftree-loop-linear -fivopts -ftree-vectorize -fprefetch-loop-arrays -fweb -frename-registers -fbranch-target-load-optimize'
    LDFLAGS='-s -Wl,-O1,--sort-common,-s,--enable-new-dtags,--as-needed'
    [提示]建议AMD64打开 -frename-registers ; -freg-struct-return 虽然能通过测试但是却会导致GCC的测试程序出现"FAIL: gcc.dg/struct-ret-libc.c execution test"因此该优化选项未包含在其中。此外, -fbranch-target-load-optimize -fbranch-target-load-optimize2 不能同时使用。

    不能通过编译或测试的 CFLAGS :-fvisibility=hidden -mfpmath=sse -malign-double -m128bit-long-double -mregparm=3 -msseregparm -ftracer --param max-gcse-passes=2 --param max-gcse-memory=100M -Wa,-R

    与 CPU L1/L2 cache 有关的提示[对于AMD,cache是L1(皆为128K)+L2(256,512,1M,2M)的大小;对于Intel,cache是L2的大小]:
    cache <= 512K 推荐使用 -finline-limit=200 -falign-functions=16
    512K < cache <= 1M 推荐使用 -finline-limit=400 -falign-functions=32
    cache > 1M 推荐使用 -finline-limit=600 -falign-functions=64

    September 30

    挖个坑,自己跳进去

        百思不得其解的问题,郁闷了那么多时日。到头来,确实自己给自己挖了坑,埋葬的是自己!

       囚鸟
    我是被你囚禁的鸟,
    已经忘了天有多高,
    如果离开你给我的小小城堡,
    不知还有谁能依靠。
    我是被你囚禁的鸟,
    得到的爱越来越少,
    看着你的笑在别人眼中燃烧,
    我却要不到一个拥抱。
    我像是一个你可有可无的影子,
    冷冷地看着你说谎的样子,
    这撩乱的城市,
    容不下我的痴,
    是什么让你这样迷恋这样的放肆,
    我像是一个你可有可无的影子,
    和寂寞交换着悲伤的心事,
    对爱无计可施,
    这无味的日子,
    眼泪是唯一的奢侈。

    我是被你囚禁的鸟,
    得到的爱越来越少,
    看着你的笑在别人眼中燃烧,
    我却要不到一个拥抱。
    我像是一个你可有可无的影子,
    冷冷地看着你说谎的样子,
    这撩乱的城市,
    容不下我的痴,
    是什么让你这样迷恋这样的放肆,
    我像是一个你可有可无的影子,
    和寂寞交换着悲伤的心事,
    对爱无计可施,
    这无味的日子,
    眼泪是唯一的奢侈。

    我像是一个你可有可无的影子,
    冷冷地看着你说谎的样子,
    这撩乱的城市,
    容不下我的痴,
    是什么让你这样迷恋这样的放肆,
    我像是一个你可有可无的影子,
    和寂寞交换着悲伤的心事,
    对爱无计可施,
    这无味的日子,
    眼泪是唯一的奢侈。

    css 引入顺序

    今天同事利用CSS进行表格单元的背景切换,做个比较炫炫的结果,但是利用的CSS却不能修改。后来对css进行修改,发现了两个简单的原则:

    1:就进

      就进原则是指CSS的定义与引用元素的距离近,则引用近元素的属性。a1{ font-size:18pt;color:#00FF00} a2{font-size:24px;color:}

    <h1 class=”a1 a2”>11231</h1> 则使用了a2定义的属性。

    2:排外

        .sort .a{font-size:10px;color:red;}

        .a1{font-size;18px;}

    <div class=”sort”>

    <h1 class=”a a1”>123132</h1>则字体效果为size使用10px;color为红色。

    该处原则是指针对引用多个class时,如果存在想到的属性定义,则采取这两种原则。

    September 26

    Linux内核完全剖析--计算组成原理的介绍

    南桥芯片和北桥芯片的概念解释

    北桥芯片用于与CPU、内存和AGP视频接口,这些接口具有很高的传输速率。北桥芯片还起着存储器控制作用,因此Intel把该芯片标号为MCH(Memory Controller Hub)芯片。南桥芯片用来管理低、中速的组件,如PCI总线、IDE硬盘接口、USB端口等,因此南桥芯片的名称为ICH(I/O Controller Hub)。之所以用"南、北"桥来分别统称这两个芯片,是由于在Intel公司公布的典型PC主板上,它们分别位于主板的下端和上端(即地图上的南部和北部),并起着与CPU进行通道桥接的作用。

    image

    I/O端口寻址

    端口统一编址的原理是把I/O控制器中的端口地址归入存储器寻址地址空间范围内。因此这种编址方式也称为存储器映像编址。CPU访问一个端口的操作与访问内存的操作一样,也使用访问内存的指令。

    端口独立编址的方法是把I/O控制器和控制卡的寻址空间单独作为一个独立的地址空间对待,称为I/O地址空间。每个端口有一个I/O地址与之对应,并且使用专门的I/O指令来访问端口。

    September 21

    KVM的失败

       今天去生产线部署环境,发现原来的程序竟然连接不上了KVM。一时不知所措。后来想了想,与原来的环境有么区别呢?

    机器换了?还是同一个型号。网络环境改动了?原来是服务器和PC机直连,现在是搭建的局域网。于是用交换机重新部署了网络

    环境,竟然无果。

         于是,刷新firmware到1.0,刷新的时候是用u盘启动,在DOS下运行命令行。无论刷新到1.0.1,1.0.3,还是刷新到最新版的1.1

    ,结果还是无法连接。

         下午实在不行了,不在产线上用机器实验,于是用大库机器刷新firmware。利用web页刷新,竟然可以了。

    头疼!不知道是怎么个情况?

    去产线接着试下刚才的机器是否可以再次刷新到版本。

    而且用u盘和web各刷下一次。

    应该避免防止的几类网站攻击

    漏洞一:数据库下载漏洞

    第一步,搜索攻击目标

    打开搜索引擎,搜索“Pragram by Dlog”,可以找到许多博客页面,这些博客都是使用“Dlog破废墟修改版”建立的。我们要找的叶面是存在暴库漏洞的1.2版本。许多用户都忽视了这个版本中内嵌的eWebEditor在线编辑数据库的安全性,致使黑客可以使用默认的路径进行下载。

    第二步,获取管理员密码

    在搜索结果列表中挑一个攻击目标:(http://s*.8888.com/blog/),用浏览器打开这个地址,在后面加上eWebEditor/db/e/eWebEditor.mdb并回车,下载数据库。

    打开这个数据库,在数据库的“eWebEditor_system”列中可以看到管理员的用户名和密码。由于密码都是经过MD5加密的,因此找一个MD5密码暴力破解器计算机分钟或几天,就可得到密码。不过据经验,只要能下载这个数据库,就说明管理员极有可能没有更改默认的登陆密码,如果看到MD5密码为“7a57a5a743894a0e”,那么密码就是默认的“admin”。现在,我们可以进入eWebEditor后台在线编辑页面了。

    第三步,控制服务器

    在博客的地址后加上“eWebEditor/admin_login.asp”即可打开eWebEditor后台在线编辑页面。输入默认的用户名和密码“admin”即可顺利登陆博客的后台管理页面。

    新添加一个博客样式,返回样式管理页面。在样式列表中找到刚才添加的样式,并点击样式名后的“设置”按钮,就可使用新的博客样式。

    退出管理页面后进行注册并登陆博客,然后发一篇帖子并选择上传文件,此时我们可以上传ASP木马以便控制整个服务器。

    漏洞二:文件上传漏洞

    第一步,搜索存在漏洞的博客

    找到任意一个目标后,首先要测试博客管理员是否将上传网页程序文件删除了,如果用户有一些安全意识,有可能会将默认的上传网页文件删除掉,这时就不行了。

    我们选“http://www.88888.net/workingbird” ,在地址后添加“/upfile.asp”后回车,如果看到的提示信息为“Microsoft VBScript运行时错误 错误‘800a01b6’”之类的信息,表示该博客网站存在着文件上传漏洞,详情您可以点击数据库安全软件他可以帮你解决所有的有的安全隐患。

    第二步,展开攻击

    运行“网站上传利用工具”,在“提交地址”中输入upfile.asp上传文件的所在地址,然后在“上传路径”中指定上传木马文件后的保存路径,我们一般将它保存在网站根目录下。“路径字段”和“文件字段”使用默认的设置就可以了,在“允许类型”中输入博客系统允许上传的图片类型。在“本地文件”后点击“浏览”选择本地的一个ASP木马,可以选择海洋顶端网木马。

    现在点击“提交”按钮,即可上传木马,如果看到信息“1 file had been uploaded!”,则表示文件上传成功。接下来,我们就可以连接上传后的ASP木马进一步渗透攻击,达到控制整个网站服务器的目的。

    漏洞三:SQL注入漏洞

    第一步,扫描博客中的注入漏洞

    以博客“http://202.112.*.***/dlog/”作为目标。可以使用工具(如NBSI 2 SQL自动注入攻击器)进行SQL注入。运行程序,点击工具栏中的“网站扫描”,在“网站地址”中输入博客网址,勾选“全面扫描”项,点击“扫描”后,就可以对博客网站中存在的所有注入漏洞进行扫描。

    第二步,开始攻击

    在扫描结果列表中任意选一个目标“http://202.112.*.***/dlog/showlog.asp?log_id=402”,然后点击界面下方的“注入分析”进入“注入攻击”页面。点击“检测”按钮,结果显示“赞为监测到注入漏洞”!

    不要紧,我们用1=1检测法。在注入浏览器地址栏中的末尾分别加上“and 1=1”和“and 2=2”,查看两者返回页面的信息中有什么不同。并记下在“and 1=1”页面中出现过,但是在“and 2=2”中未出现过的字符串,并将其输入NBSI 2界面的“特征字符串”。

    现在点击“再检测”,很快就可看到注入检测的结果。由于数据库是Access数据库,所以程序会自动猜解数据库中的表名和列名,点击窗口中的“自动猜解”,即可猜测可能存在的数据库表名,默认的表名为“user_mdb”。再利用自动猜解得到表中的列名等数据信息。然后自动猜解表中的用户数据,从而得到管理员的MD5加秘密码。最后使用MD5密码破解工具暴力破解,登陆后台管理页面,成功入侵。

    漏洞四:cookies欺骗漏洞

    第一步,搜索目标

    搜索关键词“Powered by L-Blog”,选择“http://***.*****.***/blog”作为攻击目标。

    第二步,查询cookies信息

    这里要用到一款可以修改cookies信息的工具。打开程序,输入博客网站的地址并登陆,查看当前的cookies信息,其中包含了我们的登陆用户名和密码等信息。

    第三步,“欺骗”攻击

    现在要对cookies信息进行修改,欺骗博客程序,使它以为登陆用户的身份是管理员。此时可直接对cookies信息进行修改。

    我们只修改“menStatus=SupAdmin”,其它内容保留,然后继续保持工具栏中的“锁”为按下状态。现在,退出当前的用户登陆状态,重新打开该博客首页。此时会显示我们没有登陆,然而我们已经拥有了管理员的权限。

    September 11

    一首《花沙》,

    记忆里的琥珀色仲夏
    藏著你我 多少年华
    曾在屋顶结下的誓言
    被风一吹就落下

    那些不分场合的情话
    拥抱之后 生根发芽
    奋不顾身 以为能到达

    夜深人静 反复纠缠的牵掛
    空荡的心 需要解答
    随风起舞的残花 不停追逐的黄沙
    多大代价 才能挣脱 思念的篱笆
    近在咫尺的天涯 在你的脚下
    沙守着花 花开的潇洒

    第一次听着这首歌,无所谓的视听。

    昨夜再一遍的仔细的听这首歌,原来反复纠缠的牵挂,心都空荡了。

    残花,黄沙,意境到了西风,瘦马的天下。

    在这个城市里,孤独的一个人排除着自己的不甘与压抑。

    呵呵,一切都消失了

          用笑容去面对

          人生不过如此

          哪怕失去生命

         我们也要学会一脸坦然

        

     

          如果真的在惜他

         就不会做让他伤心的事情

    September 10

    基地实施

    心情的低落,永远写在自己的脸上;

    无名的伤痛,狠狠的刺在自己心里;

    嘴上的不是,可是最明白的还是我们的心;

    不经意的流露的不耐烦,谁人都能看的明白;

    什么事情都有那么多理由推搡,可是

    反问我们自己的心,真的是那样吗?

    听着讲故事,也有一种心酸;

    因为自己不在故事里;

    就像一场角逐的爱情,

    自己不能参与,

    是多么的无奈。

            什么时候可以让爱情不自私?也许真的等到我的头像永远变灰了,心里就不会心酸了,

    因为心停止了跳动,脑袋停止了跳跃,人也开始在慢慢融化,直至消失在这个世界。

    生命当珍惜,一个生命一个世界。

    当一个世界消失的时候,真的希望能有个世界还残留着自己的印迹;

    命运注定的悲苦,也许必定要经历。

    不死不休。

    September 08

    伤感语句——最伤感的爱情语句


      你可以用一分钟遇见一个人用一小时了解一个人用一天爱上一个人但是你却要用一辈子忘记一个人

      有谁不曾为那暗恋而受苦?我们总以为那份痴情很重、很重,是世上最重的重量。有一天,募然回首,我们才发现,它一直都是很轻、很轻的。

      在遇到梦中人之前,上天也许会安排我们先遇到别人;在我们终于遇见心仪的人时,便应当心存感激。

      爱是一种感受,即使痛苦也会觉得幸福;爱是一种体会,即使心碎也会觉得甜蜜;爱是一种经历,即使破碎也会觉得美丽。爱上你只是一时,忘掉你需要一生。不管你是否还记得我,在你心里,永远有一滴我为爱你而流下的泪水,永远永远在那里…

      总是需要一些温暖。哪怕是一点点自以为是的纪念。不愿放开手不愿让你走不愿眼睁睁地看你走出我的生活。。。。

      在茫茫人海中,相遇,相知,相守,无论谁都不会一帆风顺,只有一颗舍得付出,懂得感恩的心,才能拥有一生的爱和幸福。
      想要说些什么,却无从说起,想要说声爱你却被风吹散。如果大海能换回曾经的爱我用一生等待

      每一个女孩都曾经是一个无泪的天使,当她遇上心爱的男孩时便有了泪,天使落泪,坠落人间,所以每一个男孩都不能辜负他的女孩,因为她曾经为了你,放弃了整个天堂。

      看见天空云朵厚重起伏,不可限量。曰光照耀不留余地。这种力量生生不熄。这仿佛在一场长眠之后,醒来时,嗅到新生的气息,感到洁净无比。可是一切不过一时,我们暗自承受,或者一世空虚,我们义无返顾。

      如果这是一场梦,就请让我永远不要再醒来。几乎所有童话的开端,都是从王子与公主,一场美丽的邂逅开始。我们一边埋怨著故事的俗套,一边心甘情愿的跳了下去,痴迷不可自拔。。

      当昨曰的梦已无法还原,当你再扶不起一丝记忆的幼苗,当你执意的步点踩痛我离别的视线,你知道我在等你吗?等你遗忘,等你不再回首从前一声坦诚的祝福,等你在我点亮所有的灯笼、满世界寻找又一个你时,你已化成一帘幽梦,轻轻地唤我!

      珍惜身边所有的一切事物!生活不是电影,错过了就是失去了、没有了,不可能像电影里一样有重新再来一次的机会,或许一次的错过就会让我们悔恨终身……

      初恋是美丽的。。。它的味道。。甜的。。酸的。。苦的。。涩的。。。。。。但不论它的味道如何。。。永远都是幸福的。。。。你是否想起了你的初恋了呢?。。。

      偶然认识他。偶然爱丄他。偶然幻想中拥有他。偶然失去他。偶然想恨他。偶然发现该恨他的魜不属于自己。。

      不知悲伤从何而来不得不爱,否则我就失去未来好象身不由己,不能自己很失败可是每天都过的精彩~~~━☆而是用你的心温暖我的手

      再多的困惑……再复杂的结果,一切都只不过是个选择——该忘记的,就让一切随风飘散;该珍惜的,就好好把握用心铭记;对别人好一点,也对自己好一点

      爱你的时候,未曾发觉;恨你的时候,才知道原来爱你那麽多!

      想说未说的无语,山盟海誓的词句,分别之际的泪滴,你都已忘记……但请告诉我,你能否忘记——那次朦朦胧胧的相遇,那个突然开始的忧郁……

      人,总是在不断地在舍取中矛盾中生活着。或许,有些感情只有错过了,才可以刻骨铭心,那些曾经的过往,在我们心里已是永恒。。。。。。

      尘世间最遥远的距离不是我站在你面前,却不知道我爱你;而是明明知道彼此相爱,却不能在一起。

      那不是彻夜等候你为我点的烛火,当我睁开双眼每一天,都会记得大家的笑脸,明白心中勇敢又多了一点,用音符画一个圈,经过都会被纪念,我想爱永远会留在你心间

      每个人都有属于自己的一片森林,也许我们从来没走过,但它一直在那里,迷失的人迷失了,相逢的人会再相逢。我相信美好的相遇,因为我们的生命是那样美丽生动。我们拥有的每一个遇见,都是上帝的垂爱。

      如果有如果,是否能回到曾经;如果有如果,我能不能再爱你一次;如果有如果,幸福是否依旧……但,一切的一切,只是如果……

      相识是最珍贵的缘份,思念是最美丽的心情,牵挂是最真挚的心动,问候是最动听的语言,知己是最贴心的默契。

      放弃一个人比爱一个人还要难,而要想彻底的忘掉他就会更难~!!!

      爱,永远是没有永恒的定义因为每个人的体会和感悟不同,爱很美,却也有褪去的时候,就如一场烟火,只留下短暂的美丽。。。在蓦然回首的刹那,没有怨恨的青春才会了无遗憾!擦肩而过,否则爱情会因为距离而成为一种传说!!!

      分手是必然的,因为我们不在一起了。以前我都脑子里都是你,但我现在却要忘记你。我不再想你,但你真的爱过我吗?我已把你忘记,我不再恋你,我的心里现在只有他,我以爱上他````

      比别人多一点或是少一点的都是幸福。曾经我们的思维和处世方式影响了我们对幸福的感知能力。幸福经不起你刻了一把尺子去量,它有一颗比磨难更敏感的心,稍对它挑剔,它就弃你而去。要获得幸福并不难—对他人,对自己,对生活宽容些,幸福就藏在你心里。

      盼望你没有为我又暗中淌泪,我不想让你的心空虚,盼望我别去后会与你在远方相聚,我的心如水,每一天望着远方,盼望你的突然出现,是缘是情是童真还是意外,多少春秋风雨也改变不了我对你的爱恋~~~~

      走得很急的都是最美的风景,伤得最最深的总是那些最最真的感情。我一直一直以为,自己可以承受这一天的到来,可当真面对,才知道自己也不过是个需要疼爱的女人。痴心的等待能唤回一个已经背叛的心吗?我只能用面具来遮掩自己的伤痛

      对的时间,遇见对的人,是一种幸福。对的时间,遇见错的人,是一种悲哀。错的时间,遇见对的人,是一声叹息。错的时间,遇见错的人,是一种无奈。

      回忆的画面记录的语言载着我的想念飞过了地平线你温暖的笑脸还一如从前回忆的画面记录的语言眼泪试我心中另一种完美

      想与你去画画用我们的心来画一幅属于我们的画不在乎它是酸是甜是苦是辣有你的时光那就是我的黄金时光不在乎它是否一生一世是否海枯石烂是否完美无暇是否炫眼夺人有你的曰子就是我最快乐的曰子

      面对你,我总是一笑而过;面对你,我总是默默无闻;面对你,我总是晕头转向;面对你,我总是费劲心思;面对你,我总是喋喋不休;面对你,我总是察言观色;面对你……

      回忆★是一种很奇妙☆的东西,它可以↑※让我想起曾经快乐的时光§,但它也让我&◆~~想起了许多伤心的往事

      是什么淋湿了我的眼睛,看不清你远去的背影,是什么冰冷了我的心情,握不住你从前的温馨,是雨声喧哗了我的安宁,听不清自己哭泣的声音,是雨伞美丽了城市的风景留不住身边匆忙的爱情,谁能用爱烘干我这颗潮湿的心。

      她哭了,泪水一滴一滴的落下。她失去了以往的阳光,失去了以往的蓝,天空不满阴霾,灰沉沉的一片,压仰着的心就犹如天空一般。她在轻声抽泣着,用泪水将心中的不愉快释放,阳光总在风雨后,振作吧。哭泣将成历史,新一页也已翻开。

      太多的爱,淹没了所有的恨,原来重情多感,会活得很凄楚;吸食了别人的悲伤,我在静默中缓缓地流泪....

      若有一种爱是永不能相见,永不能启口,永不能在想起,就好象永不燃起的火种,孤独的凝望着黑暗的天空,但总有一颗心需要讲明,需要倾诉,需要将爱进行到最后一刻,才不枉此生

      爱情只是一种物质,想爱就爱,想恨就恨~没什么多大的区别,每个人都拥有爱情~只是看个人的想象~

      -*渐渐餦汏钌。。 丶宥些亊看懂钌′。 宥些人吔看清钌~。ˊ。但只能仿进惢裏。*|:﹏失佉菂〃吥能喠涞。''''

      有有些失去是注定的,有些缘分是永远不会有结果的,爱一个人不一定要拥有,但拥有了一个人就一定要珍惜,不要等到伤害的时候才去乞求原谅,不要等到失去的时候再去挽回。如果我不小心流下一滴泪水,那是因为我不愿意忘记你是谁

    注定我只是你生命里的印记

    如那片雪,

    从天空翻转身姿舞动着灵魂,

    翩然落缤纷  一股清凉润喉的清爽;

    如那云儿,

    在朗朗的宇宙下变幻着梦想,

    碧蓝映白帆  一阵风清云淡的飘渺;

    如那阵雨,

    在苍苍莽莽郁郁葱葱的树林,

    牵手水精灵  轻轻呢喃着美丽的传说;

    如黑暗中的光亮,如那架子鼓的韵律

    注定,一切都会被你忽视

    对你来说,一切只是过眼云烟

    变冷了?

    一份感情能经的起多久的考验

    一份心情能持续多少未知的日子

    当走过了一个个坎坷的道路时

    我们的心是否在为了坎坷而变化

    也许,变化是渐进的

    也许,感情是曲折的,就像人生的路

    可是感情是否也可以像人生一样长久呢

    心潮澎湃的时候,你会因它的一举一动而开心

    可是某一天,你看到它的时候

    心情没有变化,脸上没有笑容

    是不是感情就淡了呢

    这个时候的它不能给你带来快乐

    这个时候的它,在你眼里,好像变了

    能给你快乐的是别人

    它为你做的一百件事

    你觉着已经无所谓了

    不如一个陌生的新认识的人

    能让你开心

    也许这个时候的你

    对它已经真的冷淡了

    甚至不如一条陌生人的短信

    让你感觉莫名的激动、兴奋

    感情当没有了拥抱

    没有了语言

    还能剩下什么呢

    也许是你的心真的冷了

    在你眼里,它不在像从前那样可以让你开心

    当心潮澎湃过后,我以为感情得到是沉淀

    更加的深,更加的厚,更加的浓

    却发现像此时的天气

    变冷了

    可是天冷了,可以加件衣服

    感情呢?

    再次游泰山

    去泰山的时候,穿件长袖,坐在公交车上,感觉到还有那么点热;上午十一点左右到达岱庙北门,看着北门,心里浮想联翩,此情此景依稀在,但已物是人非。去年在岱庙门口停滞的时候,还是原来单位的一帮同事们,一群不错的同事,一群可以做哥们的人,一群让我可以永远铭记在心的人,是在他们的热心帮助下,从一个毛毛楞楞的刚出校门的青涩男孩,快速的成长,无论是技术还是做人,都得到了充分的进步;那个时侯登泰山,逛岱庙,心无旁贷,心里想的是让自己玩的开心,过的舒服。

    今年走到岱庙门口的时候,心里突然有了心酸的感觉,身旁仍然是一帮不错的同事,但是物是人非的感觉却在心里蔓延。中午十二点左右,所有同事到达岱庙门口,吃饭,虽然也是在传说的岱庙后门的美食小吃聚集处,而且美其名曰的御膳楼,不适应的饭菜口味,人民币没少用,不太实惠;饭后,逛岱庙,选择近地,直接从北门进入了岱庙。可能是阴雨天太多,此时的岱庙满处可以见青苔,地略滑。

    晚上烧烤,呵呵,泰安东的云海烧烤城,在一家东北烧烤,无烟烧烤,呵呵,看到东北烧烤想到大学时吃的烧烤,特有感觉,于是就进入了这家店,还不错,特别是他们的涮肚、五花肉、马步鱼,做的挺有味,便宜实惠,比中午节约了接近一半,呵呵,吃的全是肉食。

    宾馆住宿,为了节约费用,七个男生,两间房子,呵呵,有点挤,晚上有五个人打扑克,保皇持续到凌晨一点。周天凌晨四点起床,准备行头,走向红门,开始攀登。从红门到中天门,一路基本无景色,除了烧香的地方比较多,其他无景色。不过对我来说,逢庙需拜。

    从中天门到南天门,路途景色较多,可见毛泽东的题词,数风流人物还看今朝,看到了迎客松。十八盘是比较艰辛的一段路,呵呵,艰辛是因为其位置太高,体力消耗已经够多了,而且其台阶又窄,走起来要小心翼翼,提心吊胆的,所以特别显累。我是汗水流下估计得有一小脸盘,到升仙坊的时候,我已经感觉有缺水的滋味。恶补水啊。

    南天门,天街,大雾天气,也没看到什么景色,最终去了玉皇顶,感觉太累,偶也没上去,在五岳独尊石处做了个看报人,狂吃咸花生。

    下山比较快,呵呵,因为上次来的时候学会了如何在台阶上跑着下,呵呵,那速度简直了。

    人生也许就是这么反复的,上次泰山回去以后,没想到会再次来到泰山。不过上次泰山的景色要比这次漂亮,看到了日出,看到了云海,这次么也没看着,呼呼腾腾跑了一圈。

    September 03

    Decorator模式

     

    一、模式概述

    一个场景是我们要为一个对象动态添加新的职责,这个职责并不修改原有的行为,而是在原有行为基础上添加新的功能,就好比装饰工人为一座新居的墙上涂抹上色彩缤纷的颜料一般。
    从我们拥有的面向对象的知识出发,为一个对象增加新的职责,完全可以利用继承机制,然而再通过实例化派生的子类,来获得新增的职责。由于需要在原有行为基础上添加新功能,此时父类的方法应该为虚方法,例如用户登录行为:
    public class User
    {
    public virtual void SignIn()
    {
      Console.WriteLine("The User Sign In.");
    }
    }
    如果需要为用户登录行为增加权限验证的职责,可以定义一个子类继承User类:
    public class SecurityUser:User
    {
    public override void SignIn()
    {
      if (IsValid())
      {
       base.SignIn();
      }
      else
      {
       throw new NotAuthorizationException();
      }
    }
    private bool IsValid()
    {
      //略;
      return true;
    }
    }
    实现的类图如下: 

    image

    然而继承机制的一个局限是它只能静态地添加对象职责,一旦添加的职责有变,例如客户需求为登录行为添加日志记录功能,虽然我们可以再定义一个子类,重写SignIn()方法,然而我们却不能控制职责添加的时机与方式。此外,当User具有本身的继承体系时,则其并不能重用SecurityUser的职责。例如,User同时具有另外一个子类Employee,则Employee类的登录行为仍然沿用了其父类User的登录行为,而不具备权限验证的职责。如果需求要求Employee同样要验证登录权限,就必须再为它创建一个子类SecurityEmployee,如图:

    image

     

    这样的结果会导致类的数量会随着需求的变化而无限量的增加,同时有关权限验证的职责也没有能够得到充分的重用,这显然违背了面向对象设计的精神。
    还有一个添加职责的办法,就是利用组合,将原有的对象嵌入到一个新的类中,由此来完成对新职责的添加,例如:
    public class SecurityUser
    {
    private User m_user;
    public User User
    {
      get {return m_user;}
      set {m_user = value;}
    }
    public void SignIn()
    {
      if (IsValid())
      {
       m_user.SignIn();
      }
    else
      {
       throw new NotAuthorizationException();
      }

    }
    private bool IsValid()
    {
      //略;
      return true;
    }
    }
    实现的类图如下:

    image

    比起继承机制而言,组合方式更加的灵活,尤其当面对User具有自身的继承体系时,如上的设计不需要任何修改,就能从容的应对:

    image

    此时我们只需要将Employee对象赋给SecurityUser中的User属性就可以实现对Employee权限验证的登录。因此,我们避免了此前采用继承机制所面临的两个问题:
    1、 类的无限量增加(所谓的“类爆炸”);
    2、 权限验证职责的不可重用。
    然而组合却失去了继承的许多优势,其中,不具备对象的多态特质,就是最大的一个局限。例如,如下创建对象的方式就是错误的:
    User user = new SecurityUser();
    当一个方法体现为对User的操作时,此时SecurityUser就无法对User类型的对象进行替代,这就限制了软件的可扩展性。例如,在表示层逻辑中,会有一个登录页面将调用SignIn方法:
    public class LoginPage
    {
    public static void SignIn(User user);
    }
    在这种情况下,SecurityUser对象就无法做为参数传入,那么,我们在前面所作的职责添加的努力岂不就是付诸东流了吗?
    如果仔细观察继承与组合的优劣,我们发现如果将继承机制与组合方式两者结合起来,将会起到意想不到的效果,此时,各自的优点弥补了各自的缺点,完美地解决了“为对象动态添加新的职责”的需求。
    新的解决方案如下图所示:

    image

    实际上,如上的类图结构就是设计模式中的Decorator模式,User是被装饰的对象,而SecurityUser则是Decorator,也就是我们所谓的“装饰工”。在这里,SecurityUser是一个具体类,如果有新的装饰需求,例如之前提到的增加日志记录功能,同样需要建立装饰类。此时,对于具体的装饰类而言,具有一些相同的逻辑,在此前提下,可以为其增加一个Decorator抽象类:

    image

    此时,我将原来的SecurityUser类更名为SecuritySignInDecorator,便于理解。SignInDecorator是一个抽象类,继承了User类,同时User类对象又作为一个属性存在于SignInDecorator抽象类中。注意,这里的组合方式其实有多种实现方式。如作为一个属性,或者作为构造函数的参数等等。
    抽象类SignInDecorator的代码如下所示:
    public abstract SignInDecorator:User
    {
    private User m_user;
    public User User
    {
      get {return m_user;}
      set {m_user = value;}
    }
    public override void SignIn()
    {
      if (m_user != null)
      {
       m_user.SignIn();
      }
    }
    }
    而SignInDecorator的子类定义则如下:
    public class SecuritySignInDecorator:SignInDecorator
    {
    public override void SignIn()
    {
      if (IsValid())
      {
       base.SignIn();
      }
      else
      {
       throw new NotAuthorizationException();
      }
    }
    private bool IsValid()
    {
      //略;
      return true;
    }
    }
    public class LoggingSignInDecorator:SignInDecorator
    {
    public override void SignIn()
    {
      base.SignIn();
      Logging(); 
    }
    private void Logging()
    {
      //略;
    }
    }
    目前的结构完全解决了前面利用继承或组合所出现的问题,避免了类的无限增加,权限验证或者日志记录的职责也能很好地重用,同时权限验证和日志记录等装饰类由于同样继承了User,因此根据多态原理,是可以完全替换User类型的对象的。
    此外,利用Decorator模式还可以解决动态组合装饰的问题,例如为SignIn()方法既添加权限验证功能,又添加日志记录功能,此时并不需要新增一个类。实现如下:
    User user = new User();
    SignInDecorator securtiyDec = new SecuritySignInDecorator();
    securityDec.User = user;
    SignInDecorator loggingDec = new LoggingSignInDecorator();
    loggingDec.User = securityDec;
    loggingDec.SignIn();
    loggingDec.SignIn()方法执行的时序图如下:

    image

    从时序图中可以看到,当我们调用LoggingSignInDecorator对象的SignIn()方法时,因为LoggingSignInDecorator对象的User属性值为SecuritySignInDecorator对象,所以将执行SecuritySignInDecorator对象的SignIn()方法,该方法会先执行IsValid()私有方法,然而再调用User属性对象的SignIn()方法。由于SecuritySignInDecorator的User属性值为User对象,因此执行User对象的SignIn()方法。待SignIn()方法执行完毕,最后再执行LoggingSignInDecorator对象的Logging()方法。
    注意上述的时序图,如果在LoggingSignInDecorator对象的SignIn()方法中,Logging()方法放在base.SignIn()前,则应该先执行Logging()方法,然后才是SignIn()方法。
    不需要添加新的Decorator对象,通过上述的实现方式,我们就轻易地完成了对User对象SignIn()方法权限控制和日志记录的装饰。

    September 02

    中国孩子“没良心”

    “都说三岁定八十,说的就是我这样的情况。我从三岁就已经不再听大人的话,顽皮得不得了,五岁就用菜刀对着我妈——晚上要按时回家?想都不要想,反正可以过夜的地方多了去了,家里不收留还可以去外婆家、叔叔家。到十六岁那年谈恋爱,还有什么没试过?从那以后,很多事情已经看透了,已经知道不过如此,再也伤不了我……我叔叔可是把我像女儿一样疼爱的,还有我外婆,还有小姨子,现在看来,如果他们不是这样宠我,我应该也不会变成现在这样……”

    在工作日上午相当拥挤的巴士上听到一个女声在讲这么一篇独白,不知道别人会怎样,我是按捺不住好奇心,向声音的来源方向看过去。不出所料,看到跟那个清脆声音完全匹配的一个二十出头的女生,还穿一件粉红T恤,更像一个小孩。

    出人意料的是,这样一个看起来很普通的小女生,怎么会有这样一个故事,好像过的也是一种浓缩的生活,也准备写一部史诗?

    马上就显出自己的生活是多么按部就班。

    若说她的故事还有什么地方落了俗套,大概就是她认为父母以外的长辈对她过分宠爱,干扰了自己父母的管教,结果“变成现在这样”。

    怎么能把自己变坏或变得不尽符合自己的理想归咎于长辈呢?

    没良心的孩子们。

    同事的故事也差不多:妈妈打电话问儿子,今年儿子的生日快到了,有什么安排——往年是儿子一家回到父母家,三代同堂,一起吃饭庆祝——儿子说差点就忘了这事,又说今年干脆一家人出去吃饭吧,不用父母操心。到了儿子生日那天,妈妈打电话去他家,想问问晚上在哪里吃饭,却发现没人在家,这才意识到,原来儿子说的一起出去吃饭的“一家人”,并不包括自己,只限于儿子的小家庭。于是打电话跟远在他乡的女儿抱怨,还好女儿也做了妈妈,可以一边觉得好笑,一边耐心听完,说,你就死了这条心吧,对孩子还能有什么指望呢,他们不会一辈子吃你的、喝你的,就是你的运气啦。

    当时就觉得心虚,因为前一天刚好发生这么一件事:在出租车里听司机说那天拉了一位五十几岁的先生,以前就认识,看他头发都掉光了,一脸憔悴,问他怎么了,两个女儿都出来工作了,还有什么要操心。这才知道,原来人家的二女儿毕业以后,想在本地找一份教师工作,找来找去找不到,明明有职位,却都在推托,最后乖乖听从朋友的劝告,花十二万元搞定了,月薪也就三千多。

    “十二万!”当时我就惊呆了。

    “对啊,供她上大学花了十万多,找工作又要十二万,怪不得头发都掉光了。”出租车司机说。

    “十二万!”我说,因为当年上大学的学费再便宜,也是父母掏的,所以现在能说的只有自己找工作没花他们的钱这一件事,最多可能为他们节约了十二万,要不要奖励一下……

    当时还觉得自己一点也不贪心。

    没良心的孩子们。

    大概不管七零后、八零后还是九零后,在父母看来,都有机会变成前苏联一首流行歌曲的奇怪标题所说的:“从前你是这样,现在还是这样”。

    September 01

    修改localhost访问

    D:\WINDOWS\system32\drivers\etc\hosts  文件

    在Windows 98系统下该文件在Windows目录,在Windows 2000/XP系统中位于C:\Winnt\System32\Drivers\Etc 目录中。该文件其实是一个纯文本的文件,用普通的文本编辑软件如记事本等都能打开。
    用记事本打开hosts文件,首先看见了微软对这个文件的说明。这个文件是根据TCP/IP for Windows 的标准来工作的,它的作用是包含IP地址和Host name(主机名)的映射关系,是一个映射IP地址和Host name(主机名)的规定,规定要求每段只能包括一个映射关系,IP地址要放在每段的最前面,空格后再写上映射的Host name(主机名)。对于这段的映射说明用“#”分割后用文字说明。
    现在让我们来看看Hosts在Windows中是怎么工作的。
    我们知道在网络上访问网站,要首先通过DNS服务器把网络域名(www.XXXX.com)解析成61.XXX.XXX.XXX的IP地址后,我们的计算机才能访问。要是对于每个域名请求我们都要等待域名服务器解析后返回IP信息,这样访问网络的效率就会降低,而Hosts文件就能提高解析效率。根据Windows系统规定,在进行DNS请求以前,Windows系统会先检查自己的Hosts文件中是否有这个地址映射关系,如果有则调用这个 IP地址映射,如果没有再向已知的DNS服务器提出域名解析。也就是说Hosts的请求级别比DNS高。

    知道了Hosts文件的工作方式,那在具体使用中它有哪些作用呢?
    1、加快域名解析
    对于要经常访问的网站,我们可以通过在Hosts中配置域名和IP的映射关系,这样当我们输入域名计算机就能很快解析出IP,而不用请求网络上的DNS服务器。
    2、方便局域网用户
    在很多单位的局域网中,会有服务器提供给用户使用。但由于局域网中一般很少架设DNS服务器,访问这些服务要输入难记的IP地址,对不少人来说相当麻烦。现在可以分别给这些服务器取个容易记住的名字,然后在Hosts中建立IP映射,这样以后访问的时候我们输入这个服务器的名字就行了。
    3、屏蔽网站
    现在有很多网站不经过用户同意就将各种各样的插件安装到你的计算机中,有些说不定就是木马或病毒。对于这些网站我们可以利用Hosts把该网站的域名映射到错误的IP或自己计算机的IP,这样就不用访问了。我们在Hosts写上以下内容:
    127.0.0.1 #屏蔽的网站
    0.0.0.0 #屏蔽的网站
    这样计算机解析域名就解析到本机或错误的IP,达到了屏蔽的目的。
    4、顺利连接系统
    对于Lotus的服务器和一些数据库服务器,在访问时如果直接输入IP地址那是不能访问的,只能输入服务器名才能访问。那么我们配置好Hosts文件,这样输入服务器名就能顺利连接了。
    最后要指出的是,Hosts文件配置的映射是静态的,如果网络上的计算机更改了请及时更新IP地址,否则将不能访问。

    August 26

    vmware虚拟机咋就那么难呢

    前几天实现的虚拟化环境,今天实现Ha,发现其中一台机器重启竟然启动不起来。

    具体环境如下:

    两台机器安装了ESX 虚拟主机,一台存储服务器。建立的ISCSI存储作为共享存储。

    刚一开始建立以后,系统运行正常,呵呵,安装三个虚拟机作为系统应用。想实验室HA功能,

    重启其中一台机器,等待n久之后,竟然发现机器不能正常启动了,也没看到界面。

    后来就把另一台机器重启,发现load scsi_nfs successfully时,停止不动。

     

    郁闷大了,搞了很长时间,也没搞出来。

    August 21

    windows下双网卡双网关的设置

    双网卡双网关的设置

    工作中遇到双网卡双网关的问题,经过查询和实践,设置好后做个笔记记录,具体如下:

    单位安装的瑞星网络版服务器,一方面服务器本身需要上互联网即时更新病毒库,另一方面内网的机器又需要到服务器上更新病毒库。这就需要在反病毒服务器上安装二块网卡,并连接二个不同的网络。

    网络A(互联网)IP:221.231.X.134 子网掩码:255.255.255.248 网关:221.231.X.129

    网络B(局域网):172.32.18.XXX 子网掩码:255.255.0.0 网关:172.32.1.1

    现设置如下:

    将网络A(互联网)设好固定IP,将网关设为221.231.X.129;网络B(局域网)设好固定IP,将网关留空。

    二个网卡要将网卡A的网关设为默认网关,即将网卡A的跃点设为1,就可设为默认网关了。(跃点设置具体为:在TCP/IP的高级属性里,去掉窗口下部的“自动跃点计数”前的小勾,并填写1即可)

    在CMD下输入route print 后面显示的默认网关就改为了221.231.X.129

    Default Gateway:       221.231.X.129
    ===========================================

    接着,再增加一条路由命令就OK了

    进入CMD,运行:

    route -p add 172.32.0.0 mask 255.255.0.0 172.32.1.1 metric 30

    (意思是将172开头IP包的路由网关设为172.32.1.1,-p 参数代表永久写入路由表,如果不加此参数,每次机器重启后设置会丢失,要重新设置。)

    同时启用两个网卡,两个网关可以同时起作用了,两个子网也可以同时访问了,加了参数-P后关机重启也不用重设,是不是很方便呢?