Gentoo Linux, Dropbox missing system tray icon

Nowadays, when I start Dropbox from command line, I found that the Dropbox system tray icon is missing.

I tried ps, and found that Dropbox is running in background:

		% ps -efww | grep -v grep | grep dropbox    
		nostalg+ 17209     1  0 Apr11 pts/6    00:02:45 /home/nostalgia/.dropbox-dist/dropbox-lnx.x86_64-3.18.1/dropbox /newerversion start

dropbox-cli indicates that Dropbox is working properly:

		% dropbox-cli status
		Syncing (3 files remaining, 41 mins left)
		Uploading "MindCache.html"...
		Downloading 2 files (25.8 KB/sec, 41 mins left)


I googled, eventually and luckily, found the solution:

		% dbus-launch /opt/dropbox/dropbox start

It seems that it’s a bug of Dropbox. :-(


Now, Dropbox works like a charm again.


References:


Gentoo Linux, libGL error

Recently, when I start Dropbox from terminal, I always get the libGL error:

/opt/dropbox/dropbox start
libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast

I googled, and luckily found this. I followed the instructions, and get the following output:

% glxinfo  
name of display: :0
libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast
X Error of failed request:  GLXBadContext
  Major opcode of failed request:  153 (GLX)
  Minor opcode of failed request:  6 (X_GLXIsDirect)
  Serial number of failed request:  46
  Current serial number in output stream:  45

% glxgears
libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast
X Error of failed request:  BadValue (integer parameter out of range for operation)
  Major opcode of failed request:  153 (GLX)
  Minor opcode of failed request:  3 (X_GLXCreateContext)
  Value in failed request:  0x0
  Serial number of failed request:  35
  Current serial number in output stream:  37

% export LIBGL_DEBUG=verbose 
% glxinfo
name of display: :0
libGL: screen 0 does not appear to be DRI2 capable
libGL: OpenDriver: trying /usr/lib64/dri/tls/swrast_dri.so
libGL: OpenDriver: trying /usr/lib64/dri/swrast_dri.so
libGL: Can't open configuration file /home/nostalgia/.drirc: No such file or directory.
libGL: Can't open configuration file /home/nostalgia/.drirc: No such file or directory.
libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast
X Error of failed request:  GLXBadContext
  Major opcode of failed request:  153 (GLX)
  Minor opcode of failed request:  6 (X_GLXIsDirect)
  Serial number of failed request:  46
  Current serial number in output stream:  45

There are two OpenGL implementations on my Gentoo Linux:

% eselect opengl list
Available OpenGL implementations:
  [1]   nvidia *
  [2]   xorg-x11

As you see, currently, I’m using the nvidia implementation.


And there are quite a lot libGL.so files on my box:

% locate libGL.so
/home/nostalgia/.dropbox-dist/dropbox-lnx.x86_64-3.18.1/libGL.so.1
/usr/fakelib/amd64/libGL.so
/usr/fakelib/x86/libGL.so
/usr/lib32/libGL.so
/usr/lib32/libGL.so.1
/usr/lib32/libGL.so.1.2.0
/usr/lib32/opengl/nvidia/lib/libGL.so
/usr/lib32/opengl/nvidia/lib/libGL.so.1
/usr/lib32/opengl/nvidia/lib/libGL.so.1.0.0
/usr/lib64/libGL.so
/usr/lib64/libGL.so.1
/usr/lib64/libGL.so.1.2.0
/usr/lib64/opengl/nvidia/lib/libGL.so
/usr/lib64/opengl/nvidia/lib/libGL.so.1
/usr/lib64/opengl/nvidia/lib/libGL.so.1.0.0

% sudo find /usr -iname "*libGL.so*" -exec ls -l {} \; 
Password: 
lrwxrwxrwx 1 root root 24 Jul 15  2015 /usr/fakelib/x86/libGL.so -> /usr/lib32/librrfaker.so
lrwxrwxrwx 1 root root 24 Jul 15  2015 /usr/fakelib/amd64/libGL.so -> /usr/lib64/librrfaker.so
lrwxrwxrwx 1 root root 14 Mar 14 01:22 /usr/lib32/libGL.so -> libGL.so.1.2.0
lrwxrwxrwx 1 root root 14 Mar 14 01:22 /usr/lib32/libGL.so.1 -> libGL.so.1.2.0
lrwxrwxrwx 1 root root 14 Apr  7 10:14 /usr/lib32/opengl/nvidia/lib/libGL.so -> libGL.so.1.0.0
lrwxrwxrwx 1 root root 14 Apr  7 10:14 /usr/lib32/opengl/nvidia/lib/libGL.so.1 -> libGL.so.1.0.0
-rwxr-xr-x 1 root root 439972 Apr  7 10:14 /usr/lib32/opengl/nvidia/lib/libGL.so.1.0.0
-rwxr-xr-x 1 root root 697944 Mar 14 01:22 /usr/lib32/libGL.so.1.2.0
lrwxrwxrwx 1 root root 14 Mar 14 01:22 /usr/lib64/libGL.so -> libGL.so.1.2.0
lrwxrwxrwx 1 root root 14 Mar 14 01:22 /usr/lib64/libGL.so.1 -> libGL.so.1.2.0
lrwxrwxrwx 1 root root 14 Apr  7 10:14 /usr/lib64/opengl/nvidia/lib/libGL.so -> libGL.so.1.0.0
lrwxrwxrwx 1 root root 14 Apr  7 10:14 /usr/lib64/opengl/nvidia/lib/libGL.so.1 -> libGL.so.1.0.0
-rwxr-xr-x 1 root root 579760 Apr  7 10:14 /usr/lib64/opengl/nvidia/lib/libGL.so.1.0.0
-rwxr-xr-x 1 root root 774688 Mar 14 01:22 /usr/lib64/libGL.so.1.2.0

So I doubt that if the glxgears/glxinfo command is using the inappropriate libGL.so file.
How to detect which libGL.so file I’m using? Of course, with strace:

		% strace -o /tmp/libGL.strace glxgears

I checked the /tmp/libGL.strace file, and found that the called libGL.so file is /usr/lib64/libGL.so.1, which is a symbolic link to /usr/lib64/libGL.so.1.2.0, the default xorg-x11 OpenGL implementation.

Now, it’s quite clear: I only need to point /usr/lib64/libGL.so.1 to the nvidia OpenGL .so implementation, which is /usr/lib64/opengl/nvidia/lib/libGL.so.1.0.0:

		% sudo ln -fs /usr/lib64/opengl/nvidia/lib/libGL.so.1.0.0 /usr/lib64/libGL.so.1

And test again:

% glxinfo | grep direct
direct rendering: Yes


Now, everything works like a charm!


References:


如何查看自己用的是哪家网络运营商?

目前,中国大陆的网络运营商主要就三家:中国移动、中国联通、中国电信。

如何查看自己当前使用的网络是哪家运营商提供的接入服务呢?你可能在家、公司、咖啡厅……

一般而言,可以直接上 ip138 或者 123cha 这类 IP 地址查询网站,在这类网站上,可以直接看到自己所在网络的出口 IP(即公网 IP),并且看到 IP 归属地。很多时侯,直接从 IP 归属地可以直接看出是哪家网络运营商,比如 xx 电信、yy 联通等。



但是,在某些情况下,就没那么方便了。比如在 ip138 上可以查到我当前的外网 IP 地址是 118.198.58.153,而外网 IP 地址是:

本站主数据:北京市北京市鹏博士宽带
参考数据一:中国

而「鹏博士宽带」到底是电信、联通,还是移动呢?Google 了下,找到了这个链接,对于「鹏博士」,它是这样介绍的:

问:成都鹏博士是属于网通还是属于电信?他们之间有什么关系?
答:成都鹏博士集团是一家在 A 股上市的独立公司, 跟网通和电信没有任何的隶属关系。需要注意,鹏博士是一家集团,集团下面有很多的子公司,其中包括北京电信通,长城宽带,宽带通。
上面提到的这三家鹏博士子公司也是提供电信业务的公司,所以跟电信和网通之间存在有竞争关系,也存在合作关系。
鹏博士属于二级运营商,网通和电信属于一级运营商,所以鹏博士的带宽是电信和联通双线的。

也就是说,「鹏博士」这个二级运营商,代理的可能是电信的网络,也可能是联通的网络。但是还是没能回答那个问题:我现在接入的网络到底是哪家(一级)网络运营商提供的呢!?


其实,这个问题不难回答。因为只要我们跟踪网络包的路由路径,就一定可以查到究竟是哪家一级网络运营商提供的接入服务。在 Linux 下,用 traceroutemtr 命令都可以看到包的路由路径。我们以 mtr 命令为例:

% mtr -rw MindCache.info
Start: Mon Apr  4 15:42:36 2016
HOST: Gentooo                                  Loss%   Snt   Last   Avg  Best  Wrst StDev
  1.|-- 192.168.0.1                               0.0%    10    0.5   0.5   0.5   0.5   0.0
  2.|-- 118.198.32.1                              0.0%    10    2.1   2.1   1.4   3.1   0.3
  3.|-- 124.205.97.54                             0.0%    10    3.1   6.1   1.4  40.5  12.1
  4.|-- 218.241.166.73                            0.0%    10    8.8   3.4   1.5   8.8   2.1
  5.|-- 218.241.166.85                            0.0%    10    2.4   3.0   1.9   4.6   0.7
  6.|-- 202.99.1.138                              0.0%    10    5.9   5.6   2.7  10.0   2.0
  7.|-- ???                                      100.0    10    0.0   0.0   0.0   0.0   0.0
  8.|-- ???                                      100.0    10    0.0   0.0   0.0   0.0   0.0
  9.|-- ???                                      100.0    10    0.0   0.0   0.0   0.0   0.0
 10.|-- 120.80.2.153                             70.0%    10   49.4  49.2  49.0  49.4   0.0
 11.|-- 120.81.0.37                               0.0%    10   44.5  47.1  44.5  48.7   1.1
 12.|-- 219.158.7.201                             0.0%    10   56.0  56.6  55.4  59.7   1.1
 13.|-- 219.158.23.118                            0.0%    10  130.9 130.6 125.9 147.9   6.2
 14.|-- 219.158.96.14                             0.0%    10  152.2 135.5 125.1 152.2  11.0
 15.|-- 219.158.102.130                           0.0%    10  337.7 338.0 313.3 354.3  12.0
 16.|-- TenGigE0-2-0-0.GW6.SJC7.ALTER.NET         0.0%    10  349.3 364.3 348.5 404.1  17.3
 17.|-- 0.ae2.BR3.SJC7.ALTER.NET                  0.0%    10  352.0 363.3 346.7 377.4  11.5
 18.|-- 204.255.168.82                            0.0%     9  204.6 212.9 203.5 228.8  10.6
 19.|-- TenGE0-0-0-1.br03.sin02.pccwbtn.net       0.0%     9  240.4 258.4 232.5 304.7  25.3
 20.|-- linode.te0-1-0-21.br03.sin02.pccwbtn.net 11.1%     9  283.8 270.0 254.8 283.8  10.9
 21.|-- 139.162.0.10                              0.0%     9  250.4 261.0 249.5 278.1  11.5
 22.|-- li1454-12.members.linode.com             12.5%     8  252.1 266.4 252.1 280.7  10.9

ip138 上,可以查到更「主干」的出口 IP 219.158.102.130 是联通的:

本站主数据:北京市北京市联通
参考数据一:北京市联通

就这样,可以确定我当前用是联通的网络。


参考:


Beautiful Soup, use find()/find_all() attrs parameter to select HTML tag

Note: This article applies to Python 3 environment.


Background

Recently, I’m working on a web-scrapying project using Python 3, and use Beautiful Soup to parse the HTML tree. I encountered several problems when selecting HTML tag, but luckily, I found that most of them can be solved via the find()/find_all() attrs parameter.


Problem & Workaround

  • find()/find_all() **kwargs parameter can’t find tags with some HTML 5 attributes(eg. the data-* attributes)
  • example:

    >>> html_content = """内地剧"""
    >>> html_soup = BeautifulSoup(html_content)
    >>> html_soup.find(data-pb-other="area")
      File "<stdin>", line 1
    SyntaxError: keyword can't be an expression
    

    workaround:

    >>> html_soup.find(attrs={"data-pb-other":"area"})
    内地剧
    


  • CSS selector can’t find tags with some HTML 5 attributes(eg. the data-* attributes)
  • example:

    >>> html_content = """内地剧"""
    >>> html_soup = BeautifulSoup(html_content)
    >>> html_soup.select('a[data-pb-other="area"]')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/usr/lib64/python3.4/site-packages/bs4/element.py", line 1313, in select
        'Unsupported or invalid CSS selector: "%s"' % token)
    ValueError: Unsupported or invalid CSS selector: "a[data-pb-other="area"]"
    

    workaround:

    >>> html_soup.find("a", attrs={"data-pb-other": "area"})
    内地剧
    


  • CSS selector can’t find tags with multiple attributes
  • example:

    >>> html_content = """大道通天第1集"""
    >>> html_soup = BeautifulSoup(html_content)
    >>> html_soup.select('a[class="movie_name" id="movie_name"]')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/usr/lib64/python3.4/site-packages/bs4/element.py", line 1313, in select
        'Unsupported or invalid CSS selector: "%s"' % token)
    ValueError: Unsupported or invalid CSS selector: "a[class="movie_name""
    

    workaround:

    >>> html_soup.find("a", attrs={"class":"movie_name", "id":"movie_name"})
    大道通天第1集
    


References:


fork + exec, child process doesn’t return

Note: This article applies to Python 2 environment.


Background

In Unix/Linux programming, we use fork + exec mechanism to create child process, replace child process with the program we want to run. Then we call wait() or waitpid() to wait for child process to return.

But in some scenarios, the child process just blocks and hangs there due to some unexpected reasons(eg. the rsync program is likely to block because of network issues), therefore the child process won’t return at all, levaing the parent process(probably the main process) hangs too.


Problem

It’s natural to think of using parent process to manage child process, control its life cycle. In more detail, we can set a maxmium time for the child process to return. If the child process doesn’t return in the specified time, the parent process can just kill it.

We can verify our idea using Python:

#!/usr/bin/env python2.7
# coding=utf-8
# vim: ts=4 sw=4

import os
import errno
import time
import signal


def kill_operation(pid, signal):
    try:
        os.kill(pid, signal)
    except OSError as err:
        if err.errno == errno.EPERM or err.errno == errno.ESRCH:
            return False
    return True


pid = os.fork()
if pid == 0:
    print "in child process ..."
    time.sleep(5*60)
    os._exit(0)
else:
    print "parent process %d, sub process id %d" % (os.getpid(), pid)


max_sleep_time = 20
current_sleep_time = 0
sleep_interval = 5
existence = True
while existence:
    if (current_sleep_time < max_sleep_time):
        try:
            os.waitpid(pid, os.WNOHANG)
        except OSError as err:
            if err.errno == errno.ECHILD:
                break
        time.sleep(sleep_interval)
        current_sleep_time += sleep_interval
    else:
        print("kill 9\t\t" + str(kill_operation(pid, 15)))
    existence = kill_operation(pid, 0)
    print("kill 0\t\t" + str(existence))


exit(0)


However, the code above doesn't work as expected, the child process doesn't exit at all. Here are the output of the program and ps command:

The program output:

% ./fork_exec.bug.py
parent process 1680, sub process id 1681
in child process ...
kill 0          True
kill 0          True
kill 0          True
kill 0          True
kill 9          True
kill 0          True
kill 9          True

ps command output before the child process was killed:

% ps -efww | grep -v grep | grep python2.7
nostalg+  1680  2442  0 22:41 pts/55   00:00:00 python2.7 ./fork_exec.bug.py
nostalg+  1681  1680  0 22:41 pts/55   00:00:00 python2.7 ./fork_exec.bug.py

ps command output after the child process was killed:

% ps -efww | grep -v grep | grep python2.7
nostalg+  1680  2442  0 22:41 pts/55   00:00:00 python2.7 ./fork_exec.bug.py
nostalg+  1681  1680  0 22:41 pts/55   00:00:00 [python2.7] <defunct>


Workaround

We can find that the killed child process became zombie/defunct process.

About zombie process from Wikipedia:

On Unix and Unix-like computer operating systems, a zombie process or defunct process is a process that has completed execution (via the exit system call) but still has an entry in the process table: it is a process in the "Terminated state". This occurs for child processes, where the entry is still needed to allow the parent process to read its child's exit status: once the exit status is read via the wait system call, the zombie's entry is removed from the process table and it is said to be "reaped". A child process always first becomes a zombie before being removed from the resource table. In most cases, under normal system operation zombies are immediately waited on by their parent and then reaped by the system – processes that stay zombies for a long time are generally an error and cause a resource leak.

Here, the parent process kills the child process, but leave it unreaped. A child process can be reaped in one of the following two ways:

  • The parent process call wait()/waitpid() immediately after it kills the child process.
  • #!/usr/bin/env python2.7
    # coding=utf-8
    # vim: ts=4 sw=4
    
    import os
    import errno
    import time
    import signal
    
    
    def kill_operation(pid, signal):
        try:
            os.kill(pid, signal)
        except OSError as err:
            if err.errno == errno.EPERM or err.errno == errno.ESRCH:
                return False
        return True
    
    
    pid = os.fork()
    if pid == 0:
        print "in child process ..."
        time.sleep(5*60)
        os._exit(0)
    else:
        print "parent process %d, sub process id %d" % (os.getpid(), pid)
    
    
    max_sleep_time = 20
    current_sleep_time = 0
    sleep_interval = 5
    existence = True
    while existence:
        if (current_sleep_time < max_sleep_time):
            try:
                os.waitpid(pid, os.WNOHANG)
            except OSError as err:
                if err.errno == errno.ECHILD:
                    break
            time.sleep(sleep_interval)
            current_sleep_time += sleep_interval
        else:
            print("kill 9\t\t" + str(kill_operation(pid, 15)))
            os.waitpid(pid, 0)
        existence = kill_operation(pid, 0)
        print("kill 0\t\t" + str(existence))
    
    
    exit(0)
    
    
    
  • Handle the SIGCHLD signal.
  • #!/usr/bin/env python2.7
    # coding=utf-8
    # vim: ts=4 sw=4
    
    import os
    import errno
    import time
    import signal
    
    
    def kill_operation(pid, signal):
        try:
            os.kill(pid, signal)
        except OSError as err:
            if err.errno == errno.EPERM or err.errno == errno.ESRCH:
                return False
        return True
    
    
    # 父进程等待子进程的异步退出
    def on_child_exit(signum, frame):
        pid, status = os.wait()
        print("on_child_exit(): parent %d, child %d, exit status %d" % (os.getpid(), pid, status))
    
    
    pid = os.fork()
    if pid == 0:
        print "in child process ..."
        time.sleep(5*60)
        os._exit(0)
    else:
        print "parent process %d, sub process id %d" % (os.getpid(), pid)
    
    
    signal.signal(signal.SIGCHLD, on_child_exit)
    
    max_sleep_time = 20
    current_sleep_time = 0
    sleep_interval = 5
    existence = True
    while existence:
        if (current_sleep_time < max_sleep_time):
            try:
                os.waitpid(pid, os.WNOHANG)
            except OSError as err:
                if err.errno == errno.ECHILD:
                    break
            time.sleep(sleep_interval)
            current_sleep_time += sleep_interval
        else:
            print("kill 9\t\t" + str(kill_operation(pid, 15)))
        existence = kill_operation(pid, 0)
        print("kill 0\t\t" + str(existence))
    
    
    exit(0)
    
    
    


Now everything works as expected. :-)

PS: All above code can be downloaded from here.


References: