<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Fwolf&#039;s Blog</title>
	<atom:link href="http://www.fwolf.com/blog/feed" rel="self" type="application/rss+xml" />
	<link>http://www.fwolf.com/blog</link>
	<description>随心·随意·随缘·努力～</description>
	<lastBuildDate>Wed, 02 Jul 2014 09:16:46 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.3.2</generator>
	<item>
		<title>配置 Nginx 子域名的泛解析</title>
		<link>http://www.fwolf.com/blog/post/453</link>
				<comments>http://www.fwolf.com/blog/post/453#respond</comments>
				<pubDate>Wed, 02 Jul 2014 09:16:00 +0000</pubDate>
		<dc:creator><![CDATA[Fwolf]]></dc:creator>
				<category><![CDATA[Server]]></category>
		<category><![CDATA[domain]]></category>
		<category><![CDATA[Nginx]]></category>
		<category><![CDATA[subdomain]]></category>
		<category><![CDATA[wildcard]]></category>

		<guid isPermaLink="false">http://www.fwolf.com/blog/?p=453</guid>
				<description><![CDATA[简单记录： 需求描述 Web 服务器为 Nginx，希望配置泛子域名解析。 其实稍加修改，配置泛域名解析也不是难事。 不影响主域名，domain.com 和 www.domain.com 的 root 依然为 www 目录 子域名 sub.domain.com 的 root 希望放在 www-sub 目录下，其他子域名同理 解决及分析 在 Nginx 的配置文件中做如下配置（示意）： server { server_name domain.com www.domain.com *.domain.com ; set $subdomain ''; if ($host ~* (\b(?!www\b).+)\.domain.com) { set $subdomain -$1; } root /home/user/www$subdomain/; } 解释： 首先，在定义 server_name 时使用通配符 * ，使 Nginx 接受任意子域名的访问。 &#8230; <a href="http://www.fwolf.com/blog/post/453" class="more-link">Continue reading <span class="screen-reader-text">配置 Nginx 子域名的泛解析</span></a>]]></description>
								<content:encoded><![CDATA[<p><!-- -*- mode: rst -*- --> <!-- -*- coding: utf-8 -*- --></p>

<p>简单记录：</p>

<div class="section" id="id1"> <h3>需求描述</h3> <p>Web 服务器为 Nginx，希望配置泛子域名解析。 其实稍加修改，配置泛域名解析也不是难事。</p> <ul class="simple"> <li>不影响主域名，domain.com 和 www.domain.com 的 root 依然为 www 目录</li> <li>子域名 sub.domain.com 的 root 希望放在 www-sub 目录下，其他子域名同理</li> </ul> </div>

<div class="section" id="id2"> <h3>解决及分析</h3> <p>在 Nginx 的配置文件中做如下配置（示意）：</p> <pre lang='ini'>
    server {
        server_name
            domain.com
            www.domain.com
            *.domain.com
        ;

        set $subdomain '';
        if ($host ~* (\b(?!www\b).+)\.domain.com) {
            set $subdomain -$1;
        }

        root    /home/user/www$subdomain/;
    }
</pre><p>解释：</p> <p>首先，在定义 server_name 时使用通配符 <tt class="docutils literal">*</tt> ，使 Nginx 接受任意子域名的访问。</p> <p>然后，对 <tt class="docutils literal">$host</tt> 进行分析，找到子域名的名称。 这个正则表达式是在网上抄的，目的是为了在匹配子域名的同时， 不匹配 www 开头的访问和不带 www 的访问。 前面的 set 是因为 Nginx 的 If 没有 Else，所以默认先将 <tt class="docutils literal">$subdomain</tt> 置空。</p> <p>最后，在定义 root 的时候，使用 <tt class="docutils literal">$subdomain</tt> 变量。</p> <!-- Substitution definitions for links --> <!-- Hyperlink targets --> </div>

<div class="wp_rp_wrap  wp_rp_twocolumns" id="wp_rp_first"><div class="wp_rp_content"><h3 class="related_post_title">Related Posts</h3><ul class="related_post wp_rp"><li data-position="0" data-poid="in-336" data-post-type="none"><small class="wp_rp_publish_date">2007-07-04</small> <a href="http://www.fwolf.com/blog/post/336" class="wp_rp_title">GoDaddy的帐号自动锁定</a></li><li data-position="1" data-poid="in-332" data-post-type="none"><small class="wp_rp_publish_date">2007-06-14</small> <a href="http://www.fwolf.com/blog/post/332" class="wp_rp_title">从万网转出域名成功</a></li><li data-position="2" data-poid="in-47" data-post-type="none"><small class="wp_rp_publish_date">2013-05-18</small> <a href="http://www.fwolf.com/blog/post/47" class="wp_rp_title">原来 netctl 是这样选择 profile 的</a></li><li data-position="3" data-poid="in-33" data-post-type="none"><small class="wp_rp_publish_date">2012-12-11</small> <a href="http://www.fwolf.com/blog/post/33" class="wp_rp_title">PHP foreach 中使用引用的注意事项</a></li><li data-position="4" data-poid="in-423" data-post-type="none"><small class="wp_rp_publish_date">2013-10-06</small> <a href="http://www.fwolf.com/blog/post/423" class="wp_rp_title">防火墙的目标地址转换和源地址转换</a></li><li data-position="5" data-poid="in-416" data-post-type="none"><small class="wp_rp_publish_date">2013-07-10</small> <a href="http://www.fwolf.com/blog/post/416" class="wp_rp_title">在U盘上安装 Arch Linux (2013-07)</a></li></ul><div class="wp_rp_footer"><a class="wp_rp_backlink" target="_blank" href="http://www.sovrn.com/" rel="nofollow">Sovrn</a></div></div></div>
]]></content:encoded>
							<wfw:commentRss>http://www.fwolf.com/blog/post/453/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>Git subtree 要不要使用 &#8211;squash 参数</title>
		<link>http://www.fwolf.com/blog/post/246</link>
				<comments>http://www.fwolf.com/blog/post/246#comments</comments>
				<pubDate>Tue, 22 Oct 2013 05:32:08 +0000</pubDate>
		<dc:creator><![CDATA[Fwolf]]></dc:creator>
				<category><![CDATA[SCM]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[GitHub]]></category>
		<category><![CDATA[Gregarius]]></category>
		<category><![CDATA[MagpieRSS]]></category>
		<category><![CDATA[squash]]></category>
		<category><![CDATA[subtree]]></category>

		<guid isPermaLink="false">http://www.fwolf.com/blog/?p=246</guid>
				<description><![CDATA[在 上一篇文章 中把 Snoopy 理顺了， 其实 Gregarius 使用的是 MagpieRSS， 而 MagpieRSS 又使用了 Snoopy， 是一个两层的包含关系。 Git submodule 的繁琐似乎是世人皆知了， 所以我用 subtree 来解决上面的包含关系。即： 在 Gregarius 中以 subtree 的方式管理 MagpieRSS， 然后在 MagpieRSS 中以 subtree 的方式管理 Snoopy。 问题的产生 subtree 处理多层包含是没有问题的，因为包含进项目之后， 别人根本看不出这是一个 subtree， 所以它本质上还只是管理本地 repo 的一种方法。 使用 Git subtree 新建或更新子项目的时候，可以选用 --squash 参数， 它的作用就是把 subtree 子项目的更新记录进行合并，再合并到主项目中。 所以，在使用 --squash 参数的情况下， subtree add 或者 &#8230; <a href="http://www.fwolf.com/blog/post/246" class="more-link">Continue reading <span class="screen-reader-text">Git subtree 要不要使用 &#8211;squash 参数</span></a>]]></description>
								<content:encoded><![CDATA[<p><!-- -*- mode: rst -*- --> <!-- -*- coding: utf-8 -*- --></p>

<p>在 <a class="reference external" href="269">上一篇文章</a> 中把 Snoopy 理顺了， 其实 <a class="reference external" href="https://github.com/fwolf/gregarius">Gregarius</a> 使用的是 MagpieRSS， 而 MagpieRSS 又使用了 Snoopy， 是一个两层的包含关系。</p>

<p>Git submodule 的繁琐似乎是世人皆知了， 所以我用 subtree 来解决上面的包含关系。即： 在 <a class="reference external" href="https://github.com/fwolf/gregarius">Gregarius</a> 中以 subtree 的方式管理 MagpieRSS， 然后在 MagpieRSS 中以 subtree 的方式管理 Snoopy。</p>

<div class="section" id="id2"> <h3>问题的产生</h3> <p>subtree 处理多层包含是没有问题的，因为包含进项目之后， 别人根本看不出这是一个 subtree， 所以它本质上还只是管理本地 repo 的一种方法。</p> <p>使用 Git subtree 新建或更新子项目的时候，可以选用 <tt class="docutils literal"><span class="pre">--squash</span></tt> 参数， 它的作用就是把 subtree 子项目的更新记录进行合并，再合并到主项目中。</p> <p>所以，在使用 <tt class="docutils literal"><span class="pre">--squash</span></tt> 参数的情况下， subtree add 或者 pull 操作的结果对应两个 commit， 一个是 Squash 了子项目的历史记录， 一个是 Merge 到主项目中。</p> <p>这种做法下，主项目的历史记录看起来还是比较整齐的。 但在子项目有更新，需要 subtree pull 的时候，却经常需要处理冲突。 严重的，在每次 subtree pull 的时候都需要重复处理同样的冲突，非常烦人。</p> <p>如果不使用 <tt class="docutils literal"><span class="pre">--squash</span></tt> 参数，子项目更新的时候，subtree pull 很顺利， 能够自动处理已解决过的冲突，缺点就是子项目的更新记录“污染”了主项目的。</p> </div>

<div class="section" id="id3"> <h3>原因分析</h3> <p>简单说，subtree add/pull 操作中，需要用到 merge，而 merge 顺利进行的前提， 是要有相同的 parent commit。对照上面的情况：</p> <p>使用 <tt class="docutils literal"><span class="pre">--squash</span></tt> 参数，原子项目历史记录被合并后就消失了，相当于一个“新”的提交。 下次再进行 add/pull 时，新添加的内容找不到“上一次的修改”， 于是在更新 subtree 内文件的时候，就会提示冲突，需要手工解决。</p> <p>不使用 <tt class="docutils literal"><span class="pre">--squash</span></tt> 参数，原子项目的历史复制到了父项目中， 下次再进行 add/pull 时，新增的 commit 能够找到“上一次的修改”， 那么他会像在子项目中逐个 am patch 那样更新 subtree 下的内容， 不会提示冲突。</p> <p>注：我使用的 Git subtree 是 PPA 上的一个 <a class="reference external" href="https://launchpad.net/~ivan1986/+archive/ppa/+build/3214310">旧版本</a> ， 或许新版已经解决了上面的问题。</p> </div>

<div class="section" id="id5"> <h3>解决问题</h3> <p>就像 <a class="reference external" href="http://psionides.eu/2010/02/04/sharing-code-between-projects-with-git-subtree/">这篇文章</a> 结尾说的那样，是否使用 squash 都是可以的， 但需要在开始阶段作出选择，并 <strong>一直坚持下去</strong> 。 如果一会儿用一会儿不用，得到的不是两者的优点，而是两者的缺点之和。</p> <p>出于个人偏好，我既希望能够比较顺利的更新子项目， 又不希望子项目的历史记录直接合并在主项目中。StackOverflow 上有人提到了 <a class="reference external" href="http://stackoverflow.com/questions/9777564">一种做法</a> ， 就是另外建立一个分支进行 &#8211;no-squash 的 subtree 更新， 这样就保留了子项目的历史记录，没有烦人的反复冲突问题； 然后在合并到主分支（比如 master）时合并提交（ <tt class="docutils literal">git merge <span class="pre">--squash</span></tt> ）， 这样主项目的主分支上只会体现一个 commit， 比直接 <tt class="docutils literal">git subtree add/pull <span class="pre">--squash</span></tt> 还要简洁。</p> <p>这种做法也有缺点，但在能够接受的范围内：</p> <ul class="simple"> <li>新开分支的历史记录比较乱，无视吧</li> <li>新开分支与 master 分支不同步，记着每次在新开分支上做 subtree 操作之前 要 merge master</li> </ul> <p>在新开分支上进行 subtree split 操作是没有问题的。 merge master 以后，subtree push 操作也没有大问题， 也许刚开始会出现 push 被 reject 的状况。</p> <p>在这种情况下，可以先在本地 split 一份，比如 <tt class="docutils literal">git subtree split <span class="pre">-P</span> extlib/magpierss <span class="pre">-b</span> test <span class="pre">--rejoin</span></tt> ， 然后切换到这个 test 分支，可以看到之所以被 reject ， 是因为主项目的那个合并提交也被 split 出来了。 这里会麻烦一些，需要通过 rebase 操作，把这些合并的提交删掉， 换成合并内容包含的每个提交（用 pick HASH）。 成功之后，可以在这个分支直接 push 到 子项目： <tt class="docutils literal">git push remote_of_subtree branch_on_local:branch_on_remote</tt> ， 注意后面是指定将本地的哪个分支 push 进 remote 的哪个分支。 这次 push 会很顺利。 接下来再作一次正常的 subtree pull 就可以了， 下次再进行 subtree split 操作时， split 出来的临时分支和 remote 是一致的。</p> <p>通过上面 push 的例子可以看出，为了 split 和 push 顺利， 即使用了 subtree 分支， 如果能在 master 分支中保存子项目历史记录还是有好处的。 同时，我们还可以参考这个来决定 subtree 使用策略：</p> <ul class="simple"> <li>subtree 里面放外围项目，只接收更新，不发送更新， 那么无论是用 squash 还是用 subtree 分支都不麻烦。</li> <li>将一个大项目拆分成若干小项目， 那么最好不要用 squash，并且活用 subtree， 最好是所有提交都在主项目中作， 然后 subtree split 出子项目来发布， 子项目原则上不直接修改，即和上一条相反， 只向子项目发送更新，不从子项目接收更新。 Symfony2 使用的就是这种做法。</li> </ul> <p>总体上都有些麻烦，subtree 分支算不上是完美解决方法，但看起来好歹清爽了很多。</p> <p>&#64;link <a class="reference external" href="https://github.com/fwolf/magpierss">https://github.com/fwolf/magpierss</a></p> <p>&#64;link <a class="reference external" href="https://github.com/fwolf/gregarius">https://github.com/fwolf/gregarius</a></p> <!-- Substitution definitions for links --> <!-- Hyperlink targets --> </div>

<div class="wp_rp_wrap  wp_rp_twocolumns"><div class="wp_rp_content"><h3 class="related_post_title">Related Posts</h3><ul class="related_post wp_rp"><li data-position="0" data-poid="in-269" data-post-type="none"><small class="wp_rp_publish_date">2013-10-18</small> <a href="http://www.fwolf.com/blog/post/269" class="wp_rp_title">将 CVS 转到 Git 并和 Github 上 Fork 的项目合并</a></li><li data-position="1" data-poid="in-6" data-post-type="none"><small class="wp_rp_publish_date">2012-11-27</small> <a href="http://www.fwolf.com/blog/post/6" class="wp_rp_title">用 rst2wp 来写 WordPress</a></li><li data-position="2" data-poid="in-36" data-post-type="none"><small class="wp_rp_publish_date">2013-01-22</small> <a href="http://www.fwolf.com/blog/post/36" class="wp_rp_title">通过代理使用 GitHub</a></li><li data-position="3" data-poid="in-14" data-post-type="none"><small class="wp_rp_publish_date">2012-11-30</small> <a href="http://www.fwolf.com/blog/post/14" class="wp_rp_title">Git commit 注释格式</a></li><li data-position="4" data-poid="in-441" data-post-type="none"><small class="wp_rp_publish_date">2009-05-14</small> <a href="http://www.fwolf.com/blog/post/441" class="wp_rp_title">[Git]真正回滚已上传的更新</a></li><li data-position="5" data-poid="in-448" data-post-type="none"><small class="wp_rp_publish_date">2009-08-25</small> <a href="http://www.fwolf.com/blog/post/448" class="wp_rp_title">Git 合并 patch 时的冲突处理一例</a></li></ul><div class="wp_rp_footer"><a class="wp_rp_backlink" target="_blank" href="http://www.sovrn.com/" rel="nofollow">Sovrn</a></div></div></div>
]]></content:encoded>
							<wfw:commentRss>http://www.fwolf.com/blog/post/246/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
							</item>
		<item>
		<title>将 CVS 转到 Git 并和 Github 上 Fork 的项目合并</title>
		<link>http://www.fwolf.com/blog/post/269</link>
				<comments>http://www.fwolf.com/blog/post/269#respond</comments>
				<pubDate>Thu, 17 Oct 2013 16:32:00 +0000</pubDate>
		<dc:creator><![CDATA[Fwolf]]></dc:creator>
				<category><![CDATA[SCM]]></category>
		<category><![CDATA[CVS]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[GitHub]]></category>
		<category><![CDATA[Gregarius]]></category>
		<category><![CDATA[Snoopy]]></category>

		<guid isPermaLink="false">http://www.fwolf.com/blog/?p=269</guid>
				<description><![CDATA[在捣鼓我的 Gregarius 时，发现无法读取 HTTPS 的 RSS ， 追查发现是他所使用的 HTTP 客户端类 Snoopy 的原因。 想升级新版 Snoopy 却发现原作者已经几年都不更新了， Github 上倒是有人弄了几个镜像， 其中 hurrycaner 的这个 还对 README 进行了一些改进。 但所有镜像都没有 SourceForge 上的修改历史。 所以，我想作的是，基于 hurrycaner 的镜像进行 Fork， 但是要把 SourceForge 上的修改历史也弄进来。 CVS &#8211;&#62; Git 现在应该没有人用 CVS 了把，SourceForge 也支持 Git 了， 但上面有些古老项目依然只有 CVS 。 把 CVS 转换成 Git 的工具还是有一些的，但从 一些讨论看来 似乎都做不到完美。 也难怪，CVS 的存储格式实在是有些奇怪， 代码、修改记录、修改注释都堆在一个文件中，解析起来肯定头疼。 &#8230; <a href="http://www.fwolf.com/blog/post/269" class="more-link">Continue reading <span class="screen-reader-text">将 CVS 转到 Git 并和 Github 上 Fork 的项目合并</span></a>]]></description>
								<content:encoded><![CDATA[<p><!-- -*- mode: rst -*- --> <!-- -*- coding: utf-8 -*- --></p>

<p>在捣鼓我的 <a class="reference external" href="https://github.com/fwolf/gregarius">Gregarius</a> 时，发现无法读取 HTTPS 的 RSS ， 追查发现是他所使用的 HTTP 客户端类 <a class="reference external" href="http://snoopy.sourceforge.net/">Snoopy</a> 的原因。 想升级新版 Snoopy 却发现原作者已经几年都不更新了， <a class="reference external" href="https://github.com/">Github</a> 上倒是有人弄了几个镜像， 其中 <a class="reference external" href="https://github.com/hurrycaner/snoopy">hurrycaner 的这个</a> 还对 README 进行了一些改进。 但所有镜像都没有 SourceForge 上的修改历史。</p>

<p>所以，我想作的是，基于 hurrycaner 的镜像进行 Fork， 但是要把 SourceForge 上的修改历史也弄进来。</p>

<div class="section" id="cvs-git"> <h3>CVS &#8211;&gt; Git</h3> <p>现在应该没有人用 CVS 了把，SourceForge 也支持 Git 了， 但上面有些古老项目依然只有 CVS 。</p> <p>把 CVS 转换成 Git 的工具还是有一些的，但从 <a class="reference external" href="http://stackoverflow.com/questions/881158">一些讨论看来</a> 似乎都做不到完美。 也难怪，CVS 的存储格式实在是有些奇怪， 代码、修改记录、修改注释都堆在一个文件中，解析起来肯定头疼。</p> <p>由于害怕 cvs2git 会像 svn2git 那样转换时把作者缀上 UUID， 我先试了试 <a class="reference external" href="https://github.com/BartMassey/parsecvs">parsecvs</a> ， 但这货连使用说明都没有，放弃了。 然后用的是 StackOverflow 上最后一个人推荐的 <a class="reference external" href="https://github.com/rcls/crap">crap</a> 。 和上面的一样，都是简单 make 一下就有可执行文件用， 但比上面的帮助全，还有一个非常简单的例子。</p> <p>这就可以开始了，先把 SourceForge 上的仓库下载下来：</p> <pre lang='bash'>
$ mkdir Snoopy.cvs

$ rsync -av rsync://snoopy.cvs.sourceforge.net/cvsroot/snoopy/ Snoopy.cvs
receiving incremental file list
./
CVSROOT/
CVSROOT/.#checkoutlist
CVSROOT/.#commitinfo
CVSROOT/.#config
CVSROOT/.#cvswrappers
CVSROOT/.#editinfo
CVSROOT/.#loginfo
CVSROOT/.#modules
CVSROOT/.#notify
CVSROOT/.#rcsinfo
CVSROOT/.#taginfo
CVSROOT/.#verifymsg
CVSROOT/checkoutlist
CVSROOT/checkoutlist,v
CVSROOT/commitinfo
CVSROOT/commitinfo,v
CVSROOT/config
CVSROOT/config,v
CVSROOT/cvswrappers
CVSROOT/cvswrappers,v
CVSROOT/editinfo
CVSROOT/editinfo,v
CVSROOT/history
CVSROOT/loginfo
CVSROOT/loginfo,v
CVSROOT/modules
CVSROOT/modules,v
CVSROOT/notify
CVSROOT/notify,v
CVSROOT/passwd
CVSROOT/rcsinfo
CVSROOT/rcsinfo,v
CVSROOT/readers
CVSROOT/taginfo
CVSROOT/taginfo,v
CVSROOT/val-tags
CVSROOT/verifymsg
CVSROOT/verifymsg,v
CVSROOT/writers
CVSROOT/Emptydir/
Snoopy/
Snoopy/AUTHORS,v
Snoopy/COPYING.lib,v
Snoopy/ChangeLog,v
Snoopy/FAQ,v
Snoopy/INSTALL,v
Snoopy/Makefile.am,v
Snoopy/NEWS,v
Snoopy/README,v
Snoopy/Snoopy.class.php,v
Snoopy/TODO,v
Snoopy/autogen.sh,v
Snoopy/configure.in,v
Snoopy/Attic/
Snoopy/Attic/.cvsignore,v
Snoopy/Attic/COPYING,v
Snoopy/Attic/Snoopy.class.inc,v

sent 1,066 bytes  received 229,013 bytes  17,042.89 bytes/sec
total size is 225,573  speedup is 0.98
</pre><p>注意这和下载 CVS 代码是不一样的，这里下载的是 CVSROOT，仓库的原始码。</p> <p>然后初始化一个 Git 仓库目录，用 crap 开始转换：</p> <pre lang='bash'>
$ mkdir Snoopy.git
$ cd Snoopy.git

$ git init

$ ../crap/crap-clone /home/fwolf/dev/Snoopy.cvs Snoopy
Valid-requests Root Valid-responses valid-requests Repository Directory Max-dotdot Static-directory Sticky Entry Kopt Checkin-time Modified Is-modified Empty-conflicts UseUnchanged Unchanged Notify Questionable Argument Argumentx Global_option Gzip-stream wrapper-sendme-rcsOptions Set Gssapi-authenticate expand-modules ci co update diff log rlog add remove update-patches gzip-file-contents status rdiff tag rtag import admin export history release watch-on watch-off watch-add watch-remove watchers editors init annotate rannotate noop version
*********** CYCLE **********
Changeset  andrei
*** empty log message ***

    INSTALL:1.1
    Makefile.am:1.1
    NEWS:1.1
    autogen.sh:1.1
    configure.in:1.1
    .cvsignore:1.1
Deferring:
    autogen.sh:1.2
Tag 'Snoopy' placing on branch ''
Tag 'start' placing on branch 'Snoopy'
opening version cache failed: No such file or directory
1970-01-01 08:00:00 CST BRANCH
2000-02-03 23:40:59 CST COMMIT
2000-02-03 23:40:59 CST BRANCH Snoopy
2000-02-03 23:40:59 CST COMMIT
2000-02-03 23:40:59 CST COMMIT
2000-02-03 23:40:59 CST TAG start
2000-02-04 00:10:54 CST COMMIT
2000-02-04 00:10:54 CST COMMIT
2000-02-04 00:28:59 CST COMMIT
2000-02-22 23:44:57 CST COMMIT
2000-03-10 04:52:59 CST COMMIT
2000-03-10 04:54:47 CST COMMIT
2000-05-18 22:50:14 CST COMMIT
2000-05-18 23:36:34 CST COMMIT
2000-05-18 23:44:00 CST COMMIT
2000-06-30 02:37:25 CST COMMIT
2000-08-23 04:36:52 CST COMMIT
2000-09-14 04:52:04 CST COMMIT
2000-09-14 22:09:58 CST COMMIT
2000-09-15 21:11:11 CST COMMIT
2000-09-16 05:57:37 CST COMMIT
2000-09-27 03:34:38 CST COMMIT
2000-09-27 04:28:45 CST COMMIT
2000-10-09 21:13:52 CST COMMIT
2001-03-25 04:15:18 CST COMMIT
2001-07-07 05:24:11 CST COMMIT
2001-08-22 23:43:24 CST COMMIT
2001-11-21 04:23:02 CST COMMIT
2002-10-03 22:38:49 CST COMMIT
2002-10-03 22:55:06 CST COMMIT
2002-10-03 22:57:39 CST COMMIT
2002-10-10 04:25:50 CST COMMITMissed first time round: ChangeLog 1.11
Missed first time round: Snoopy.class.inc 1.21

2002-10-10 04:41:24 CST COMMITcvs checkout ChangeLog 1.14 - version is duplicate
cvs checkout Snoopy.class.inc 1.24 - version is duplicate
Missed first time round: ChangeLog 1.12
Missed first time round: Snoopy.class.inc 1.22

2002-10-10 04:51:57 CST COMMITcvs checkout ChangeLog 1.14 - version is duplicate
cvs checkout Snoopy.class.inc 1.24 - version is duplicate
Missed first time round: ChangeLog 1.13
Missed first time round: Snoopy.class.inc 1.23

2002-10-10 04:56:14 CST COMMIT
2003-03-12 22:40:55 CST COMMIT
2003-09-15 21:58:28 CST COMMIT
2003-10-22 03:18:39 CST COMMIT
2003-11-08 03:52:58 CST COMMIT
2003-12-24 03:34:35 CST COMMIT
2004-01-08 03:16:10 CST COMMIT
2004-07-25 02:23:27 CST COMMITMissed first time round: ChangeLog 1.19
Missed first time round: Snoopy.class.php 1.5

2004-07-25 02:34:28 CST COMMITcvs checkout ChangeLog 1.22 - version is duplicate
cvs checkout Snoopy.class.php 1.8 - version is duplicate
Missed first time round: ChangeLog 1.20
Missed first time round: Snoopy.class.php 1.6

2004-07-25 08:49:02 CST COMMIT
2004-07-25 10:42:48 CST COMMIT
2004-07-25 10:46:34 CST COMMIT
2004-07-25 10:46:59 CST COMMIT
2004-07-25 11:18:32 CST COMMIT
2004-10-16 13:14:11 CST COMMIT
2004-10-16 13:17:41 CST COMMIT
2004-10-16 13:44:51 CST COMMIT
2004-10-16 14:27:09 CST COMMIT
2004-10-16 14:28:30 CST COMMIT
2004-10-16 14:40:42 CST COMMIT
2004-10-17 00:33:58 CST COMMIT
2004-10-17 00:36:18 CST COMMIT
2004-10-18 13:12:55 CST COMMIT
2004-10-18 13:18:27 CST COMMIT
2004-10-18 13:19:04 CST COMMIT
2004-10-18 13:19:28 CST COMMIT
2004-10-18 13:19:51 CST COMMIT
2004-11-18 13:51:32 CST COMMIT
2004-11-18 13:52:28 CST COMMIT
2004-11-18 14:37:05 CST COMMIT
2005-02-03 12:43:26 CST COMMIT
2005-02-03 12:57:05 CST COMMIT
2005-10-23 10:08:40 CST COMMIT
2005-10-23 10:16:26 CST COMMIT
2005-10-24 00:30:34 CST COMMIT
2005-10-24 23:34:50 CST COMMIT
2005-10-24 23:44:12 CST COMMIT
2005-10-24 23:44:59 CST COMMIT
2005-10-24 23:46:10 CST COMMIT
2005-10-30 13:33:15 CST COMMIT
2005-10-30 13:45:09 CST COMMIT
2005-10-31 02:32:42 CST COMMIT
2005-10-31 02:51:35 CST COMMIT
2005-11-08 14:53:56 CST COMMIT
2005-11-08 15:01:47 CST COMMIT
2008-10-22 23:30:41 CST COMMIT
2008-10-22 23:53:14 CST COMMIT
2008-11-09 05:09:09 CST COMMIT
Emitted 79 commits (= total 79).
Exact     2 +     1 =     3 branches + tags.
Fixup     0 +     0 =     0 branches + tags.
Download 147 cvs versions in 84 transactions.
String cache: 141 items, 132/1024 buckets used, mean search 1.06383
git-fast-import statistics:
---------------------------------------------------------------------
Alloc'd objects:       5000
Total objects:          289 (         8 duplicates                  )
      blobs  :          134 (         7 duplicates         46 deltas of        133 attempts)
      trees  :           77 (         0 duplicates         70 deltas of         71 attempts)
      commits:           78 (         1 duplicates          0 deltas of          0 attempts)
      tags   :            0 (         0 duplicates          0 deltas of          0 attempts)
Total branches:           3 (         2 loads     )
      marks:           1024 (       220 unique    )
      atoms:             15
Memory total:          2294 KiB
       pools:          2098 KiB
     objects:           195 KiB
---------------------------------------------------------------------
pack_report: getpagesize()            =       4096
pack_report: core.packedGitWindowSize =   33554432
pack_report: core.packedGitLimit      =  268435456
pack_report: pack_used_ctr            =          7
pack_report: pack_mmap_calls          =          3
pack_report: pack_open_windows        =          1 /          1
pack_report: pack_mapped              =     350104 /     350104
---------------------------------------------------------------------
</pre><p>这样这个 Git 仓库就包含了已经转换过了的 CVS 历史记录， 如果看不到文件可以 reset 一下。</p> <p>按说后续的操作理论上可以在这个仓库目录中操作，但为了更好的和 Fork 的项目合并， 我使用导出 Patch 的方法，后面再 am：</p> <pre lang='bash'>
$ git log --pretty=oneline |wc -l
78

$ git format-patch -78
</pre><p>其实在这里，也可以在目标 repo 里面，通过添加 Snoopy.git 为 Git remote， 然后 merge remote 的方式进行，效果更好，还不用修改提交时间。</p> </div>

<div class="section" id="fork"> <h3>Fork 项目，移花接木</h3> <p>在 Github 上 Fork <a class="reference external" href="https://github.com/hurrycaner/snoopy">https://github.com/hurrycaner/snoopy</a> ， 得到 <a class="reference external" href="https://github.com/fwolf/snoopy">https://github.com/fwolf/snoopy</a> ， 但先不下载到本地，后面的操作方法和正常 Fork 项目是 <strong>不一样</strong> 的。</p> <p>在本地再新建一个 Git 仓库，这个仓库是我们今后维护 Snoopy 的主仓库：</p> <pre lang='bash'>
$ mkdir Snoopy
$ cd Snoopy
$ git init
$ git remote add origin git@github.com:fwolf/snoopy.git
$ touch .gitignore
$ git add .gitignore
$ git commit -a -m "Initial commit"
$ git push -f origin master
</pre><p>和新建项目的方法基本一样，不同点是我们的 origin 是 Fork 后的项目， 并且进行了 <tt class="docutils literal">push <span class="pre">-f</span></tt> 操作，覆盖掉了 hurrycaner 的所有提交。</p> <p>接下来新建一个 sourceforge 分支，保留 SourceForge 上 CVS 代码的最终状态， 提交是通过 am 导入的， <tt class="docutils literal"><span class="pre">--committer-date-is-author-date</span></tt> 参数是将作者的时间作为提交时间， 也可以不要。Patch 0002 是空的，会导致 am 失败，所以删除掉：</p> <pre lang='bash'>
$ git branch sourceforge
$ git checkout sourceforge

$ rm ../Snoopy.git/0002-Initial-check-in.patch
$ git am ../Snoopy.git/00* --committer-date-is-author-date

$ git checkout master
$ git merge sourceforge
$ git push
</pre><p>现在，master 分支上是我作的一个初始提交，加上 CVS 上导过来的提交内容， 相当于是 CVS 被完整的导入了 Git。</p> <p>添加只有一个空 .gitignore 文件的初始提交是 Git 的一个习惯， 因为 Git 的初始提交可以视为是“不可以操作”的， 所以最好是空或者只包含最少内容。</p> <p>接下来，我们要将 hurrycaner 所作的修改合并进来。 由于他是基于 Snoopy 1.2.4 代码修改的， 和我导入的最终代码差距不大，所以合并还比较顺利，只有几处冲突而已：</p> <pre lang='bash'>
$ git branch hurrycaner
$ git checkout hurrycaner
$ git remote add upstream git@github.com:hurrycaner/snoopy.git
$ git fetch upstream
$ git merge upstream/master     # 手工解决冲突

$ git checkout master
$ git merge hurrycaner
$ git push
</pre><p>这就基本上完成了，保留了从 CVS 到 hurrycaner 的完整修改记录， 并且还能像正常 Fork 的项目那样继续工作。</p> <p>修改记录看起来是这个样子的：</p> <a href="http://www.flickr.com/photos/fwolf/10330582973/" title="2013-10-18-000402_722x358_scrot by fwolf, on Flickr"><img src="http://farm6.staticflickr.com/5491/10330582973_fba050b9c8.jpg" width="500" height="248" alt="2013-10-18-000402_722x358_scrot"/></a><p>我已经向原项目作者推送 <a class="reference external" href="https://github.com/hurrycaner/snoopy/pull/1">Pull Request</a> 了。 hurrycaner 在 Github 上并不活跃，不知道能不能看到、会不会收啊。</p> </div>

<div class="section" id="id2"> <h3>尾声</h3> <p>Git 的使用是比较灵活的，我相信其他分布式 SCM 也能做到，没研究过，不对比。 话说回来，本文中的做法，是不是有点鸠占鹊巢的感觉？</p> <p>&#64;link <a class="reference external" href="https://github.com/fwolf/snoopy">https://github.com/fwolf/snoopy</a></p> <!-- Substitution definitions for links --> <!-- Hyperlink targets --> </div>

<div class="wp_rp_wrap  wp_rp_twocolumns"><div class="wp_rp_content"><h3 class="related_post_title">Related Posts</h3><ul class="related_post wp_rp"><li data-position="0" data-poid="in-246" data-post-type="none"><small class="wp_rp_publish_date">2013-10-22</small> <a href="http://www.fwolf.com/blog/post/246" class="wp_rp_title">Git subtree 要不要使用 &#8211;squash 参数</a></li><li data-position="1" data-poid="in-36" data-post-type="none"><small class="wp_rp_publish_date">2013-01-22</small> <a href="http://www.fwolf.com/blog/post/36" class="wp_rp_title">通过代理使用 GitHub</a></li><li data-position="2" data-poid="in-6" data-post-type="none"><small class="wp_rp_publish_date">2012-11-27</small> <a href="http://www.fwolf.com/blog/post/6" class="wp_rp_title">用 rst2wp 来写 WordPress</a></li><li data-position="3" data-poid="in-14" data-post-type="none"><small class="wp_rp_publish_date">2012-11-30</small> <a href="http://www.fwolf.com/blog/post/14" class="wp_rp_title">Git commit 注释格式</a></li><li data-position="4" data-poid="in-431" data-post-type="none"><small class="wp_rp_publish_date">2009-03-27</small> <a href="http://www.fwolf.com/blog/post/431" class="wp_rp_title">[Git]提交后自动发email</a></li><li data-position="5" data-poid="in-429" data-post-type="none"><small class="wp_rp_publish_date">2009-03-26</small> <a href="http://www.fwolf.com/blog/post/429" class="wp_rp_title">Git起步</a></li></ul><div class="wp_rp_footer"><a class="wp_rp_backlink" target="_blank" href="http://www.sovrn.com/" rel="nofollow">Sovrn</a></div></div></div>
]]></content:encoded>
							<wfw:commentRss>http://www.fwolf.com/blog/post/269/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
		<item>
		<title>防火墙的目标地址转换和源地址转换</title>
		<link>http://www.fwolf.com/blog/post/423</link>
				<comments>http://www.fwolf.com/blog/post/423#comments</comments>
				<pubDate>Sun, 06 Oct 2013 10:30:00 +0000</pubDate>
		<dc:creator><![CDATA[Fwolf]]></dc:creator>
				<category><![CDATA[Internet]]></category>
		<category><![CDATA[DNAT]]></category>
		<category><![CDATA[Firewall]]></category>
		<category><![CDATA[SNAT]]></category>
		<category><![CDATA[TCP]]></category>

		<guid isPermaLink="false">http://www.fwolf.com/blog/post/423</guid>
				<description><![CDATA[遇到一起防火墙故障，对防火墙的工作原理和目标地址转换、 源地址转换有了进一步的了解，记录于此。 结果说在前面 网络结构非常简单：外网-防火墙-内网。内网中架有网站，在外网使用域名访问。 内网中机器需要上外网，也需要用域名互访。 在这种情况下，地址转换规则应当这样配： 外网访问内网，只需要做目标地址转换，不需要做源地址转换。 内网通过域名访问内网，除了做目标地址转换，还必须做源地址转换。 上面第一条有一种“例外”情况，就是网关配置错误的情况，比如我们遇到的： 内网6有 2 块网卡，都配置了同一网段的内网地址，并且每块网卡都配置了网关。 由于是同一网段，所以两个网关是一样的。 在这种情况下，外网访问也必须做源地址转换， 否则内网能收到请求，但处理结果无法返回外网，外网看到的结果是没有回应。 防火墙数据包转换发送原理 为什么会这样？这要从防火墙的原理说起。 上面的外网访问内网，正常处理过程应该是这样的： 防火墙收到外网访问请求数据包，格式中包含【防火墙外网IP 外网用户IP】 防火墙进行目标地址转换，数据包变成【内网IP 外网用户IP】 内网服务器收到请求，进行处理，返回结果数据包【外网用户IP 内网IP】， 由于目标地址是外网IP，所有经过路由，此数据包被发向网关（防火墙） 针对返回数据包，防火墙做目标地址转换的反操作， 数据包变成【外网用户IP 防火墙外网IP】 数据包发回请求用户。 刚才说到的“例外”情况，问题就出在步骤 3，内网服务器返回结果数据包中， 内网IP 不是防火墙指向的那个 IP，而是这太内网服务器的另一个 IP 地址， 也就是说内网服务器通过网卡1接受了请求，却从网卡2发送返回数据。 这样的数据包到了防火墙之后，目标地址转换的反操作会失败（内网IP 不一致）， 所以数据依然会通过防火墙发给用户，但却是一个新的 TCP 会话/连接， 无法和原先的用户请求包对应。 结果就是新的数据包到了用户那里，不知道是给谁的， 而用户原先发送的请求，也一直“收不到”回应数据包。 外在表现就是用户看到请求发送成功，却没有回应。 在这种情况下，如果同时做了源地址转换是能够通的，处理过程如下： 防火墙收到外网访问请求数据包，格式中包含【防火墙外网IP 外网用户IP】 防火墙进行目标地址转换，数据包变成【内网IP 外网用户IP】， 进行源地址转换，数据包变成【内网IP 防火墙/网关IP】 内网服务器收到请求，进行处理，返回结果数据包【防火墙/网关IP 内网IP】， &#8230; <a href="http://www.fwolf.com/blog/post/423" class="more-link">Continue reading <span class="screen-reader-text">防火墙的目标地址转换和源地址转换</span></a>]]></description>
								<content:encoded><![CDATA[<p><!-- -*- mode: rst -*- --> <!-- -*- coding: utf-8 -*- --></p>

<p>遇到一起防火墙故障，对防火墙的工作原理和目标地址转换、 源地址转换有了进一步的了解，记录于此。</p>

<div class="section" id="id1"> <h3>结果说在前面</h3> <p>网络结构非常简单：外网-防火墙-内网。内网中架有网站，在外网使用域名访问。 内网中机器需要上外网，也需要用域名互访。 在这种情况下，地址转换规则应当这样配：</p> <ul class="simple"> <li>外网访问内网，只需要做目标地址转换，不需要做源地址转换。</li> <li>内网通过域名访问内网，除了做目标地址转换，还必须做源地址转换。</li> </ul> <p>上面第一条有一种“例外”情况，就是网关配置错误的情况，比如我们遇到的： 内网6有 2 块网卡，都配置了同一网段的内网地址，并且每块网卡都配置了网关。 由于是同一网段，所以两个网关是一样的。 在这种情况下，外网访问也必须做源地址转换， 否则内网能收到请求，但处理结果无法返回外网，外网看到的结果是没有回应。</p> </div>

<div class="section" id="id2"> <h3>防火墙数据包转换发送原理</h3> <p>为什么会这样？这要从防火墙的原理说起。 上面的外网访问内网，正常处理过程应该是这样的：</p> <ol class="arabic simple"> <li>防火墙收到外网访问请求数据包，格式中包含【防火墙外网IP 外网用户IP】</li> <li>防火墙进行目标地址转换，数据包变成【内网IP 外网用户IP】</li> <li>内网服务器收到请求，进行处理，返回结果数据包【外网用户IP 内网IP】， 由于目标地址是外网IP，所有经过路由，此数据包被发向网关（防火墙）</li> <li>针对返回数据包，防火墙做目标地址转换的反操作， 数据包变成【外网用户IP 防火墙外网IP】</li> <li>数据包发回请求用户。</li> </ol> <p>刚才说到的“例外”情况，问题就出在步骤 3，内网服务器返回结果数据包中， 内网IP 不是防火墙指向的那个 IP，而是这太内网服务器的另一个 IP 地址， 也就是说内网服务器通过网卡1接受了请求，却从网卡2发送返回数据。 这样的数据包到了防火墙之后，目标地址转换的反操作会失败（内网IP 不一致）， 所以数据依然会通过防火墙发给用户，但却是一个新的 TCP 会话/连接， 无法和原先的用户请求包对应。 结果就是新的数据包到了用户那里，不知道是给谁的， 而用户原先发送的请求，也一直“收不到”回应数据包。 外在表现就是用户看到请求发送成功，却没有回应。</p> <p>在这种情况下，如果同时做了源地址转换是能够通的，处理过程如下：</p> <ol class="arabic simple"> <li>防火墙收到外网访问请求数据包，格式中包含【防火墙外网IP 外网用户IP】</li> <li>防火墙进行目标地址转换，数据包变成【内网IP 外网用户IP】， 进行源地址转换，数据包变成【内网IP 防火墙/网关IP】</li> <li>内网服务器收到请求，进行处理，返回结果数据包【防火墙/网关IP 内网IP】， 由于目标地址仍然是防火墙/网关IP，所以防火墙能够找到相应的连接， 会接受数据包并进行处理。</li> <li>针对返回数据包，防火墙 做源地址转换的反操作，数据包变成【外网用户IP 内网IP】， 做目标地址转换的反操作， 数据包变成【外网用户IP 防火墙外网IP】（R）</li> <li>数据包发回请求用户。</li> </ol> <p>可以看到，即使（R）操作失败，由于防火墙已经将内网服务器返回数据包和 防火墙接收的外网用户请求连接成功对应， 结果数据包的目标地址也成功转换成了外网用户IP， 所以数据能够成功发回请求用户，并和用户请求会话/连接相对应。</p> <p>从另外一个角度看，外网访问做双向地址转换虽然可行，但有一个缺点， 就是数据包到达内网服务器时，外网用户IP 被转换成了防火墙/网关IP， 这样内网中的应用程序就无法获取外网用户的真实IP了， 只能看到请求来自防火墙/网关IP。</p> </div>

<div class="section" id="id3"> <h3>内网通过域名访问内网</h3> <p>上面的都理解之后，内网通过域名访问内网为什么必须要做双向转换就清楚了。 问题同样出在接受请求的服务器处理完，发送返回数据包时。</p> <p>内网1 通过域名访问内网6，在没有做源地址转换时的情形：</p> <ul class="simple"> <li>由于是通过域名访问，所以请求数据通过防火墙转发给内网6， 用户IP是内网地址（这是关键）</li> <li>内网6处理完毕发送结果数据包，返回数据包的目标地址就是内网1的地址 由于同在一个子网内，数据包会通过交换机直接发向内网1，不过防火墙</li> </ul> <p>问题产生了，在内网1 上，请求数据直接发向防火墙，返回数据直接来自内网6， 不对应，又是一宗没有回应数据包的情形。</p> <p>如果同时做了源地址转换，问题就能够解决。因为内网1 的请求数据在通过防火墙时， 用户地址（内网1 IP）会被转换成防火墙/网关IP， 返回数据包也就会发往防火墙/网关IP，再被防火墙转换发回 内网1， 不存在内网1 和内网6 的直接对话， TCP 数据包也能对应上，访问就没有问题了。</p> <p>不同品牌、类型的防火墙工作机制也许不同，但原理都差不多。 不专业的地方，还请过路仙人不吝赐教。</p> <!-- Substitution definitions for links --> <!-- Hyperlink targets --> </div>

<div class="wp_rp_wrap  wp_rp_twocolumns"><div class="wp_rp_content"><h3 class="related_post_title">Related Posts</h3><ul class="related_post wp_rp"><li data-position="0" data-poid="in-47" data-post-type="none"><small class="wp_rp_publish_date">2013-05-18</small> <a href="http://www.fwolf.com/blog/post/47" class="wp_rp_title">原来 netctl 是这样选择 profile 的</a></li><li data-position="1" data-poid="in-453" data-post-type="none"><small class="wp_rp_publish_date">2014-07-02</small> <a href="http://www.fwolf.com/blog/post/453" class="wp_rp_title">配置 Nginx 子域名的泛解析</a></li><li data-position="2" data-poid="in-401" data-post-type="none"><small class="wp_rp_publish_date">2008-05-06</small> <a href="http://www.fwolf.com/blog/post/401" class="wp_rp_title">新的广告交换、51.la统计和web标准</a></li><li data-position="3" data-poid="in-406" data-post-type="none"><small class="wp_rp_publish_date">2008-06-23</small> <a href="http://www.fwolf.com/blog/post/406" class="wp_rp_title">麻烦一连串儿</a></li><li data-position="4" data-poid="in-308" data-post-type="none"><small class="wp_rp_publish_date">2007-04-01</small> <a href="http://www.fwolf.com/blog/post/308" class="wp_rp_title">CSS技巧两则——居中和编号列表</a></li><li data-position="5" data-poid="in-352" data-post-type="none"><small class="wp_rp_publish_date">2007-09-04</small> <a href="http://www.fwolf.com/blog/post/352" class="wp_rp_title">让numlock开机就亮的方法</a></li></ul><div class="wp_rp_footer"><a class="wp_rp_backlink" target="_blank" href="http://www.sovrn.com/" rel="nofollow">Sovrn</a></div></div></div>
]]></content:encoded>
							<wfw:commentRss>http://www.fwolf.com/blog/post/423/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
							</item>
		<item>
		<title>在U盘上安装 Arch Linux (2013-07)</title>
		<link>http://www.fwolf.com/blog/post/416</link>
				<comments>http://www.fwolf.com/blog/post/416#comments</comments>
				<pubDate>Wed, 10 Jul 2013 15:28:00 +0000</pubDate>
		<dc:creator><![CDATA[Fwolf]]></dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Arch Linux]]></category>
		<category><![CDATA[ext4]]></category>
		<category><![CDATA[Fluxbox]]></category>
		<category><![CDATA[GPT]]></category>
		<category><![CDATA[install]]></category>
		<category><![CDATA[LXDE]]></category>
		<category><![CDATA[MBR]]></category>
		<category><![CDATA[netctl]]></category>
		<category><![CDATA[USB]]></category>
		<category><![CDATA[XFS]]></category>

		<guid isPermaLink="false">http://www.fwolf.com/blog/post/416</guid>
				<description><![CDATA[前言 1 月份在移动硬盘上装了个 Arch ， 但这块移动硬盘实在是太旧了，在我的旧电脑上经常供电不足， 弄了块 USB 2.0 PCI 卡 也无济于事。 最近终于挺不住了，频繁的报分区损坏、无法进入系统， 严重的时候会在进行硬盘操作时死机。 无奈，拿出一个比较新的 8G U盘，重做随身系统。 本篇文章基于上次移动硬盘安装的经历修改补充而来， 不过半年的时间，一些基础组件就已经发生了变化， Arch Linux 可真是够“折腾”的。 PS：基于半年的 Arch Linux 使用经验， 我 合租的 Linode VPS 也用上了 Arch， 目前感觉尚好，Nginx + PHP-FPM 确实是不错的组合。 Linode 使用修改过的 Linux 内核， AUR 上也有人发布 自己制作的更新版 ， 还没研究怎么升级。 基本系统安装 和上次移动硬盘安装一样，选择 32 位系统。 安装介质使用 archlinux-2013.07.01-dual.iso dd 到另一个U盘。 使用U盘启动，自动以 root &#8230; <a href="http://www.fwolf.com/blog/post/416" class="more-link">Continue reading <span class="screen-reader-text">在U盘上安装 Arch Linux (2013-07)</span></a>]]></description>
								<content:encoded><![CDATA[<p><!-- -*- mode: rst -*- --> <!-- -*- coding: utf-8 -*- --></p>

<div class="section" id="id1"> <h3>前言</h3> <p><a class="reference external" href="/blog/post/7">1 月份在移动硬盘上装了个 Arch</a> ， 但这块移动硬盘实在是太旧了，在我的旧电脑上经常供电不足， 弄了块 <a class="reference external" href="http://item.jd.com/166127.html">USB 2.0 PCI 卡</a> 也无济于事。 最近终于挺不住了，频繁的报分区损坏、无法进入系统， 严重的时候会在进行硬盘操作时死机。 无奈，拿出一个比较新的 8G U盘，重做随身系统。</p> <p>本篇文章基于上次移动硬盘安装的经历修改补充而来， 不过半年的时间，一些基础组件就已经发生了变化， Arch Linux 可真是够“折腾”的。</p> <p>PS：基于半年的 Arch Linux 使用经验， 我 <a class="reference external" href="http://wpmu.fwolf.com/">合租的 Linode VPS</a> 也用上了 Arch， 目前感觉尚好，Nginx + PHP-FPM 确实是不错的组合。 Linode 使用修改过的 Linux 内核， AUR 上也有人发布 <a class="reference external" href="https://aur.archlinux.org/packages/linux-linode/">自己制作的更新版</a> ， 还没研究怎么升级。</p> </div>

<div class="section" id="id3"> <h3>基本系统安装</h3> <p>和上次移动硬盘安装一样，选择 32 位系统。 安装介质使用 <tt class="docutils literal"><span class="pre">archlinux-2013.07.01-dual.iso</span></tt> dd 到另一个U盘。</p> <ul> <li><p class="first">使用U盘启动，自动以 root 身份进入系统。</p> </li> <li><p class="first">插入移动硬盘，分区，格式化，挂载。</p> <p>本想使用 GPT 分区表，查了一些资料， 为了使这个U盘在 BIOS 和 UEFI 电脑上都能用， 需要创建一个 BIOS boot 分区，2M 大小足够，位置尽量靠前。 多系统的话还要创建一个 200M 的 EFI System Partition(ESP) 分区。 这些都不是问题，但实际做下来， GPT 中的 NTFS 分区在 Win7 下死活不认， 想用这个分区作为常规U盘使用就不行了， 只好再回到 MBR 分区表。 如果是移动硬盘用 GPT 应该没有问题。</p> <p>所以仍然使用 MBR 分区，所以就要用 fdisk 或者 cfdisk 了， 不能使用支持 GPT 的 gdisk 和 cgdisk， 4k 对齐也是自动完成。 有趣的是，如果想把 GPT 分区表转换成 MBR 分区表， 还得借助 gdisk：r 进入 Recovery 模式， g 进入 MBR 模式，w 进行转换。 根据实际情况， 有些分区转换未必能够成功， 不过变回 MBR 分区表是没有问题的。</p> <p>NTFS 分区得在第一个分区，不然 Windows 不认。</p> <p>启动U盘是 /dev/sdb，目标U盘就成了 /dev/sdc。</p> <pre lang='bash'>
# fdisk /dev/sdb

Disk /dev/sdc: 8022 MB, 8022982656 bytes, 15669888 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x00000000

Device      Boot    Start       End         Blocks      Id      System
/dev/sdb1           2048        1804287     901120      7       HPFS/NTFS/exFAT
/dev/sdb2   *       1804288     2009087     102400      83      Linux
/dev/sdb3           2009088     10405887    4198400     83      Linux
/dev/sdb4           10405888    15669887    2632000     83      Linux
</pre><p>第一个分区先用 ntfs，当正常U盘使用， 如果以后需要用到 ESP 分区，直接用这个分区转，或者切一部分空间过去。 第二个分区 100M，挂 /boot； 第三个分区 4G，作为 ArchLinux 根分区； 第四个分区 2.5G，作为 <tt class="docutils literal">$HOME</tt> ；</p> <p>格式化分区：</p> <p>如果使用 xfs 分区格式：</p> <pre lang='bash'>
# mkfs.ntfs -f /dev/sdc1 -L f004-c
# mkfs.xfs -n size=64k -l lazy-count=1 /dev/sdc2 -L f004-boot
# mkfs.xfs -n size=64k -l size=128m,lazy-count=1 /dev/sdc3 -L f004-a
# mkfs.xfs -n size=64k -l size=128m,lazy-count=1 /dev/sdc4 -L f004-b
</pre><p><tt class="docutils literal"><span class="pre">-n</span> size=64k</tt> 参数增加了文件名（目录）区域大小（默认 4k）， 这样可以减少 IO 消耗，代价是 CPU 消耗多一些， 这对现代计算机显然不是问题。 <tt class="docutils literal"><span class="pre">-l</span> size=128m</tt> 参数扩大日志的容量（默认 10m），更安全， 代价是挂载时间会长一些。 <tt class="docutils literal"><span class="pre">-l</span> <span class="pre">lazy-count=1</span></tt> 参数减少 superblock 读写次数，提高性能。</p> <p>如果使用 ext4 分区格式：</p> <pre lang='bash'>
# mkfs.ntfs -f /dev/sdc1 -L f004-c
# mkfs.ext4 -b 4096 -m 0 -i 16384 -O '^has_journal' /dev/sdc2 -L f004-boot
# mkfs.ext4 -b 4096 -m 1 -i 16384 -O '^has_journal' /dev/sdc3 -L f004-a
# mkfs.ext4 -b 4096 -m 0 -i 16384 -O '^has_journal' /dev/sdc4 -L f004-b
</pre><p><tt class="docutils literal"><span class="pre">-b</span> 4096</tt> 是每个存储块的大小。 <tt class="docutils literal"><span class="pre">-m</span> 1</tt> 是指定 root 保留空间为 1%，home 区就不留了。 <tt class="docutils literal"><span class="pre">-i</span> 16384</tt> 是指定多少字节的数据设置一个 inode 节点， 增加它的值会减少 inode 的总数，占用的空间会少一些， 相应的能够存储的文件数量也减少了，这个稍微注意一下就好，一般都够用。 <tt class="docutils literal"><span class="pre">-O</span> '^has_journal'</tt> 是关掉文件系统日志，有点小危险。</p> <p>经过两天的折腾，个人感觉 ext4 在U盘上读写速度快一些。</p> <p>挂载分区：</p> <pre lang='bash'>
# mount /dev/sdc3 /mnt
# mkdir /mnt/boot
# mount /dev/sdc2 /mnt/boot
# mkdir /mnt/home
# mount /dev/sdc4 /mnt/home
</pre><p><tt class="docutils literal">df <span class="pre">-h</span></tt> 检查一下：</p> <pre lang='bash'>
# xfs
Filesystem  Size    Used    Avail   Use%    Mounted on
/dev/sdc3   3.9G    33M     3.9G    1%      /mnt
/dev/sdc2   82M     5.2M    77M     7%      /mnt
/dev/sdc4   2.4G    33M     2.4G    2%      /mnt/home

# ext4
Filesystem  Size    Used    Avail   Use%    Mounted on
/dev/sdc3   3.9G    8.1M    3.8G    1%      /mnt
/dev/sdc2   96M     48K     96M     1%      /mnt
/dev/sdc4   2.5G    3.8M    2.4G    1%      /mnt/home
</pre><p>ext4 改变 bytes-per-inode 确实对分区所占空间影响很大。</p> </li> <li><p class="first">安装基本系统</p> <p>家里有无线路由，网络不用配置，已经自动连上了。</p> <p>编辑 <tt class="docutils literal">/etc/pacman.d/mirrorlist</tt> ，把最快的源挪到最上面。 一般来说 163 和台湾的源比较快，163 似乎有时候不稳定， 几个中国大学的源有些是 ipv6 的，用不了。 安装完成后，这个配置文件也会自动拷贝到新系统中。 自带的 vi 真的是比 vim 难用多了，一会儿第一时间换掉。</p> <p>按照官网说明，用 <tt class="docutils literal"># pacstrap /mnt base <span class="pre">base-devel</span></tt> 安装基本系统， base-devel 也一并装上，迟早会用到 AUR 或 ABS。 提示共 128 个软件包，需要下载 158.37M 内容，安装完成后是 507.09M。</p> <p>安装 grub： <tt class="docutils literal"># <span class="pre">arch-chroot</span> /mnt pacman <span class="pre">-S</span> grub</tt> 。</p> <p>生成 fstab： <tt class="docutils literal"># genfstab <span class="pre">-p</span> <span class="pre">-U</span> /mnt &gt;&gt; /mnt/etc/fstab</tt> ， 然后更改 fstab （系统默认一般就比较好了，不优化也行）：</p> <ul> <li><p class="first">使用 <tt class="docutils literal">relatime</tt> 挂载参数。</p> <p>以前是推荐增加 <tt class="docutils literal">noatime</tt> 挂载参数，不记录文件读取时间， 但这会导致 Mutt 等需要文件读取时间的软件出错。 现在改为使用 <tt class="docutils literal">relatime</tt> 参数了 （已经默认加上了，Linux 2.6.30 起此参数成为默认值）， 只有在文件读取时间早于文件更新时间时，才更新读取时间数据。</p> </li> <li><p class="first">使用 <tt class="docutils literal">nodiratime</tt> 挂载参数，不记录目录读取访问时间。</p> </li> <li><p class="first">把 <tt class="docutils literal">/tmp</tt> 放到 tmpfs 上去。（没单独分区，免了）</p> </li> <li><p class="first">不再使用 <tt class="docutils literal">discard</tt> 挂载参数。</p> <p>这个参数主要是针对 SSD 硬盘的，对不支持 TRIM 的机械硬盘无效， 对U盘貌似作用不明显。</p> </li> <li><p class="first">不再使用 <tt class="docutils literal">async</tt> 挂载参数，开启异步读写模式。 由于只是“看起来”快了，实际数据写入速度并没有改善， 考虑到稳定性，是否应使用此参数？</p> </li> <li><p class="first">不要使用 <tt class="docutils literal">barrier=0</tt> 挂载参数，这个选项似乎在突然断电、 拔U盘时，有几率丢失文件或损坏分区。 （基于我的经历 + <a class="reference external" href="https://wiki.archlinux.org/index.php/Ext4#Barriers_and_Performance">参考</a> ）</p> </li> </ul> <p>由于不会跑什么大应用，为了降低 swap 的使用频率， 修改 <tt class="docutils literal">/mnt/etc/sysctl.conf</tt> ：</p> <pre lang='ini'>
vm.swappiness = 1
vm.vfs_cache_pressure = 50
</pre><p>前一句是尽量不使用 swap，后一句是缓存文件系统信息。</p> <p>下面的操作可以在 chroot 环境下运行：</p> <pre lang='bash'>
# arch-chroot /mnt
</pre><p>设置 hostname： <tt class="docutils literal">echo 'f004' &gt; /etc/hostname</tt> 。</p> <p>设置时区：</p> <pre lang='bash'>
# ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
</pre><p>新建 <tt class="docutils literal">/etc/locale.conf</tt> 内容为：</p> <pre lang='ini'>
LANG='en_US.UTF-8'
LC_COLLATE='C'
LC_MESSAGES='C'
</pre><p>编辑 <tt class="docutils literal">/etc/locale.gen</tt> ，取消 en_US.UTF-8, zh_CN.UTF-8, zh_TW.UTF-8 前面的注释，然后执行 <tt class="docutils literal"><span class="pre">locale-gen</span></tt> 命令。</p> <p>更改 root 密码： <tt class="docutils literal">passwd root</tt> 。</p> </li> <li><p class="first">安装 Grub 引导系统。</p> <p>仍然在 chroot 环境中操作。 编辑 <tt class="docutils literal">/etc/mkinitcpio.conf</tt> ，检查 HOOKS 段， 让 block 参数紧挨着 udev 参数之后（早一点加载）， 然后 <tt class="docutils literal"># mkinitcpio <span class="pre">-p</span> linux</tt> 生成 img 文件。 同时加上了 shutdown 参数，作用以后再试。 resume 参数就算了，U盘本来就小、慢，支持休眠更痛苦。 （注：新版本中 block 参数替代了 usb pata sata scsi 等一众参数）</p> <p>安装 grub：</p> <pre lang='bash'>
# grub-install --target=i386-pc --recheck --boot-directory=/boot --no-floppy /dev/sdc
# cp -v /usr/share/grub/{unicode.pf2,ascii.pf2} /boot/grub/
# cp -v /usr/share/locale/en\@quot/LC_MESSAGES/grub.mo /boot/grub/locale/en.mo
</pre><p>无论是 32 位还是 64 位系统，都是使用 <tt class="docutils literal"><span class="pre">--target=i386-pc</span></tt> 参数， <tt class="docutils literal"><span class="pre">--no-floppy</span></tt> 是不检查软驱（这玩意儿现在应该没人用了）。 后两句不执行也行，还没弄懂是做什么的。</p> <p>然后，千万不要忘记 <strong>生成 grub.cfg 文件</strong> ：</p> <pre lang='bash'>
# grub-mkconfig -o /boot/grub/grub.cfg
# grep 'set=root' /boot/grub/grub.cfg
# blkid /dev/sdc2
</pre><p>现在的 Grub2 使用 UUID 来找硬盘分区， 后两句就是检查新生成的 grub.cfg 使用的分区 UUID 和硬盘是否相符。 如果忘记生成 grub.cfg 了，可以再次用光盘启动进去做。</p> <p>最后，退出 chroot 环境，umount，重启。 启动U盘可以收起来了。</p> <p>启动后，新安装的U盘变成了 /dev/sdb， 此时最好将 mkinitcpio grub-install grub-mkconfig 重新做一遍， 否则有可能在下次或另外一台机器上启动时，损坏分区表，丢失文件。 或许没有道理，但这是我重复安装好多次以后的感觉，可能有以下原因：</p> <ul class="simple"> <li>带电插拔，可我都是 umount 了啊，不应当这么脆弱。</li> <li>被 USB 3.0 高电流给破坏了，没拔U盘烧了算我走运？ 倒是听说过 USB 3.0 损坏U盘数据。</li> <li>/boot 原先没有单独分区，这个不应该。</li> <li>是原先使用 GPT 分区在 BIOS 电脑上水土不服？ U盘难道就不能用 GPT 分区么？</li> </ul> <p>反正换回 MBR 分区后，貌似比较正常了。</p> </li> </ul> </div>

<div class="section" id="id5"> <h3>初始设置</h3> <p>如果一切正常，现在可以用 root 登录系统了：</p> <pre lang='bash'>
# uname -a
Linux f004 3.9.9-1-ARCH #1 SMP PREEMPT Wed Jul 3 22:52:05 CET 2013 i686 GNU/Linux

# free -h
            total   used    free    shared  buffers cached
Mem:        1.0G    54M     951M    0B      5.6M    27M
-/+ buffers/cache:  21M     984M
Swap:       0B      0B      0B

# df -h
Filesystem      Size    Used    Avail   Use%    Mounted on
/dev/sdb3       3.9G    764M    3.1G    20%     /
dev             499M    0       499M    0%      /dev
run             503M    7.1M    496M    2%      /run
tmpfs           503M    0       503M    0%      /dev/shm
tmpfs           503M    0       503M    0%      /sys/fs/cgroup
tmpfs           503M    0       503M    0%      /tmp
/dev/sdb4       2.5G    3.8M    2.4G    1%      /home
/dev/sdb3       96M     39M     58M     41%     /boot
</pre><p>安装U盘拿掉后，这个U盘就成为 /dev/sdb 了。</p> <ul> <li><p class="first">配置有线网络。</p> <p>没网络的时候，可以直接设定ip应急，后面 netctl 才是正规设置：</p> <pre lang='bash'>
# ip addr add 192.168.0.100/24 dev enp0s4
# ip link set dev enp0s4 up
# ip route add default via 192.168.0.1
# echo nameserver 208.67.222.222 >> /etc/resolv.conf
</pre><p>觉得设备名 enp0s4 不习惯，也可以在 udev 中改名（重启生效）：</p> <pre lang='bash'>
# cat /etc/udev/rules.d/10-network.rules
SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="00:50:70:a2:49:7d", NAME="eth0"
</pre><p>如果使用 dhcd 动态分配地址：</p> <pre lang='bash'>
# dhcpcd        # 自动让 eth0 获取 IP
#               # 或者配置成服务自启动（更加方便）
# systemctl enable dhcpcd@eth0
# systemctl start dhcpcd@eth0
</pre><p>如果使用静态地址，现在是用 netctl 进行管理：</p> <pre lang='bash'>
# pacman -S ifplugd
# systemctl disable dhcpcd@eth0
# systemctl stop dhcpcd@eth0    # 要停掉 DHCP，不然有干扰
# cd /etc/netctl
# cp examples/ethernet-static home
# vi home           # 设置我的静态 IP 设置 profile
# systemctl enable netctl
# 重启一下，清除刚才的临时 IP 设置
# netctl start home
# netctl enable home
</pre><p>如果要快速切换网络环境， 再在 <tt class="docutils literal">/etc/netctl/</tt> 下建立一个新的 profile 文件， 用 <tt class="docutils literal">netctl <span class="pre">switch-to</span> PROFILE</tt> 来进行切换，会自动停掉旧的。 更详细的可以看 <a class="reference external" href="47">我以前写的 netctl 如何选择 profile</a> 。</p> </li> <li><p class="first">安装 vim，默认的 vi 实在是用不惯：</p> <pre lang='bash'>
# pacman -S vim
# pacman -R vi
# ln -s /usr/bin/vim /usr/bin/vi
</pre></li> <li><p class="first">关闭 PC 小喇叭。</p> <p>这个实在是太烦人了，在启动时就禁用：</p> <pre lang='bash'>
# cat /etc/modprobe.d/nopcspkr.conf
blacklist pcspkr
</pre><p>这个文件需要自己创建。</p> </li> <li><p class="first">安装 ntp 自动更新时间</p> <pre lang='bash'>
# pacman -S ntp libedit
# systemctl enable ntpd
# systemctl start ntpd
</pre><p>另外，Arch 建议在 <tt class="docutils literal">/etc/ntp.conf</tt> 中添加 iburst 参数，比如：</p> <pre lang='conf'>
server 0.pool.ntp.org iburst
server 1.pool.ntp.org iburst
server 2.pool.ntp.org iburst
server 3.pool.ntp.org iburst
</pre><p>检查 ntpd 同步情况：</p> <pre lang='bash'>
# systemctl restart ntpd
# ntpq -np
</pre><p>时间同步完成后，用 <tt class="docutils literal">hwclock <span class="pre">-w</span></tt> 写入硬件时钟。</p> </li> <li><p class="first">创建普通用户。</p> <pre lang='bash'>
# useradd -m fwolf
# passwd fwolf
</pre><p>通常，这个用户我们要赋予 sudo 权限：</p> <pre lang='bash'>
# pacman -S sudo
# cat /etc/sudoers.d/fwolf_sudo_conf
Defaults    env_reset
Defaults    secure_path="/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
fwolf   ALL=(ALL:ALL) ALL
%admin  ALL=(ALL) ALL
%sudo   ALL=(ALL:ALL) ALL
# chmod 0440 /etc/sudoers.d/fwolf_sudo_conf
</pre><p>注意， <tt class="docutils literal">/etc/sudoers.d/</tt> 下的文件，名称带有 <tt class="docutils literal">~</tt> 或者 <tt class="docutils literal">.</tt> 的不会生效， 参见 <a class="reference external" href="http://bugs.centos.org/view.php?id=5017">CentOS &#8211; 0005017: The #includedir directive in sudoers does not work</a> ， 文件属性也必须是 0440 。</p> </li> <li><p class="first">安装 Yaourt</p> <p>在 <tt class="docutils literal">/etc/pacman.conf</tt> 中添加：</p> <pre lang='conf'>
[archlinuxfr]
SigLevel = Never
Server = http://repo.archlinux.fr/$arch
</pre><p>然后 <tt class="docutils literal">pacman <span class="pre">-Sy</span> yaourt</tt> 完成安装。</p> </li> <li><p class="first">安装其他常用工具</p> <p>bash-completion ctags git htop openssh subversion tk</p> </li> </ul> </div>

<div class="section" id="id6"> <h3>图形系统</h3> <p>由于U盘要带着到处跑，所以图形驱动一定是什么都有。 也不追求多么花哨的界面效果，简洁明快，所以选择 LXDE+Fluxbox 。</p> <ul> <li><p class="first">字符界面分辨率</p> <p>默认进入字符界面后，分辨率是最大分辨率，如果要另行指定， 可以修改 <tt class="docutils literal">/etc/default/grub</tt> ：</p> <pre lang='conf'>
GRUB_CMDLINE_LINUX_DEFAULT="quiet video-1024x768M@75m"
</pre><p>然后 <tt class="docutils literal"><span class="pre">grub-mkconfig</span> <span class="pre">-o</span> /boot/grub/grub.cfg</tt> 重新生成 grub 配置文件。</p> </li> <li><p class="first">默认点亮 Numlock</p> <p>需要用到两个命令：系统自带的 setleds 和 通过 pacman 安装的 numlockx。</p> <p>要在字符界面下打开 Numlock，可以在 <tt class="docutils literal"><span class="pre">$HOME/.bashrc</span></tt> 中添加：</p> <pre lang='bash'>
# Numlock
if [ -x /usr/bin/setleds ]; then
    for tty in /dev/tty{1..6}; do
        /usr/bin/setleds -D +num < /dev/tty > /dev/null 2>&1
    done
fi
</pre><p>这样设置会在登录之后自动打开 Numlock，若要登录之前就打开，可以参照 <a class="reference external" href="http://wiki.archlinux.org/index.php/Activating_Numlock_on_Bootup_(简体中文)">Arch Wiki</a> 将上述内容添加到 <tt class="docutils literal">/etc/rc.local</tt> 或者 <tt class="docutils literal">/etc/inittab</tt> ， 但不如跟着用户配置容易备份。</p> <p>要在 X 下打开 Numlock，可以在 <tt class="docutils literal"><span class="pre">$HOME/.xinitrc</span></tt> 中添加：</p> <pre lang='bash'>
# Set numlock
if [ -x /usr/bin/numlockx ]; then
    /usr/bin/numlockx on
fi
</pre></li> <li><p class="first">安装 xorg 和显卡驱动</p> <ul class="simple"> <li>Xorg: xorg-server xorg-xinit xorg-server-utils mesa</li> <li>显卡驱动：xf86-video-ati xf86-video-intel xf86-video-nouveau nouveau-dri</li> <li>笔记本触摸板支持：xf86-input-synaptics</li> <li>测试 X 工作是否正常：xorg-twm xorg-xclock xterm</li> </ul> <p>现在可以用 startx 启动 X 看到简陋的图形界面了。 如果想用 Ctrl+Alt+Backspace 关闭 X，需要在 <tt class="docutils literal"><span class="pre">/etc/X11/xorg.conf.d/10-evdev.conf</span></tt> 中增加一段：</p> <pre lang='conf'>
Section "InputClass"
    Identifier "Keyboard Defaults"
    MatchIsKeyboard "yes"
    Option "XkbOptions" "terminate:ctrl_alt_bksp"
EndSection
</pre></li> <li><p class="first">安装 LXDE &amp; Fluxbox</p> <ul class="simple"> <li>LXDE 组的所有包</li> <li>Fluxbox</li> <li>监测文件系统变化的 Gamin</li> <li>常用软件：leafpad obconf epdfview</li> </ul> <p>配置一个简单的 <tt class="docutils literal"><span class="pre">$HOME/.xinitrc</span></tt> ，从 <tt class="docutils literal"><span class="pre">/etc/skel/.xinitrc</span></tt> 复制一份， 然后添加：</p> <pre lang='conf'>
#xrandr -s 1024x768 # 如果需要的话，提前指定分辨率
exec startlxde
</pre><p>现在都是液晶的天下，很少出现分辨率刷新率超出界限不显示的情况， 命令行下的分辨率可以用自动，嫌字小上面有修改 grub 设置的方法， 图形下 LXDE 也支持 auto 分辨率，一般也都自动设置好了。</p> <p>为了把 Openbox 换成 Fluxbox，需要修改 <tt class="docutils literal">/etc/xdg/lxsession/LXDE/desktop.conf</tt> ：</p> <pre lang='conf'>
[Session]
window_manager=fluxbox
</pre></li> <li><p class="first">中文相关</p> <ul> <li><p class="first">基本字体 ttf-dejavu artwiz-fonts wqy-microhei</p> </li> <li><p class="first">输入法 fcitx-im fcitx-configtool fcitx-fbterm ，在 <tt class="docutils literal"><span class="pre">$HOME/.xinitrc</span></tt> 里添加：</p> <pre lang='bash'>
export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=fcitx
export XMODIFIERS="@im=fcitx"
</pre></li> <li><p class="first">字体配置，把原先用的其他常用字体和配置文件都搬过来了， 就是 <tt class="docutils literal"><span class="pre">$HOME/.fonts</span></tt> 目录，Ubuntu 下用的很好，这里也可以直接用。 把 <tt class="docutils literal"><span class="pre">$HOME/.fonts/fonts.conf</span></tt> 链接为 <tt class="docutils literal">/etc/fonts/local.conf</tt> 即生效， 然后修改 <tt class="docutils literal">/etc/fonts/conf.avail</tt> 下的 <tt class="docutils literal"><span class="pre">40-nonlatin.conf</span></tt> 和 <tt class="docutils literal"><span class="pre">60-latin.conf</span></tt> 将 SimSun 或者其他你喜欢的字体设置为首选字体， 最后 <tt class="docutils literal">$ <span class="pre">fc-cache</span> <span class="pre">-vf</span></tt> 更新下字体缓存，重启 X 就可以了。</p> </li> </ul> </li> </ul> <p>至此，一个基本的、具备图形界面的 Arch Linux 就安装完成了， <tt class="docutils literal">pacman <span class="pre">-Scc</span></tt> 清理一下，已安装程序占用空间约 1.4G。 总体感觉，运行速度受U盘读写速度影响非常大，有时候会卡。</p> <p>&#8230;&#8230;大约反复两周后，经历了无数次的重装，我终于下了结论： U盘上的 Linux 系统除非只以只读方式使用，否则几乎没有可用性。 大概是因为重启、关机时，umount 总是等不及U盘的灯闪来闪去， 就强制重启或关机了，然后文件系统未正常 umount， 然后就是文件系统损坏，一修复都是文件丢失，损坏的 inode。 难道是因为我的U盘质量不好么？ 不管怎样，拿这个做随身系统的想法破灭了， 还是磁介质的机械硬盘靠谱一点。</p> <div class="section" id="id7"> <h4>参考</h4> <ul class="simple"> <li><a class="reference external" href="http://www.rodsbooks.com/gdisk/">GPT fdisk Tutorial</a></li> <li><a class="reference external" href="http://manual.aptosid.com/en/part-gdisk-en.htm">GPT gdisk partitioning overview</a></li> <li><a class="reference external" href="http://bbs.pcbeta.com/viewthread-1333881-1-1.html">非UEFI，BIOS引导GPT磁盘，MacOS + Linux + (Hybrid-MBR+扩展分区+Windows)</a></li> <li><a class="reference external" href="http://linuxtoy.org/archives/small-test-of-linux-system-hadrware-migration.html">Linux 硬件迁移小测试</a> （评论中的 <a class="reference external" href="http://linuxtoy.org/archives/small-test-of-linux-system-hadrware-migration.html#comment-295562">linux的两种 gpt 分区方案</a> 说得间接明了，但搜不到原出处）</li> <li><a class="reference external" href="http://www.sebastien-han.fr/blog/2012/10/29/optimized-your-ssd/">Optimized Your SSD</a></li> <li><a class="reference external" href="http://xfs.org/index.php/XFS_FAQ#Q:_Performance:_mkfs.xfs_-n_size.3D64k_option">Q: Performance: mkfs.xfs -n size=64k option</a></li> <li><a class="reference external" href="http://www.iteye.com/topic/636770">xfs文件系统优化</a></li> <li><a class="reference external" href="https://pracops.com/wiki/index.php/XFS_optimisation">XFS optimisation</a></li> <li><a class="reference external" href="http://qixinglu.com/post/ext4_filesystem_inode_used_space.html">优化 Ext4 分区格式化后占用空间</a></li> <li><a class="reference external" href="http://www.ruanyifeng.com/blog/2011/12/inode.html">理解inode</a></li> <li><a class="reference external" href="https://wiki.archlinux.org/index.php/Installing_Arch_Linux_on_a_USB_key">Installing Arch Linux on a USB key</a></li> <li><a class="reference external" href="http://www.rodsbooks.com/gdisk/mbr2gpt.html">Converting to or from GPT</a></li> <li><a class="reference external" href="http://comments.gmane.org/gmane.org.user-groups.ale/95901">Installing Arch Linux on USB drive (instability)</a></li> </ul> <!-- Substitution definitions for links --> <!-- Hyperlink targets --> </div> </div>

<div class="wp_rp_wrap  wp_rp_twocolumns"><div class="wp_rp_content"><h3 class="related_post_title">Related Posts</h3><ul class="related_post wp_rp"><li data-position="0" data-poid="in-7" data-post-type="none"><small class="wp_rp_publish_date">2013-01-15</small> <a href="http://www.fwolf.com/blog/post/7" class="wp_rp_title">在移动硬盘上安装 Arch Linux (2013-01)</a></li><li data-position="1" data-poid="in-47" data-post-type="none"><small class="wp_rp_publish_date">2013-05-18</small> <a href="http://www.fwolf.com/blog/post/47" class="wp_rp_title">原来 netctl 是这样选择 profile 的</a></li><li data-position="2" data-poid="in-392" data-post-type="none"><small class="wp_rp_publish_date">2008-03-27</small> <a href="http://www.fwolf.com/blog/post/392" class="wp_rp_title">virtualbox连接usb设备</a></li><li data-position="3" data-poid="in-375" data-post-type="none"><small class="wp_rp_publish_date">2007-12-15</small> <a href="http://www.fwolf.com/blog/post/375" class="wp_rp_title">安装配置fluxbox桌面环境</a></li><li data-position="4" data-poid="in-442" data-post-type="none"><small class="wp_rp_publish_date">2009-05-15</small> <a href="http://www.fwolf.com/blog/post/442" class="wp_rp_title">Ubuntu升级到9.04 Jaunty的变化和遇到的问题</a></li><li data-position="5" data-poid="in-417" data-post-type="none"><small class="wp_rp_publish_date">2009-03-22</small> <a href="http://www.fwolf.com/blog/post/417" class="wp_rp_title">机房搬家过程中的几件趣事</a></li></ul><div class="wp_rp_footer"><a class="wp_rp_backlink" target="_blank" href="http://www.sovrn.com/" rel="nofollow">Sovrn</a></div></div></div>
]]></content:encoded>
							<wfw:commentRss>http://www.fwolf.com/blog/post/416/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
							</item>
		<item>
		<title>Claws Mail 不识别 PHPMailer 发送的附件</title>
		<link>http://www.fwolf.com/blog/post/415</link>
				<comments>http://www.fwolf.com/blog/post/415#respond</comments>
				<pubDate>Wed, 03 Jul 2013 06:25:00 +0000</pubDate>
		<dc:creator><![CDATA[Fwolf]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Claws Mail]]></category>
		<category><![CDATA[mail]]></category>
		<category><![CDATA[PHPMailer]]></category>

		<guid isPermaLink="false">http://www.fwolf.com/blog/post/415</guid>
				<description><![CDATA[环境：Claws Mail 3.9.1, PHP 5.4.16, PHPMailer 5.2.6 c5e9f7873f 现象：PHPMailer 发送带附件的邮件，直接使用 AddAttachment() 方法 $mailer->AddAttachment($attach_file); 没有其他设置。Claws Mail 收到信以后，查看邮件内容为空白， 附件栏显示： message/rfc822 multipart/mixed 以下就是空白了。 而能够正常识别附件的邮件，附件栏内容一般为： message/rfc822 multipart/mixed text/plain text/html （这个是附件的 mime 类型） gmail 和 mutt 中识别这样的邮件是正常的。 分析：通过对比正常和不正常的邮件原始码， 发现不正常邮件在声明内容是分节之后，多了一句传输编码声明，比如： Content-Type: multipart/mixed; boundary="b1_95a848b14cb4385965320b915d5829dd" Content-Transfer-Encoding: base64 最后的 Content-Transfer-Encoding 就是比正常邮件多的一行。 由于邮件原始码的这个部分，只是用来声明后续邮件是多个部分组成， 并定义了每个部分的辨识边界 boundary，并没有实际的内容， 所以应当是不需要声明编码类型的。在 PHPMailer 中相关代码为： public function GetMailMIME() { $result = ''; &#8230; <a href="http://www.fwolf.com/blog/post/415" class="more-link">Continue reading <span class="screen-reader-text">Claws Mail 不识别 PHPMailer 发送的附件</span></a>]]></description>
								<content:encoded><![CDATA[<p><!-- -*- mode: rst -*- --> <!-- -*- coding: utf-8 -*- --></p>

<p>环境：Claws Mail 3.9.1, PHP 5.4.16, PHPMailer 5.2.6 <a class="reference external" href="https://github.com/PHPMailer/PHPMailer/commit/c5e9f7873f6ed025dfc50ce481766287cfc3f18d">c5e9f7873f</a></p>

<p>现象：PHPMailer 发送带附件的邮件，直接使用 AddAttachment() 方法</p>

<p><pre lang='php'>
$mailer->AddAttachment($attach_file);
</pre></p>

<p>没有其他设置。Claws Mail 收到信以后，查看邮件内容为空白， 附件栏显示：</p>

<p><pre>
message/rfc822
    multipart/mixed
</pre></p>

<p>以下就是空白了。 而能够正常识别附件的邮件，附件栏内容一般为：</p>

<p><pre>
message/rfc822
    multipart/mixed
        text/plain
        text/html   （这个是附件的 mime 类型）
</pre></p>

<p>gmail 和 mutt 中识别这样的邮件是正常的。</p>

<p>分析：通过对比正常和不正常的邮件原始码， 发现不正常邮件在声明内容是分节之后，多了一句传输编码声明，比如：</p>

<p><pre>
Content-Type: multipart/mixed;
    boundary="b1_95a848b14cb4385965320b915d5829dd"
Content-Transfer-Encoding: base64
</pre></p>

<p>最后的 Content-Transfer-Encoding 就是比正常邮件多的一行。</p>

<p>由于邮件原始码的这个部分，只是用来声明后续邮件是多个部分组成， 并定义了每个部分的辨识边界 boundary，并没有实际的内容， 所以应当是不需要声明编码类型的。在 PHPMailer 中相关代码为：</p>

<p><pre lang='php'>
  public function GetMailMIME() {
    $result = '';
    switch($this->message_type) {
      case 'inline':
        $result .= $this->HeaderLine('Content-Type', 'multipart/related;');
        $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1].'"');
        break;
      case 'attach':
      case 'inline_attach':
      case 'alt_attach':
      case 'alt_inline_attach':
        $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;');
        $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1].'"');
        break;
      case 'alt':
      case 'alt_inline':
        $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
        $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1].'"');
        break;
      default:
        // Catches case 'plain': and case '':
        $result .= $this->TextLine('Content-Type: '.$this->ContentType.'; charset='.$this->CharSet);
        break;
    }
    //RFC1341 part 5 says 7bit is assumed if not specified
    if ($this->Encoding != '7bit') {
      $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
    }
</pre></p>

<p>特意加上了这个申明，因为按照 RFC1341，7bit 编码类型是默认的。</p>

<p>解决： 或许问题是出在 Claws Mail 上，但我暂时只能修改 PHPMailer 来适应这个问题了。 上面的问题弄清楚之后，在 multipart 后面不添加传输编码声明即可：</p>

<p><pre lang='php'>
    //RFC1341 part 5 says 7bit is assumed if not specified
    // Not after multipart/mixed, claws-mail will not recoginize attachment
    if (($this->Encoding != '7bit') &amp;&amp; (!in_array($this->message_type, array(
        'attach',
        'inline_attach',
        'alt_attach',
        'alt_inline_attach',
    )))) {
      $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
    }
</pre><!-- Substitution definitions for links --> <!-- Hyperlink targets --></p>

<div class="wp_rp_wrap  wp_rp_twocolumns"><div class="wp_rp_content"><h3 class="related_post_title">Related Posts</h3><ul class="related_post wp_rp"><li data-position="0" data-poid="in-37" data-post-type="none"><small class="wp_rp_publish_date">2013-05-12</small> <a href="http://www.fwolf.com/blog/post/37" class="wp_rp_title">同步 Claws Mail 的回收站到邮件服务器</a></li><li data-position="1" data-poid="in-155" data-post-type="none"><small class="wp_rp_publish_date">2006-04-14</small> <a href="http://www.fwolf.com/blog/post/155" class="wp_rp_title">终于能够通过phpmailer使用gmail账号发送邮件了</a></li><li data-position="2" data-poid="in-176" data-post-type="none"><small class="wp_rp_publish_date">2006-05-23</small> <a href="http://www.fwolf.com/blog/post/176" class="wp_rp_title">让phpmailer支持中文名称的附件</a></li><li data-position="3" data-poid="in-33" data-post-type="none"><small class="wp_rp_publish_date">2012-12-11</small> <a href="http://www.fwolf.com/blog/post/33" class="wp_rp_title">PHP foreach 中使用引用的注意事项</a></li><li data-position="4" data-poid="in-451" data-post-type="none"><small class="wp_rp_publish_date">2010-06-29</small> <a href="http://www.fwolf.com/blog/post/451" class="wp_rp_title">Apple Mail 邮件太多不下载问题的解决</a></li><li data-position="5" data-poid="in-379" data-post-type="none"><small class="wp_rp_publish_date">2008-01-12</small> <a href="http://www.fwolf.com/blog/post/379" class="wp_rp_title">[Mutt]用msmtp替代esmtp作发信代理</a></li></ul><div class="wp_rp_footer"><a class="wp_rp_backlink" target="_blank" href="http://www.sovrn.com/" rel="nofollow">Sovrn</a></div></div></div>
]]></content:encoded>
							<wfw:commentRss>http://www.fwolf.com/blog/post/415/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
							</item>
	</channel>
</rss>
