Prevent a package from being installed on Ubuntu / 在 Ubuntu 系统中阻止安装某个软件包

This article shows how to prevent a certain package from being installed, manually or as a dependency, on Linux systems using apt (apt-get) like Ubuntu and Debian.
这篇文章介绍如何在使用 apt (apt-get) 的系统上(例如 Ubuntu 和 Debian),防止某个软件包被安装,包括手动或被依赖。

It utilizes the “pinning” feature of apt, which you can read about in detail with man apt_preferences .
使用的原理是 apt 的 “pinning” 功能,可以通过 man apt_preferences 获取详细文档。

  1. Say we want to block “ttf-mscorefonts-installer” from being installed, which is a recommended dependency of “ubuntu-restricted-extras”. When we use apt-get install ubuntu-restricted-extras , the package will be automatically installed. If we use the “–no-install-recommends” switch, many other packages will be ignored, but we just want to block that one specific package.
    假设我们不想安装 “ttf-mscorefonts-installer” 软件包,但它是 “ubuntu-restricted-extras” 的推荐依赖。如果我们使用 apt-get install ubuntu-restricted-extras 命令,则依赖软件包也会自动安装。我们可以用 “–no-install-recommends” 开关阻止推荐依赖,但是同时会阻止其它很多软件包。接下来的方法适用于只阻止特定的一个软件包。
  2. In the folder “/etc/apt/preferences.d” we create a plain text file “block-package”, with the following contents:
    在 “/etc/apt/preferences.d” 文件夹中创建一个文本文件 “block-package”,内容如下:

    Package: ttf-mscorefonts-installer
    Pin: version *
    Pin-Priority: -10
    
  3. With a negative priority, the package will not be installed either manually or as a dependency when using apt-get.
    由于设置了负优先级,在使用 apt-get 时,这个软件包无论手动还是依赖都不会被安装。

Reference: http://askubuntu.com/questions/75895/how-to-forbid-a-specific-package-to-be-installed

Debugging random lagging on Android

My Samsung tablet with Android (4.4.2, rooted) has been experiencing random lagging for a while. This affects me most when I’m playing games on it. Earlier today I finally decided to find the root of the problem.

Finding the cause

The ultimate solution is to know which application is causing the lag and disable it. I first went to Settings > General > Developer Options (If you don’t have it, go to Settings > General > About phone/device and tap “Build number” 7+ times to enable it), and ticked “Show CPU usage”. Then you would see an overlay on the top-right corner of your device showing the top (like the Linux command) processes, similar to the image below.

Then I used my device to play games, and wait for the random lagging to happen. When the device start to response slowly, I watched the CPU usage overlay and see “gzip” topping the list. If you are not familiar with Linux, gzip is a compression tool similar to RAR or 7-Zip.

Wrapping (first attempt)

I was expecting some Android application to cause the lagging, instead it’s a command gzip that can be called by anyone. The problem became finding out who called it. Since my device is rooted, I decided to replace the original gzip binary with a wrapper that can log who called it before actually gzipping. Here is the wrapping bash script I used (first version, read on for second version):

#!/system/bin/sh

OPERATION=/system/bin/gzip.real
LOGFILE=/sdcard/gziplog.txt

OPTIONS="$@"

echo "`date` + $EUID `id` + $OPERATION "$@"" >> $LOGFILE

exec $OPERATION "$@"

The script does the following: (1) Log the time, user ID (the $EUID variable turns out to be useless, but `id` worked) and command line parameters to $LOGFILE (a plain text file in the internal storage); then (2) hand over the control to real gzip so that it doesn’t break the gzip functionality.

Then I used Root Explorer to rename /system/bin/gzip to /system/bin/gzip.real, and put my script to /system/bin/gzip (remember to modify the permission to be the same as gzip.real, usually 0755).

After using the device for a while and several lagging happened, I read the logging file and got these lines:

Fri Aug 28 13:53:22 CST 2015 +  uid=2000(shell) gid=2000(shell) groups=1007(log),1009(mount),1015(sdcard_rw),1028(sdcard_r),3003(inet),3006(net_bw_stats) context=u:r:dumpstate:s0 + /system/bin/gzip.real -6
Fri Aug 28 13:54:32 CST 2015 +  uid=2000(shell) gid=2000(shell) groups=1007(log),1009(mount),1015(sdcard_rw),1028(sdcard_r),3003(inet),3006(net_bw_stats) context=u:r:dumpstate:s0 + /system/bin/gzip.real -6
Fri Aug 28 13:55:43 CST 2015 +  uid=2000(shell) gid=2000(shell) groups=1007(log),1009(mount),1015(sdcard_rw),1028(sdcard_r),3003(inet),3006(net_bw_stats) context=u:r:dumpstate:s0 + /system/bin/gzip.real -6
Fri Aug 28 13:56:53 CST 2015 +  uid=2000(shell) gid=2000(shell) groups=1007(log),1009(mount),1015(sdcard_rw),1028(sdcard_r),3003(inet),3006(net_bw_stats) context=u:r:dumpstate:s0 + /system/bin/gzip.real -6

Observe that `id` produced “uid=2000(shell) gid=2000(shell) ...” and the command called is “gzip -6“. This means gzip was called by the shell user, not a specific application, and the data to be compressed was piped in to gzip and then piped out, since there are no input or output file names. (Spoiler: Actually this has shown “context=u:r:dumpstate:s0” which indicated that it was called by “dumpstate“, but I didn’t realize for the first time.)

Wrapping (second attempt)

Then I decided to take the surveillance up a level, and used the following wrapper in place of the first version:

#!/system/bin/sh

OPERATION=/system/bin/gzip.real
LOGFILE=/sdcard/gziplog.txt
TEE="/system/bin/busybox0 tee"
PSTREE="/system/bin/busybox0 pstree"

OPTIONS="$@"

echo "[$$] `date` + $EUID `id` + $OPERATION "$@"" >> $LOGFILE
$PSTREE -p >> $LOGFILE

#exec $OPERATION "$@"
$TEE -a $LOGFILE | $OPERATION "$@"

The difference between it and the previous one is that, it uses Busybox’s “pstree” command to output the process tree of that moment, and “tee” command to record the data piped in and pipe it out again. In order for this to work, I downloaded busybox-armv7l binary (my device has ARMv7 architecture) from the official website and put it to /system/bin/busybox0 with the same permission as gzip.real. You can also use Busybox installer apps and modify the busybox path accordingly.

After a while, I got the following log this time:

[8691] Fri Aug 28 14:30:46 CST 2015 +  uid=2000(shell) gid=2000(shell) groups=1007(log),1009(mount),1015(sdcard_rw),1028(sdcard_r),3003(inet),3006(net_bw_stats) context=u:r:dumpstate:s0 + /system/bin/gzip.real -6
init(1)-+-Binder_2(2299)---{Binder_1}(2360)
        |-DaemonServer(5419)---app_process(8668)
        |-DaemonServer(6687)
<...snip...>
        |-debuggerd(2276)---dumpstate(8690)-+-gzip(8691)---busybox0(8695)
        |                                   `-top(8696)
<...snip...>
========================================================
== dumpstate: 2015-08-28 14:30:46
========================================================

Build: KOT49H.P601ZCUCNH1
Build fingerprint: 'samsung/lt033gzc/lt033g:4.4.2/KOT49H/P601ZCUCNH1:user/release-keys'
Bootloader: P601ZCUCNH1
Radio: unknown
<...snip...>

Observe that [8691] is the gzip wrapper’s PID, and it’s called by “dumpstate“, which is then called by “debuggerd“. The wrapper also logged the data to be compressed, which is 5 MB long and takes 0.14s to be compressed on my PC instead of a poor mobile device.

Final solution

A quick Google told me this is for developers to debug the system state, and since I’m not a developer in this area, I decided to disable it once for all. This is done by using Root Explorer to revoke the execute permissions from the two binaries /system/bin/{debuggerd,dumpstate}.

Now the lagging is gone.

Use yumdb command with DNF to list explicitly installed packages

Since Fedora 22, DNF has replaced Yum as the default package manager. But not all yum commands have been migrated.

Today I felt like querying what packages I installed explicitly, and a quick Google told me to use yumdb search reason user, but it returned nothing.

I dug into the cause, and it turns out DNF now has its own yumdb (the database, not the command, sadly) at “/var/lib/dnf/yumdb”, along with yum’s “/var/lib/yum/yumdb”, and the command yumdb uses the latter by default.

In the man page of yum.conf, it says the “persistdir” value controls the path of yum’s db files, and it defaults to “/var/lib/yum”; but, yumdb --help tells me that it allows me to specify the location of config file. (Cheering for not touching /etc/yum.conf)

So, here’s what I did:

  1. Create a new fake config file with persistdir set to DNF’s folder.
    echo '[main]\npersistdir=/var/lib/dnf' > /tmp/dnf.conf
  2. Calls yumdb with that config file.
    yumdb -c /tmp/dnf.conf search reason user

Voila.

使用 systemd 的系统关机或重启时,自动执行特定命令

Arch Linux 这种比较潮的系统,已经迁移到了 systemd 这个管理器。这篇文章介绍如何在系统关机或重启时,自动执行特定命令。当然开机时自动启动服务也是一样的道理。

Manpage of Systemd

systemd 是一种系统和服务管理程序,与 Ubuntu 下的 upstart 类似,都是用来替代原始 BSD 或 System V 风格的 init 程序,实现在开机、不同的启动级别以及关机和重启时,执行相应的命令,启动或停止相应的服务。

1. 首先,我们要创建自己的 .service 服务文件。创建 /etc/systemd/system/xiaodu.service 内容如下:(点击下载

[Unit]
Description=Xiaodu: Remove bbswitch before shutdown/reboot
DefaultDependencies=no
Before=shutdown.target

[Service]
Type=oneshot
ExecStart=/sbin/modprobe -r bbswitch

其中,ExecStart= 后面替换为自己要执行的命令。我这里是为了在关机或重启前,卸载 bbswitch 模块,以便正常关机。

2. 按照需求将该服务文件链接到特定的位置。例如需要在关机之前执行,则:

# ln -s /etc/systemd/system/xiaodu.service /usr/lib/systemd/system/shutdown.target.wants/

这里的 shutdown.target 指的是关机前需要执行,同样也会在重启之前执行。如果只需在重启之前执行,则需要链接到 reboot.target.wants (可能需要创建该文件夹)。

由于在编写 .service 文件的时候,没有写 [Install] 段落,因此不能直接通过 # systemctl enable xiaodu.service 来启用,只能手动链接。更多信息可以参考 systemd.service 的手册页。

3. 要测试是否生效,可以尝试“启动”该服务 # systemctl start xiaodu.service ,也可以直接关机或重启来检查。

Compiling Custom Linux Kernel With PAE And PF-Patch On Arch Linux

The x86 Linux kernel in the official Arch Linux repository oddly doesn’t have PAE enabled by default. So I decided to compile my own with PAE as well as -pf patch set.

WARNING: Compiling and installing your own kernel can / will take VERY LOOOONG and be DANGEROUS. There are pre-compiled PAE kernels available as well as -pf ones, if that’s only what you want. If you are a regular user who don’t want to take that risk, or even don’t know what Linux kernel is, just follow these links and enjoy your life.

So you still decided to do it manually, huh? Very brave and good choice. So let’s begin.

First let me introduce the kernel we’re going to compile. PAE (Physical Address Extension) makes it possible to use as many as 64GB of physical RAM with 32-bit kernel. PF patch set includes “-ck” patch set, BFS scheduler, BFQ I/O sched, TuxOnIce feature and UKSM patch (the last one comes from China).

1) Get PKGBUILD for “linux-pf” package from AUR. Use yaourt or download here then $ makepkg.

We can also (optionally) edit the PKGBUILD before really start using it. You can change the URL to download Linux kernel, for example to a local mirror. That’ll save you some time. Change the first line of “source” as you want and save.

2) Start compiling and building package.

 — 2.a Choosing base config:

        First you will be asked whether to use “your running kernel’s config”, “make localmodconfig” or “build an all-inclusive kernel like stock -ARCH“.

The second choice should be used with caution, because it means that you only compile the drivers you loaded now, and if you add a new device later (even a USB mouse you don’t use now), it will NOT get recognized and run by your custom kernel.

Here I recommend the last choice, though it’ll take longer than the second, it’s the best choice for most people.

— 2.b Manually config:

  Since the default config for “linux-pf” still comes with PAE (CONFIG_HIGHMEM64G) disabled, we need to alter that choice. Here we can use “make menuconfig” (you can also use GUI-based ones), and change “Process type and features” — “High Memory Support” to the 64G choice. (You can also manually modify “.config” file and change “CONFIG_HIGHMEM64G” to “y”.)

 — 2.c Wait for compiling.

If it’s not too late to say it now (which it definitely is, ha~ha), you can change “/etc/makepkg.conf” (before you start the whole thing) and make the compiling multithreaded (useful for systems with Dual/Quad core CPUs). Read the docs for how.

3) Install the compiled kernel.

There should be two packages, for kernel and its headers. After installiation, (backup your grub.cfg and) # mkinitcpio -p linux-pf , # grub-mkconfig -o /boot/grub/grub.cfg , then restart the computer to use the new kernel.


This is the first time I post here in English. Hope it is English anyway.