4
15
2017
0

卸载被挂载点掩蔽的挂载点

刚刚遇到一件很囧的事情:我在 /run/user/1000/cache 挂载了我的 SSD,用作火狐和 neocomplete 的缓存。/run/user/1000 这个目录是 systemd 为用户创建的,用来放那些只在运行时有用的文件,比如 pid 文件啦、套接字啦之类的。把挂载点放这里,很显然可以避免为其在磁盘上创建目录,又不必和 /tmp 里的一堆临时文件混在一起。

然而这一次,出大事了!我的火狐启动不了了!我的 Vim 也报了一堆错!细看下来,发现 /run/user/1000/cache 没了……

因为需要 root 权限,/run/user/1000/cache 是在 /etc/rc.local 里挂载的。这一次,它抢先挂载了 /run/user/1000/cache,然后我登录,systemd 帮我挂载了 /run/user/1000。就是下边这个样子:

├─/run                           run        tmpfs          rw,nosuid,nodev,relatime,mode=755                                                shared
│ ├─/run/user/1000/cache         test       zfs            rw,xattr,posixacl                                                                shared
│ └─/run/user/1000               tmpfs      tmpfs          rw,nosuid,nodev,relatime,size=804780k,mode=700,uid=1000,gid=1000                 shared
│   └─/run/user/1000/gvfs        gvfsd-fuse fuse.gvfsd-fus rw,nosuid,nodev,relatime,user_id=1000,group_id=1000                              shared

WTF!这样我就访问不到它了呀!我一开始还以为我的 SSD 又出什么状况了呢,结果是这样,挂载上了,但是访问不到……而因为访问不到,所以也没法卸载……

当然啦,我可以先把 /run/user/1000 和下边的那个 gvfs 给卸载掉。但那样做,我不确定 systemd、PulseAudio、D-Bus 它们会有多生气。bind mount 也尝试了,然而并没有什么用。它只能用来访问被挂载点掩蔽的文件,访问不到被挂载点掩蔽的挂载点。

然后我想到了之前玩过的网络命名空间。当然这次需要的是之前没仔细探索的挂载命名空间了。

直接 sudo unshare -m 进去,findmnt -o+PROPAGATION 发现全部都是 private 的,也就是 umount 了不影响外边。于是我就可以把 /run/user/1000 这个树卸载掉啦。然后 mount --make-shared /run/user/1000/cache 把它变成 shared 状态,再卸载,应该就可以把外边那个也卸载掉了吧?

No。失败了。研究了半天 unshare、mount_namespace 的文档之后确认,把 private 的挂载点变成 shared 之后,会创建一个新的「共享组」,而只有在同一个「共享组」里的挂载点才会相互传播。所以,unshare 你别把我的挂载点都变成 private 了好么?

文档下翻,它还真有这么个选项:

sudo unshare -m --propagation shared

然后里外执行这条命令,确认一下「shared:」后边那个数字是一致的:

# cat /proc/self/mountinfo | grep zfs
282 281 0:47 / /run/user/1000/cache rw shared:137 - zfs test rw,xattr,posixacl

没问题了。先 mount --make-private /run/user/1000 等把它们变成私有的,卸载掉,再把 /run/user/1000/cache 给卸载掉。来外边一看,果然被卸载掉啦~

(然后我还是为其在磁盘上专门建立个目录防止出问题好了。zfs,不知道怎么写 systemd 的 .mount 文件。)

Category: Linux | Tags: linux
3
14
2017
18

我的 zsh 提示符

这是我用了多年的 zsh 提示符。

My zsh prompt

右提示符比较简单,先说。

首先,这个右提示符是 zsh 才支持的,不是 hack 左提示符来的哦。

我的右提示符显示的是(提示符打印出来时的)时间。在有后台任务时,会在左边以黄色显示出后台任务的数量,增加些许后台默默工作的进程的存在感啦。

截图中可以看到,只有最后一行才显示了右提示符(以至于我截图都得 hack 一下)。我使用了setopt transient_rprompt,这样 zsh 会清掉旧的右提示符,就不会影响复制了。以前每次复制时都带上一堆空格然后几个时间,折行之后根本没法看,后来才发现体贴的 zsh 已经有这么个选择了。

另外,在输入命令到右提示符时,右提示符会自动消失,以免和命令混淆。都说了很体贴的哦~

左边,是一个两行的提示符。之所以做成两行,是为了保持命令的起始位置不会因为提示符的长度变化而变化,每次输入新命令的时候,光标都在同一列,易读好找。我就不明白,那些坚持 bash 默认提示符的人是怎么坚持下来的,用着用着不知道自己光标去哪里了……对了,zsh 在输出提示符时,会保证它从终端最左边那一列开始输出。如果上一行不完整,zsh 会打印一个反色的「%」来表示(截图里 ^C 那里就有一个)。

蓝色「>>> 」是学 Python 的,但是使用了蓝色以免和 Python 混淆。如果是 root 用户,则显示红色的「### 」以警示。这个比较刺眼,所以就尽量不用 root 跑 shell 啦。

第一行开头是命令序号,就是历史记录里有多少条命令。每执行一条命令它就会加一,空行或者 Ctrl-C 放弃的不算。其实没什么用的样子。

然后是一个用于标识不同机器的名字。比如这里 lilywork 表示我正在我的工作机上。我家里那个系统里不会显示这个。这个信息可以通过ZSH_PS_HOST变量来设置,比如一般可以设置成$(hostname)。GitLab 之前的提示符里大概没有这个吧。

再就是最后一条命令的状态码($?)。如果命令成功就不显示,否则显示一个红色的数字,以提示上条命令出错了。所以说了嘛,我没法理解坚持使用 bash 及其默认提示符的人……

然后是缩短过的当前目录。~tmp是我的临时目录,有名字(hash -d tmp=....)的。但是它不会缩短中间路径的名字,反正我在它下边写命令,不用担心路径太长。不过我不建议深入探索 nodejs 的模块树,显示好几行的路径并不好看的。

最后一项又是可选的,git 当前分支。这个功能是我自己写的,不是 zsh 自带的那个,是异步显示的哦~忙着干活呢,不能在这种小事上浪费时间、中断思绪嘛。并且还可以通过设置来排除一些目录,比如访问特别慢的远程目录,比如已经死掉很久的 Wuala。

显示的信息不多,也一点都不华丽,但十分有用呢。

介绍完毕,提示符的定义我这里就不写啦。代码都在这里:https://github.com/lilydjwg/dotzsh

Category: shell | Tags: zsh linux
3
10
2017
6

在 Vim 8 里用 git subrepo 安装 vim-go

我一直没有使用 Vim 插件管理插件。我没数过,但是三四个实现肯定是有的。我不喜欢它们的原因,一是迁移成本,二是依赖太巨大:我在一个新环境上配置 Vim 时,我不希望必须访问 GitHub,而且是几十个 clone,这得多慢啊……而且这还意味着它需要有 git,能够联网,DNS 解析正常,等等。这些在各种奇怪的环境里都不容易实现啊。

后来,Vim 8 出来了,内建 packages 管理功能。不愧是官方出品,没有奇怪的依赖。插件来源用户随意,把文件放对位置就可以了。

然后,我又遇见了 git-subrepo,给了 submodule 以外的选择。简单来说它有点 vendoring 的感觉,把第三方仓库放自己里边了。如果目标没有安装 git-subrepo,也没有关系,所有文件都在这儿了,只是没有与第三方仓库同步的能力了而已。

而且,git-subrepo 和 git-notes 类似,它使用额外的 ref 来存储第三方仓库的数据。但与 notes 不同的是,subrepo 已经存在于第三方仓库了,所以我不必把 subrepo 的 ref 推得到处都是,还在每个地方 fetch 下来浪费空间。万一第三方仓库没了或者搬家了,关系也不大,反正我用的代码还在我的仓库里呀。

git-subrepo 是很棒的「pay as you go」设计呢。

有了这两个东西,我就可以尝试一下新的 Vim 插件管理方案了。刚好我需要安装 vim-go,所以就开始尝试啦~

于是开始安装:

cd ~/.vim
git subrepo clone git@github.com:fatih/vim-go.git pack/go/start/vim-go

Vim 8 会自动加载pack/*/start/*下的东西(它下边的目录跟原来的 ~/.vim 布局和用法一样),:packadd命令会加载pack/*/opt/*下的东西。

然后记得设置环境变量。首先是 GOPATH,这是放所有 Go 的源码和编译出来的库和二进制文件的地方。Go 1.8 开始默认 ~/go,但是也需要设置 GOPATH,不然 vim-go 不认。然后得把 $GOPATH/bin 加到 PATH 里去。

确认环境变量设置好之后,打开一个新的 Vim,执行:GoInstallBinaries命令安装依赖。如果中途有神秘失败的,可以把地址拷出来,在命令行里手动调用 go install xxx 安装。部分软件需要访问 Google 的服务器,国内用户注意自行配置一下国际互联网的访问。

安装好之后就有补全、自动格式化、自动加 imports、重命名什么的啦。具体看 vim-go 的文档吧。不过有几点我稍微调整了一下。

我使用 syntastic 来进行代码检查。它默认不启用针对 Go 的检查,需要配置一下:

let g:syntastic_go_checkers = ['go', 'golint']

syntastic 的显示效果比 :GoMetaLinter 命令使用 quickfix 窗口的要好很多哦。

另外不要使用 :GoLint 这个命令,它连非常简单的未定义变量都检查不出来。

而且 vim-go 好 chatty,连跳转到定义都要用显眼的颜色来报告一下成功了……安静真的很珍贵的说。

:GoDoc 我还不会用,因为它报错了:

vim-go: gogetdoc: couldn't get package for .../t.go: can't find package containing .../t.go^@

写 Go 的时候,特别是调试的时候,加句fmt.Printf得记得修改 import,不需要了还得再去删掉才能通过编译……Go 编译是快了,但是处理未使用变量比等待编译结束更令人心烦啊。

有了 goimports 这个命令之后,不需要在开发过程中反复手动修改导入的包列表了。它可以自动添加和删除 import。不过 vim-go 并没有提供在保存时自动调用的支持,所以我就自己动手了。

首先禁用掉它自己的自动格式化:

let g:go_fmt_autosave = 0

然后,是我自己设置的自动命令:

if !exists('#GoImports') && executable("goimports")
  augroup GoImports
    au!
    autocmd BufWrite *.go silent call s:GoImports()
  augroup END
endif

function! s:GoImports()
  let pos = getpos('.')
  let na = line('$')
  %!goimports
  if v:shell_error
    undo
  endif
  let nb = line('$')
  let pos[1] = pos[1] + nb - na
  call setpos('.', pos)
endfunction

还有待提高(比如 undo 的处理),但至少能用。

Category: Vim | Tags: vim go Git
2
28
2017
9

如果重回到学生时代,我想这样做

试题太多了做不完就挑喜欢的做。自习没意思就去图书馆里借书看。累了就休息,困了就睡觉。

老师要是有意见,就告诉TA,你别管我这么多,反正考试的时候给你拿年级前五。要是还不同意,每次考试时就这么干:

所有单选题,一律选正确答案后边那项。多选择题该全选的就选A,否则就只选错误的部分。数值填空题就把正确值加一再填上,解答题就只写上答案,然后解释说太困了就不写过程了,或者手写作业写酸了过程就省掉了。英文填空就填反义词。没反义词的就随便找个押韵的词填上好了。作文当然向现在网传的各种高考零分作文看齐。要不就写社论。社论太敏感就写相对论,或者总结一下微积分啊抽象代数啥的,也可以教教阅卷老师编程。

当然抗议完了,有意思的东西还是照学不误。除了高考这样的考试,分数都是老师家长的,但知识和思考能力是自己的。反正推掉了那么一大堆重复的试题,自己有的是时间把那么点儿知识学得融会贯通嘛。当然在此之前,要对自己好点,该吃就吃,慢慢吃,要吃得健康。到点就睡觉,休息好,精神爽,身体棒,才能够好好地生活。


我的学生时代,父母听信了 CCTV 和学校老师的谎言,为虎作伥,编织了一个美丽的谎言。在那时候,没有人关心我的感受,关注我的将来、我的命运。那是一个充满敌意的世界。那是一段灰暗无光的童年与青春。直到结束了他们制定的行程,走入社会多年,我才发现,那个美丽的未来不过是个谎言,是牢笼的围栏,也是那个充满敌意的世界里虚构的天堂。


To be who you are and become what you are capable of is the only goal worth living. —Alvin Ailey
Category: 未分类 | Tags: 生活 教育
2
25
2017
17

中键的功能

鼠标中键,就是左键和右键之间的那个键啦。常见的鼠标上它在滚轮上。所以你知道了,滚轮是可以往下按的哦。如果是触摸板并且没有中键的话,可以配置双指点击来作为中键使用的(synclient ClickFinger2=3)。

中键具有以下好用的功能哦~(括号里是适用的场景)

  • 粘贴选择区,不用按复制和粘贴的快捷键了~不过选择区的寿命通常比较短,只适合快速的粘贴操作。另见 X Window 中的剪贴板一文。(Linux 桌面、macOS 终端、gpm)
  • 在后台新标签页打开链接(火狐、Google Chrome 等浏览器都支持)
  • 关闭标签页(基本上也是用于网页浏览器。我自己的 GVim 也支持)
  • 定位滚动条,可以快速地定位到开头、结尾,或者之前的位置。不需要拖来拖去的麻烦。可惜 GTK 3 里这个功能不好用的了。(GTK 2、Qt)
  • 移动画布(GIMP、Inkscape 等作图软件、GNOME 的文档查看器 Evince)

这只是比较通用的功能。我的 Awesome 还配置了使用中键关闭窗口呢(「关闭标签页」语义的扩展)。火狐的一些菜单项也支持中键点击,比如书签菜单,右键的「查看图像」菜单,比如前进/后退按钮,以及在它上边点击右键出来的历史记录项目。

总结一下中键的语义:

  • 在可以粘贴的地方,粘贴
  • 在打开对象时,打开新对象而不取代已有者
  • 在打开的对象本身上时,关闭之
  • 在可定位对象上,移动之
Category: Linux | Tags: linux X Window X window
2
4
2017
15

使用 Reabble 在 Kindle 上阅读 InoReader 里的文章

2017年02月08日更新:已经无法通过 InoReader 的 OAuth 功能登录。现只能通过提交 InoReader 账号和密码到 Reabble 的方式登录。我正考虑放弃此服务。


InoReader 的核心在于阅读。Kindle 的核心也在于阅读。

InoReader 的重点在于,它是在线 RSS 阅读器,手机 app 还支持离线,不仅可以在电脑前研读,还可以随时随地使用手机来闲读。可有个问题:长时间盯着 LCD 屏幕看,对眼睛不好!

而这正是使用电子墨水的阅读器——如 Kindle——所解决的问题。所以,怎么把两者结合起来呢?

土木坛子介绍了一个名为 kindle4rss 的服务,通过电子邮件推送 RSS 源。其实我之前也听朋友说过,RSS 源是可以推送到 Kindle 的。但是这样是针对单个的 RSS 设置,推送到 Kindle 的部分不能和其它地方的阅读同步。然后,我顺着 kindle4rss 看了一下,忽然眼前一亮:他们基于 InoReader 的 API 做了一个网页版的、适合 Kindle 使用的阅读器!

就是 Reabble 啦。其实它支持各种浏览器的,只是配色、操作方式是为 Kindle 优化的。(说起来,我挺讨厌像美团招聘或者 AirDroid 局域网 HTTPS 版那样故意不支持特定客户端的行为,明明能用的,却偏偏不让用户用。)

直接访问就可以试用啦。黑白的界面,在电脑上看着挺丑的,不过在 Kindle 上看就大不一样啦。左边是文章列表界面(调整过选项,隐藏了侧栏和已读文章),右边是文章阅读界面(打开了菜单):

Reabble 文章列表 Reabble 文章阅读

在 Kindle 上的体验非常好。而且 Kindle 上的登录做得非常棒:只需要在电脑上通过 InoReader 的 OAuth 授权登录,之后就可以获得一串代码,在 Kindle 那边填写就可以了。我的 InoReader 是用 Google 账号登录的,要是让我在 Kindle 上登录我大概会直接放弃的。

它要求有 Wi-Fi 网络(废话,Kindle 那个破浏览器又不支持离线模式)。不过这对我来说不是问题。真要没 Wi-Fi 的话,用手机开个热点用也成。

不过有些小问题:

  • 不支持广播和赞,只支持加星标。
  • 侧栏里没有未读文章的项、以及星标数不能隐藏。
  • 免费用户只能每天阅读15篇文章,但是并没有阅读到那么多就会出现提示。好像重新打开又可以继续读了。

最后,这服务收费也非常便宜,一年只要18RMB,订更久还会更便宜~最重要的是,它的支付方式对于我很方便!(谁去帮 InoReader 接入支付宝或者微信支付吧,这样我就不用看广告了~)另外,推荐它的话,可以获赠两年的使用权。

Category: 网络 | Tags: 阅读 rss kindle InoReader
1
6
2017
3

如何快速高效地修 bug?

看到知乎上的一个问题,心血来潮,随意写写,请读者不要太较真。

看回答,有一些可操作性很强的答案。但是呢,你知道的,考试好不代表能力强,如果你只是学习别人的方法而并不理解,那么学来之后只会是东施效颦而不能融会贯通。所以呢,我也来发表一下自己的见解。

首先,你要定位 bug。这时,你需要:

  1. 注重逻辑性。不要做没有证据的结论。如果你有猜测,就去证实或者否定它。比如某次,同事代码返回的数据有问题,认为是缓存用的 Redis 有问题,返回了错误的数据。然而没人去对此猜测进行求证……我去确认了一下,Redis 收到了请求,并且响应正常。接下来,排除所有其它可能的原因之后,最后剩下的那个就是真相。真相就是,代码里有个 } 的位置放错了,因为它刚好在一屏之后的位置,所以没有人发现……(是 Vim 帮我找到的)
  2. 基本的方法论。比如二分法。比如最小化测试用例。如果你要提问,要懂得提问的智慧,不管是向搜索引擎还是向人,你都需要提出正确的问题
  3. 知识面。你写 Web 后端的话,普通的 HTTP 得懂,浏览器的开发者工具得会用。简单的 JavaScript 也有会点儿。简单地说就是,你要精于你自己主攻的部分,然后要熟悉你的上下游。再比如如果你使用 CPython 的话,你要准备一份 CPython 的源码,并且要能够流畅地阅读 C 代码。
  4. 工具。工欲善其事,必先利其器。一大堆调试用的工具,你至少得知道它们能干什么,需要的时候能用。比如 strace、lsof、gdb、git bisect,还有高级点的 sysdig、systemtap、perf 等等。当然还有一堆不是专门为调试而设计的通用工具,比如 the silver searcher 或者 ripgrep。一个快速的全文搜索工具能帮你在最短时间内找到相关的代码或者日志。你不必成为正则表达式大师,但是简单的一定要会,不然面对上千个匹配结果你要怎么办呢?Vim 有一个插件 Mark,能够同时高亮多个模式,非常利于调试期间阅读代码和日志。投入时间学习使用高效的工具,不要把时间浪费在等待和人工搜索上,也不要让自己忙于琐事而断了灵感和线索。

最后,不要不断地、毫无目的地换个环境啦,换个版本啦,换个用户啦,这样子找问题。如果这样做很有效的话,大家都去买彩票去了。

找到 bug 之后,理解它是如何产生的。当你理解之后才能真正修好它。就像你感冒了吃抗生素,根本没有用。

Category: 编程 | Tags: 编程 软件开发
1
5
2017
17

我使用的 Xposed 模块

开始使用 Xposed 之后,我对我的手机又多了一份拥有感,然后呢,装的模块越来越多了。以下是我正在使用的模块的列表,以及我为什么使用它们。链接我就懒得放了,想要安装的读者可以自己去 Xposed Installer 里搜。

绿色守护。装上这个我才敢装各种国产应用。它的 Xposed 模块用于功能增强,最重要的一点是,它可以切断唤醒途径。这样就不会总也杀不死那些耗电又耗流量的应用们了。

去你大爷的内置浏览器。我发现 Android 6 里,好多 Google 家的应用都开始默认使用内置浏览器了呢……不过国外的应用一般都是可以选择在内置浏览器里打开,还是外部浏览器里打开的。我更喜欢在外置浏览器里打开,一来减少相同的缓存和数据文件,节约存储空间,因为缓存共享而加快加载速度,二来能够使用自己的配置(比如广告拦截),并且能够使用最新的浏览器特性。上次听说了一个很棒的浏览器特性来着,然后就有人告诉我微信里不支持……当然了,微信这种应用,为它的内置浏览器增加了接口,有些网页必须在它里边打开。所以这个模块是有白名单的。

微信防撤回模块。顾名思义啦。

Android通话振动。Android 4.0.4 有一个很贴心的功能:在拨出电话接通时,它可以振动一下,告诉用户已经接通了。所以就不用一直把电话放在耳边等着啦,有时候等着等着,因为某些原因呼叫终止了还傻傻地等着……不知道为什么,后来的版本就没有这个功能了。还好我们有 Xposed。这个模块不仅把接通时振动给加回来了,还可以挂断时振动,以及如果对话费敏感的话,可以定时振动。

App Settings。目前我用来强制QQ轻聊版出现在最近使用的应用列表中。以后还可能需要强制某些中文翻译拙劣的应用使用英文语言。

Battery Stats Plus。这是一个同名应用带的模块。用于电池使用统计。

Xposed Torch。不需要解锁屏幕然后点来点去的手电筒。在锁屏状态下长按音量上键就可以启动了,再按一下音量下就关闭了。方便好用~

XPrivacy。权限管理。也是使用国产应用时必备的功能。虽然 Android 6 里,很多权限都像 iOS 那样在运行的时候询问了。但是呢,流氓总有流氓的手段,你要拒绝授权?那好,一切功能免谈,你卸载我吧。

XuiMod。我用来让右上角的时间显示秒数的。

哇已经装了九个模块了呢。其实我是不希望用这么多 Xposed 模块的,毕竟是打补丁嘛。可是呢,毕竟不是自由软件,只能这样了。也幸好我们还能打补丁。

Category: Android | Tags: Android Xposed
1
2
2017
3

在 Android 上运行 sshd

新的 Z5C 到手。拿 root 装软件。然后发现一个很重要的事情:我之前在 Z3C + Android 4.4.4 上用得好好的 Rooted SSH/SFTP Daemon,在登录的时候报了这么个错:

CANNOT LINK EXECUTABLE: "/system/lib/libc++.so" is 32-bit instead of 64-bit
page record for 0xXXXXXXXXXX was not found (block_size=32)

网上搜了一下,解决方法是有的,要重新编译 dropbear。可我之前研究过,我这软件使用的 dropbear 是一个修改版,和我用的这个 app 一样,好久没更新了……

于是想找个新的 sshd。之前我是使用的 SSHDroid。后来它需要付费版才能使用密钥认证了……而我的要求就两点:可以以 root 身份登录,并且支持密钥认证。在 Play 商店里能找到的 sshd 我都试过了一遍,竟然没一个能满足这么基本的需求的…………

之所以需要以 root 身份登录,而不是登录之后再获取 root,是因为跑命令时 su 之后很容易出现奇怪的问题,和缓冲、终端控制有关。

于是我只好失望地放弃使用 app,转到自己熟悉的领域——Linux 系统,编译一个 sshd adb 进去跑好了。

一开始使用的是 socat + tinyssh 的方案。这个方案我之前在光猫上实现过,tinyssh 的代码很少,很容易编译和修改。socat 直接用之前编译的版本就可以了。因为 Android 毕竟不是完整的 Linux userland,所以得把 tinyssh 改一改,主要是用户主目录和默认 shell 的部分。我就直接硬编码进 root 的配置了。然后写个 shell 脚本来启动:

#!/system/bin/sh

export ANDROID_ROOT=/system ANDROID_DATA=/data
PATH=/system/xbin:/su/xbin:/su/bin:/sbin:/vendor/bin:/system/sbin:/system/bin
socat tcp-l:PORT,reuseaddr,fork exec:'tinysshd /data/tinyssh/keydir' &

这样就可以了。只支持 Ed25519 密钥登录,挺好的。

然而,用着用着就发现有点小问题:socat 对经由网络的数据进行转发,有点低效;tinyssh 不支持连接复用,在一个会话中收到新的连接请求时会直接退出;还没有 scp 命令……

一开始我去 dropbear 那边编译了一个 scp。编辑好配置文件、开始 make 的时候,敲「make PROGRAMS=scp」就可以编译出一个 scp 命令了。然后我就想,既然都用上 dropbear 了,要不就都用了吧。于是把 dropbear 也编译出来了。不是很顺利,主要是以下几个事:

  • 改路径。各种路径,host key 的,pid 文件的,默认 PATH,还要禁用掉 lastlog 和 syslog 什么的
  • 改用户信息。默认 shell、主目录。不要检查 /etc/shells。刚刚发现我还不小心把其中两行代码交换了,是说怎么退出的时候会段错误呢 _(:з」∠)_
  • dropbear 的构建系统不支持 out-of-tree 构建,也就是不能像我习惯的那样,「mkdir build-android」然后进去「../configure」 :-(

另外就是,dropbear 不支持 Ed25519 key,于是我只好用 RSA key 了(DSS 有问题;openssh 的 ECDSA 实现也有问题) :-(

弄好之后同样写个 shell 脚本方便调用:

#!/system/bin/sh

export ANDROID_ROOT=/system ANDROID_DATA=/data
/system/xbin/dropbear -R -p PORT

然后,启动服务的事情。我发现改 /init.rc 不管用。这个是 initramfs,每次重启之后就恢复原状了……我懒得去重新打 initamfs 的包了,就每次重启系统之后接上 USB 线,然后 adb shell 进去跑脚本……还好 Z5C 跟 Z3C 不一样,USB 口在外边,很好插。

终于把 remote root shell 弄好了,接下来就是各种 rsync 和 scp 传文件改配置什么的了,一是复制各种软件的配置文件和数据,二是备份,三是把文件拿电脑上研究、编辑,方便啊!Sony 有个「换机助手」软件,但是它不能在加密了的手机上使用……

最后,还留下了一个问题:同样的环境,同样是 Wi-Fi 传输,我的电脑和 Z3C 之间传输速度能达到 4MiB/s,但是 Z5C 却只有 300KiB/s 左右的样子……

Category: Android | Tags: ssh Android 交叉编译
12
22
2016
5

利用 systemd 的 watchdog 功能重启卡住的服务

我在用 offlineimap。用着用着就发现一个问题:偶尔 offlineimap 会卡在网络上不动弹了。跟 getmail 一个德性……

但是 offlineimap 又跟 getmail 有点不一样,它是持续运行着的。虽然非要把之前那个 killhung 程序拿来用不是不可以,但我还是重新弄了一个更优雅的方案:systemd watchdog。

我的 offlineimap 本来就是用 systemd 服务的方式来跑的,所以很适合这样的改造呢。只是,当我瞅了一眼源码之后,我就放弃了 patch offlineimap 的打算。很难在合适的地方添加 watchdog 相关的代码。

既然从内部着手不好做,那就从外部写一个 wrapper 好了,反正 offlineimap 跟 getmail 不一样,正常情况下一直在输出东西,就把这个作为它的「心跳」特征好了。当然这个 wrapper 还可以给其它程序用。

于是,watchoutput 程序诞生了!稍微改一下 offlineimap 的 .service 文件,像这样子就好了:

[Unit]
Description=Offlineimap Service

[Service]
Type=notify
ExecStart=.../watchoutput /usr/bin/offlineimap
TimeoutStopSec=3s
SyslogIdentifier=offlineimap
Restart=on-failure
WatchdogSec=70
LimitCORE=0

[Install]
WantedBy=default.target

加上LimitCORE=0是为了阻止重启的时候由于 SIGABRT 信号导致 coredump,浪费磁盘空间。

用了几天之后,终于观察到一次由 watchdog 触发的重启:

12月 19 12:26:53 lilywork offlineimap[21623]:  Establishing connection to imap.exmail.qq.com:993 (main-remote)
12月 19 12:28:03 lilywork systemd[687]: offlineimap.service: Watchdog timeout (limit 1min 10s)!
12月 19 12:28:03 lilywork systemd[687]: offlineimap.service: Killing process 21623 (python3) with signal SIGABRT.
12月 19 12:28:03 lilywork systemd[687]: offlineimap.service: Killing process 21625 (offlineimap) with signal SIGABRT.
12月 19 12:28:03 lilywork systemd[687]: offlineimap.service: Main process exited, code=dumped, status=6/ABRT
12月 19 12:28:03 lilywork systemd[687]: offlineimap.service: Unit entered failed state.
12月 19 12:28:03 lilywork systemd[687]: offlineimap.service: Failed with result 'core-dump'.
12月 19 12:28:03 lilywork systemd[687]: offlineimap.service: Service hold-off time over, scheduling restart.
12月 19 12:28:03 lilywork systemd[687]: Stopped Offlineimap Service.
12月 19 12:28:03 lilywork systemd[687]: Starting Offlineimap Service...
12月 19 12:28:04 lilywork systemd[687]: Started Offlineimap Service.

没过几天,我又给这个 watchoutput 的脚本找到另外的用处:自动重启网络。

我家里的笔记本连 Wi-Fi 不知怎么,这些天经常会卡住(只发不收,一直处于 ARP 找网关的状态)。内核之前报过一次错,现在也没反应了。

于是:

[Unit]
Description=Watch for network availability

[Service]
Type=notify
ExecStart=.../watchoutput --retry-on-exit 2 --wait-before-retry 30 --ignore-stderr \
    -- ping -i 30 192.168.1.1
Restart=on-failure
WatchdogSec=70
StandardOutput=null
StandardError=journal
LimitCORE=0
SyslogIdentifier=watch-network

[Install]
WantedBy=default.target

拿 watchoutput 监控 ping 网关的输出,每30秒 ping 一次,如果70秒还没反应就重启它自己。然后我们还需要重新连接网络。在 /etc/systemd/system 下建立 netctl-auto@wlan0.service.d 目录,并在其下建立一个 watchdog.conf 文件,给 netctl-auto@wlan0.service 服务增加一项配置:

[Unit]
PartOf=watch-network.service

这样当 watch-network.service 重启的时候,netctl-auto@wlan0.service 就会自动重启了~

Category: Linux | Tags: linux systemd

部分静态文件存储由又拍云存储提供。 | Theme: Aeros 2.0 by TheBuckmaker.com