触摸板异常及用downgrade降级Udev

前几日私在推上发牢骚,曰“进来命途不顺,Arch升级愈升问题愈多”,计算机科学屠戮者大神反问:“此岂非生活之常态?”。其实真的不是生活的常态。也许是私当年用惯了kubuntu(呃……一不留神又黑了kubuntu啊,话说私过几天还要参加release party呢),觉得Arch简直是一个稳定得令人惊讶的系统。唯一的一次问题是源于私穷折腾时的操作失误。在此之前还真的没有找出任何的问题。

然而一次升级过后悲剧发生了。重启候发现触摸板无法使用,遂接上外接鼠标查找原因,计算机科学屠戮者大神说可能是内核的问题,然而私在本地未找到早先留下的包,作罢。后来开机时发现触摸板反映很怪,有时认不出,有时能认出,还有时会认成鼠标,查Xorg的Log,发现自己的EasyCamera(摄像头)被认成了触摸板,然后自然发生错误,于是触摸板的驱动就自动Unload了,没有挂载在正确的地方。去Arch的论坛找,发现貌似是新版本Udev(167-1)的问题,降级回去就可以了。

不过私依然没找到遗留的老版本的Udev包,难道真的要编译才能解决吗?后来看到Bug Report下有人提到可以用AUR里面的叫做“downgrade”的包(名字真直接)。下载后只需用downgrade xxx命令,就可以找到xxx软件的一些早先版本(Udev貌似保留了十多个早先版本),选择一个降级即可,操作非常傻瓜,避免了因误操作可能出现的各种问题,很适合私这样的初学者使用。

后记:

私降级后就把Udev放到升级忽略列表中了。然而今天升级之后发现有个叫做“initscripts”的包要求Udev版本高于167。Google之,发现和启动初始化有关(貌似是废话,嗯……因为细节私也没太看懂)。难道就是因为Udev和这个包的版本不匹配才出现的问题吗?一会可以试试看。

后记的后记:

果然跟此事有关。今日在Arch官网上找到了这句话:

We would like to remind everyone that initscripts expect all other packages (except for the kernel) to be up-to-date. This in particular includes udev, mdadm, dmraid and lvm.

于是升级一下就一切都好了。

出现在楼里的兔子

不知怎地,宿舍楼里不久前出现了只瘦弱的兔子。私宿舍恰好种了薄荷,拿给它,它不由分说便啃,看上去似乎有好几天没吃东西了。由于我们的楼是个“I”字型,我们正好处于这“I”的一个角落,所以看到兔子的人并不多,也就没演变成大家七手八脚去“把玩”的境况。至今我们未曾弄清兔子的来历,据我们猜测大概是做实验的人从实验室带出来放到这里的。

兔子很老实,虽然常会在地上跳来跳去,但并不跑远。见到人不会害怕地躲闪,所以很容易照料。和私住一个角的都是熟识的同学,甚至还有高中的同学,大多也还算友善。高中同学把自己的箱子(运动会奖品)贡献了出来,作为兔子晚上的居所,免得晚上黑灯瞎火踩死了它。由于老实,平时它大多待在外面,从这个宿舍小步蹦到另一个宿舍,到处寻找吃的。大概是某舍友给它喂了些瓜子等好东西,让它的口味提高了吧。总之私是反对喂这些的。兔子的肠道很长,过多的油脂可能会在其中异常发酵。即使不异常发酵,消化过多的油脂也是不利的。于是私会去外面拔些草来,它吃便吃,不吃便罢。

其实私一直以为自己是个有点冷血的人,更何况做实验时会虐杀无数实验动物,因此连私都不知自己为何会如此善良地对待一只兔子。大概人总是有点矛盾的吧……

按说宿舍楼里是不允许养宠物的,然而我们都不想(至少现在还不想)把它送走。然而私作为一个相当喜新厌旧的人,或许以后会厌烦它,然后逐渐疏于照料吧……

Arch恢复

首先感谢计算机科学屠戮者大神,在私的PC上大大地展现了一番bash功力。当然他自己未必觉得如此,但私看得却是眼花缭乱得很……

其实不能挂载的症结就是私grub配置不知怎地(反正绝不是私搞的),挂载root分区那行里的“ro”莫名其妙地变成了“rw”,以至于root被挂载为读写模式,而Arch自检的时候要求挂载为只读模式,于是就出现问题了。

而这个问题说到根上,都是源于私换驱动的时候用了“pacman -Rns catalyst”的命令,以至于pacman把其依赖——xserver卸掉了,于是乎装了啥驱动也不管用了。

另外其实原先私fstab还有个问题,就是swap挂载写了两遍,所以每次启动会提示swap挂载有误,这次也一并解决了。另外还对系统进行不少小调整,在此不一一赘述。

总之很感谢计算机科学屠戮者大神,不过私想到以后如果再有这样的问题,凭自己这样的能力,大概是解决不了的吧。还是得再研究再学习啊。

Arch挂了……

仔细看了看私以前的日志,发现自己是在1月22日装好的Arch linux。今日——4月16日彻底挂掉。三个月才挂掉,在私用Linux的历史上也还算比较长了,想到这里实在让人哭笑不得。也许只是因为Arch难掌握,所以在胡搞的时候稍稍用了点心吧……

故事是这样的。某日升级的时候发现Catalyst 11.3不支持xorg 1.10以后版本,但Arch的软件源里已经有1.10了,导致无法更新。于是私就打算换开源驱动试试。其实私在开源驱动和Catalyst之间换已经许多次了,都没有出现什么问题。结果这次不知怎么就无法启动X了。私以为是驱动只兼容xorg 1.10,于是就做了一次系统更新,仍旧是没有用。

然后……私做了个极其错误的决定——开testing源。重启之后,mount出错,说继续的话会造成严重数据损失,其中的“will”和“severe”还有专门的着重号。私害怕甚,没有继续,于是只读挂载,要私手动修复问题。对私这Linux万年新手来说当然是搞不定的,于是现在就挂在那里。

其实私只要耐心等待一下,等Catalyst支持新xorg,问题可能就会很容易解决……还是太不谨慎啊……

笔电又开始宕机……

私曾记载过自己IdeaPad Y460在CPU、显卡均高负载下如果突然撤去CPU负载发生宕机问题,后来换主板得以解决。而现在似乎又开始了。私尚未进一步测试,不过十之八九是用样的问题。屏线貌似最近也开始接触不良。这实在不是买了一年的机器该有的样子。

现在越发地后悔当初没有选择ThinkPad SL410。虽说Y460性能要强很多,但绝大多数情况根本用不到。没有Trackpoint,多一堆花哨功能,和Linux兼容性不良……

歪脖桃树

私在p大最常去的食堂门前有两棵山桃,上面挂了牌子,写着“物候监测对照”。起初私没有太在意那到底是什么树,只记得夏天入学之后长满了叶子,后来叶子掉光了,也就没再关注它。前一阵子早上去吃饭时远远地看到树上有淡粉色,走近一看,发现已经冒出了骨朵。最近几天颜色愈发鲜艳了,只是花还没开。

于是乎想起中学时校门口的那颗歪脖桃树。也是先开花后长叶,但似乎花开得更早一些,早到似乎从气温上根本感觉不到变化,而往往是从那树上首先感知到春天的到来。等春天真的“到来”时——当然,帝都的“春天”其实很难称之为春天,应该说冬天真的过去更合适——那桃树已经开始落英缤纷了,此后便长出在私印象中略有卷曲的叶子。

虽然这棵歪脖桃树花期其实很短,叶子也不甚喜人,私却以为这是整个学校最好的一棵树。在早上顶着睡眠不足的不适感奔跑在进教室的路上时,大抵想到的都是生活的苦闷。此时突然有一棵桃树映入眼帘,对私来说就像突然走进了桃花源一样欣喜。于是乎进教室前好歹对这新的一天抱了希望。

后来私初中即将毕业,就想将其照下来以兹留念,然而终究因为种种原因错过了花期没有照成。幸运(或是不幸)的是高中时在原来学校的分校上学,还要经常过去上课,于是又有了三年和其相会的机会,也终于在最后的时候用古老的卡片机(其实一点都不卡片)照了照片。回去用显示器一看,曝光时间太长,效果并不很好。后来这照片似乎也遗失在了硬盘中或是存储卡中,总之现在已经找不到了。后来私似乎也把它忘掉了,前几日看到食堂门前的桃树,才想起了这段事情。

写到此处私也不知该如何将这文章继续下去,像那些私很“鄙视”的文学家一样写一个可以作为中考高考题目的结尾。其实奠定语文高考这种模式的人才是真正可耻的人,文学家只是“想把自己的文章用这样的方法结尾”,这又有什么错呢?当初私想到写这篇文章,不过就是在看到食堂门前那两颗桃树时突然有了“我想把这件事记录下来”的冲动,仅此而已。

仅此而已。

 

3月25日追记:

其实帝都这地方还是比较盛产桃花的。往郊区走的话会看到街边有很多观赏的桃花。不过多是些枝杈被修剪得很整齐,并排垒着大朵大朵好似假花的品种。像食堂门前的那两棵还算自然的桃树私并没有见过几个——它们旁边的那几棵现在还光秃秃的树貌似也因为可能伤害学生都被或多或少地截肢了,它们还好,藏在深处,暂时似乎没有遭殃——,而像中学门口那棵那样恣意伸展,只自顾自冒出点点繁星,清新脱俗的仙品,私来到地球许多年,也只见到过那独一份。

信手闲话:懒/大笑江湖主题曲

前言:

这段文字其实已经拖了很长的时间了。开始写第一笔可能已经是上周这个时候的事情了。后来因为事比较多,一直没有继续。直到某旧友向我私起我已经很久没更新网志了,才想起这段本来不长的内容还没有完。现在看来,还真是够懒的。

然而网志究竟是应该用来干什么的呢?如果只描述一些最近的事却无更深刻内容的话,发布出来是不是只是迷惑他人的实现而已呢?写一些别人可能根本不感兴趣的内容,除了能获得“让他人了解”这样的满足感以外,旁的大抵都是一种浪费。

//

私记得似乎自己已经写过关于“懒”这一主题的网志了……不过若干年过去还是没能摆脱这一毛病啊。
虽然如今空闲无多,但仔细想想似乎也并不是紧张到了一点副业都不能做的程度。然而细细想来,这些难得的宝贵时间并未被私用于“号称”喜爱的地方,例如C,例如Qt,甚至是游戏。反而是浏览网页、上推的时间相较而言多得多,大概是因为不用动太多脑子的缘故吧。

于是乎,C还没学到家;Qt只会画界面(Hello World);当年理发店管理程序新功能加到一半,后来也一直没动,程序都快看不懂了;《侍魂-天下一剑客传》可以完美模拟了,却甚至未曾尝试一下。

归根结底还是个懒字啊……

//

近期听了大笑江湖的主题曲。电影私没有看过,实在无法提出更多评论。只是很欣赏歌曲里面没什么文学水平的歌词。以草根不争名逐利,对一切释然的心态来讲述江湖。也许没有一个人眼中的“江湖”能涵盖江湖的方方面面,但有如此的心态实在是一件令人艳羡的事啊。

//

后记:
现在在听维瓦尔第的《四季》更准确地说是《四季》中的《春》,神作也……

DFS解迷宫的一些想法

写在前面:私不是程序员,也不是学信科的,也只是最近开始没事的时候翻翻C语言的书。因此阁下很可能会觉得下文所述的想法很原始或是阁下早已用过了。私在此只是记录一下自己的想法。

现阶段私学C语言用的书是宋劲杉的《Linux C编程一站式学习》,里面讲深度优先搜索的时候讲的是个走迷宫问题,用1表示墙,0表示路,从左上走到右下。代码如下:

#include <stdio.h>
#define MAX_ROW 5
#define MAX_COL 5

struct point { int row, col; } stack[512];
int top = 0;

void push(struct point p)
{
    stack[top++] = p;
}

struct point pop(void)
{
    return stack[--top];
}

int is_empty(void)
{
    return top == 0;
}

int maze[MAX_ROW][MAX_COL] = {
    0, 1, 0, 0, 0,
    0, 1, 0, 1, 0,
    0, 0, 0, 0, 0,
    0, 1, 1, 1, 0,
    0, 0, 0, 1, 0,
};

void print_maze(void)
{
    int i, j;
    for (i = 0; i < MAX_ROW; i++) {
        for (j = 0; j < MAX_COL; j++)
            printf("%d ", maze[i][j]);
        putchar('n');
    }
    printf("*********n");
}

struct point predecessor[MAX_ROW][MAX_COL] = {
    {{-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}},
    {{-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}},
    {{-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}},
    {{-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}},
    {{-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}, {-1,-1}},
};

void visit(int row, int col, struct point pre)
{
    struct point visit_point = { row, col };
    maze[row][col] = 2;
    predecessor[row][col] = pre;
    push(visit_point);
}

int main(void)
{
    struct point p = { 0, 0 };

    maze[p.row][p.col] = 2;
    push(p);

    while (!is_empty()) {
        p = pop();
        if (p.row == MAX_ROW - 1  /* goal */
            && p.col == MAX_COL - 1)
            break;
        if (p.col+1 < MAX_COL     /* right */
            && maze[p.row][p.col+1] == 0)
            visit(p.row, p.col+1, p);
        if (p.row+1 < MAX_ROW     /* down */
            && maze[p.row+1][p.col] == 0)
            visit(p.row+1, p.col, p);
        if (p.col-1 >= 0          /* left */
            && maze[p.row][p.col-1] == 0)
            visit(p.row, p.col-1, p);
        if (p.row-1 >= 0          /* up */
            && maze[p.row-1][p.col] == 0)
            visit(p.row-1, p.col, p);
        print_maze();
    }
    if (p.row == MAX_ROW - 1 && p.col == MAX_COL - 1) {
        printf("(%d, %d)n", p.row, p.col);
        while (predecessor[p.row][p.col].row != -1) {
            p = predecessor[p.row][p.col];
            printf("(%d, %d)n", p.row, p.col);
        }
    } else
        printf("No path!n");

    return 0;
}

大概意思就是每次弹出一个栈,找到周围所有的合法步骤然后把它们栈压进栈区,下一轮时再弹出最后压入的栈,如果走入死路就再次弹栈,找另外一条可能路线,直到找到迷宫的解。如果栈空了就说明无路可走,打出“No path !”。
但是找到解之后就比较麻烦。如何输出路径呢?这段代码使用的方法是建立一个predecessor数组,用来表示每个点的前趋,然后从最后一个点顺藤摸瓜往前找,逐渐打印出来。但这个predecessor数组占用的空间很大,且只能从后向前找,不便于找到其中的某个特定步骤。怎么解决这一问题呢?作者宋劲杉出了一道思考题,还问读者能够想出几种方法,可见方法是不止一种的。

在正确理解这段代码之前,私一直认为栈区中至少应该存有正确路径走过的所有的点,后来才明白这个想法是有问题的。由于每个循环开始时栈顶已经弹出了,此时如果再在这一点继续向深处找,新压入的栈就会把刚才弹出的栈顶覆盖掉,这样找到最后整个栈中在极端情况下(例如整个迷宫都没有岔路)可能一个点也不剩。此外一个循环内是4个方向均会搜索,所以如果有岔路,就会压入多个点,但弹出时只会弹出一个点,所以栈中会残留错误道路的点。

怎么修改呢?其实很容易。原来每个循环会从栈顶弹出一个栈,其实找到路径之后,完全可以把这一栈再压回去,比如这样:

int main(void)
{
    struct point p = { 0, 0 };

    maze[p.row][p.col] = 2;
    push(p);

    while (!is_empty()) {
        p = pop();
        if (p.row == MAX_ROW - 1  /* goal */
            && p.col == MAX_COL - 1)
            break;
        if (p.col+1 < MAX_COL     /* right */
            && maze[p.row][p.col+1] == 0) {
            top++;
            visit(p.row, p.col+1, p);
        } else if (p.row+1 < MAX_ROW     /* down */
            && maze[p.row+1][p.col] == 0) {
            top++;
            visit(p.row+1, p.col, p);
        } else if (p.col-1 >= 0          /* left */
            && maze[p.row][p.col-1] == 0) {
            top++;
            visit(p.row, p.col-1, p);
        } else if (p.row-1 >= 0          /* up */
            && maze[p.row-1][p.col] == 0) {
            top++;
            visit(p.row-1, p.col, p);
        }
        print_maze();
    }

    int i;
    if (!is_empty()) {
        for (i=0; i<top; i++)
            printf("(%d, %d)n", stack[i]);
    } else
        printf("No path.n");

    return 0;
}

如果找到了可用的路,由于有了top++,相当于仅仅是读取到栈顶的数据(而栈没有弹出),这样在搜索路径压栈的时候就不会把原来的栈顶覆盖掉,从而保证了栈中存在所有正确路径上的点。解决残留错误道路的点的问题也很容易,只需让一个循环内如果搜索到了一条可以深入的路径就停止(用else实现),否则再搜索下一条路径。如果找到死路栈会逐个弹出,直到岔路口,所以不用担心找不到正解。到最后如果迷宫存在解的话,栈中所保存的就是正确的路径。由于例子中的“栈”是一个数组(当然您可能会反驳说这个例子中stack[]并不是真正意义上的栈,“栈”在理论上应该只能访问顶端的元素,但那只是个形式问题),于是可以很容易地访问任何一步的点,输出的时候正着打反着打跳着打均可,程序中所有和predecessor有关的内容便可以删去了。

但是事实上这个办法在程序效率上是劣化而不是优化,首先虽然不需要predecessor了,但是栈空间消耗变得更大。原本栈空间的消耗和分岔路的多少有关,现在则是和路径的长度有关而与有多少岔路无关。那么栈空间的最小值应该是多大呢?私还没考虑好,但分配为整个迷宫的大小肯定是足够的。还有个问题是原来的方式由于覆盖了之前走过的路径,只保留岔路上其他方向的点,如果找到死路,弹栈后会直接跳到另外一个可能的岔路继续搜索,而修改后的方法如果找到死路,必须沿原路一步步跳回岔路口。再加上top++所用的时间,程序效率比原来要低,而且岔路越多越深入,效率上的差距越明显。

前几天看到个好玩的推,说“情人节我玩一天连连看,消灭一对是一对”。私寻思既然学了DFS和BFS,不如自己也写个文本连连看玩玩?再说吧。

另:为嘛我Tag里写C,wordpress会给自动补全成C++?