跳到主内容

GFW

今天发现VPS(linode) 无法访问,ssh 和 http 同时罢工.

逐步检查问题:

  1. dns 没有问题

  2. ping 不通

  3. traceroute 失败

通过 Ajax Console 可以正常访问。 之前有利用 VPS 通过 ssh 翻墙,但发现 ssh server 使用的端口很快就不能使用; 又换了两个端口利用 ssh 翻墙, 新端口很快就又不能使用了; 早上发现 VPS 完全不能访问,无论是 ssh 还是 http.

网上搜索发现, 早就用同学遇到这种情况了; GFW 可以探测到 走 ssh 的 http, 先封端口,再封IP.

从不传谣, 不信谣的我,真的很愤怒!

伟大的GFW 开发者, 你们真牛!!

方校长, 一路走好!!!

ftok 陷阱

最近手上的项目出现了一个很严重的bug, 系统的message queue 资源被消耗完毕; 在创建 message queue 时提示已超出系统的资源限制(ENOSPC); 通过msgctl 查看系统上的 message queue 数目, 的确超出了系统的 限制(/proc/sys/kernel/msgmni).

System IPC (message queue, share memory 等等) 在创建时, 必须指定一个 KEY 值, 这个 KEY 来自于 ftok.

debug 发现, 调用ftok产生的 KEY, 每次都不一样.

查看fotk的 source code(glibc 2.20)

key_t ftok (const char *pathname, int proj_id) {
        struct stat64 st;
        key_t key;

        if (__xstat64 (_STAT_VER, pathname, &st) < 0)
                return (key_t) -1;

        key = ((st.st_ino & 0xffff) | ((st.st_dev & 0xff) << 16)
                | ((proj_id & 0xff) << 24));

        return key;
}

这样看, KEY 值与文件系统所在的 device id 和 文件节点号 有关, 如果 pathname 没有被删除, 则key值应该维持不变.

最终发现, pathname 在出错处理时被删除, 从而导致 KEY 值不固定.

实验发现, 如果 pathname 位于真实的文件系统, 比如EXT4, 删除后重新创建 pathname , st_inost_dev 不一定发生变化; 但如果 pathname 位于 ramfs 或者 tmpfs, 删除后重新创建, st_ino 一定会改变. 所以, pathname 所在的文件系统可能会影响 KEY 的产生. (笔者所在的项目中, pathname 位于 ramfs)

另外, 在 glibc 2.20 的 ftok 实现中, 只是使用了inode number 的低 16 位, 如果文件系统中包含大量的文件, 就会存在两个文件的 inode_number 低 16 位 相同; 此时, 这两个文件对应的 KEY 值 就会相同, 违背了 不同的文件产生不同的 KEY 的原则.

Linux programmer's Manual 是这样说的:

Of course no guarantee can be given that the resulting key_t is unique.
Typically, a best effort attempt combines the given proj_id byte,
the lower 16  bits  of the inode number, and the lower 8 bits of
the device number into a 32-bit result.  Collisions may easily happen,
for example between files on /dev/hda1 and files on /dev/sda1.

gcc 常用实例

前言

GCC (the GNU Compiler Collection) 是由GNU组织开发的编译器套件, 可以执行预处理,编译,汇编和链接动作. 这篇文章首先向大家介绍如何生成C语言的可执行文件, 共享库(动态库) 以及静态库, 然后介绍一下gcc常用的选项.

例子

  1. 以下的例子都在Ubuntu13.10 上使用gcc 4.8.1 测试通过. 假设有三个文件

    • main.c 定义main函数

    • a.c 定义add 函数

    • b.c 定义sub 函数

  2. 可执行文件

    gcc -o test main.c a.c b.c

  3. 共享库

    • 生成共享库

      gcc -shared -o libmymath.so a.c b.c

    • 使用共享库

      gcc -o test main.c -L. -lmymath

  4. 静态库

    • 生成静态库
      1. gcc -c a.c b.c

      2. ar crv libmymath.a a.o b.o

    • 使用静态库

      gcc -o test main.c -static -L. -lmymath

    • 注意: 当ld的搜索默认搜索路径即包含共享库又包含静态库时, 默认选择链接共享库;若需要链接静态库, 则需要加上-static选项

选项

  1. -I(大写的i) 添加路径到预处理器的搜索目录

    • 使用方法 -IPATH

      • gcc -I. -o test main.c a.c b.c

      • gcc -I/home/tony/work/myheaer -o test main.c

    • 注意: 在搜索头文件时, 通过-I添加的目录会优先与系统默认的搜索目录

  2. -D 预定义宏
    • 使用方法 -DNAME

      • gcc -DCONFIG_GATE -o test main.c

        等同于: #define CONFIG_GATE=1

      • gcc -DCONFIG_GATE_VALUE=128 -o test main.c

        等同于: #define CONFIG_GATE_VALU=128

  3. -c 执行编译和汇编, 但不执行链接动作, 生成中间文件

    • gcc -c main.c a.c b.c

    • 生成 main.o, a.o, b.o

    • gcc -c main.s a.s b.s

    • 生成 main.o, a.o, b.o

  4. -S 执行编译动作, 但不执行汇编, 生成汇编文件, 通常文件后缀为.s

    • gcc -S main.c a.c b.c

    • 生成 main.s, a.s, b.s

  5. -L 添加路径到链接器的搜索目录

    gcc -o test main.c -L.

  6. -l(小写的L) 在指定的library中查找符号表

    gcc -o test main.c -L. -lmypath

  7. -Wall 打开所有的编译警告

    gcc -Wall -o test main.c

  8. -static 优先选择链接静态库

    gcc -o test main.c -static -L. -lmymath

  9. -shared 生成的目标为共享库

    gcc -shared -o libmymath.so a.c b.c

  10. -o 指定生成目标的名字

  11. -Wl 传递参数给链接器

    • gcc -o test main.c -Wl,-Map=out.map -L. -lmymath

    • gcc -o test main.c -Wl,-rpath=/media/code/exercise/gcc -L. -lmymath

  12. rpath 的作用是添加目录到运行时共享库搜索路径

  13. -g 生成debugging信息, 在使用debug工具比如GCB的时候需要

    gcc -g -o test main.c a.c .bc

结束语

虽然gcc是一个非常强大的工具, 但当一个工程比较庞大是, 直接使用gcc是不明智的选择.

  • 对于中等规模的工程,使用makefile来管理是一个不错的选择

  • 但对于非常庞大的工程, 比如KDE, 可以使用更高阶的管理工具, 比如 CMake , automake 以及 Scons

git 常用实例

Clone and Checkout

  1. clone远程仓库

  2. 删除远程分支

    git push origin --delete branchname

Tag

  1. 创建轻量级TAG

    git tag v-0.1

  2. 创建有附注的标签

    git tag -a v3.8rc -m "RC 3.8"

  3. 创建带签名的标签

    git tag -s v3.8rc -m "RC 3.8"

  4. 将标签v3.8rc推送到远程仓库orgin

    git push origin v3.8rc

  5. 将本地所有的标签都推送到远程仓库origin

    git push origin --tags

  6. 将标签v3.8rc 检出

    git checkcout -b NEWBRANCH v3.8rc

  7. 删除本地标签v0.1

    git tag -d v0.1

  8. 删除远程仓库上的标签k1.2.0

    git push origin --delete tag k1.2.0

Revert

我们家的宝贝女儿出生了

蓁蓁都出生一个月了, 还没为女儿说点什么.

宝贝, 对不起了. 不是爸爸懒, 是爸爸最近太忙了.

工作忙, 还有新房子的装修; 当然, 还有你哦, 宝贝.

小咪的奇怪行为

  1. 听到人咳嗽或者打喷嚏, 总是会低低的叫一声, 好像是回应什么

  2. 优先选择高处的水, 比如经常喝餐桌或者茶几上水杯中的水

_IOC定义的不严谨性

C语言中默认类型转换绝对是一个坑. 最近项目中有以下一段code, 隐藏了一个很严重的BUG.

int v4l2_ioctl(int requet, void *arg) {
        if (UVCIOC_CTRL_QUERY == request) {
        /* do something */
        }
}

实际执行过程发现, UVCIOC_CTRL_QUERY == request 永远为false, 即使request == UVCIOC_CTRL_QUERY.

运行环境:

Ubuntu12.04 x86_64

写了一段测试code: .. sourcecode:

int main(int argc, char **argv)
{
        int request = UVCIOC_CTRL_QUERY;

        if (UVCIOC_CTRL_QUERY == request)
                fprintf(stdout, "equal\n");
        else
                fprintf(stdout, "different\n");
        return 0;
}

编译, 运行, 得到的结果是 different, 应该是默认转换出了问题. 查看UVCIOC_CTRL_QUERY的定义, 所用到的宏主要定义在 <linux/uvcvideo.h><sys/ioctl.h>.

#define _IOC_TYPECHECK(t) (sizeof(t))
# define _IOC_WRITE     1U
# define _IOC_READ      2U
#define _IOC(dir,type,nr,size) \
        (((dir)  << _IOC_DIRSHIFT) | \
         ((type) << _IOC_TYPESHIFT) | \
         ((nr)   << _IOC_NRSHIFT) | \
         ((size) << _IOC_SIZESHIFT))
#define _IOWR(type,nr,size)     _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))
#define UVCIOC_CTRL_QUERY       _IOWR('u', 0x21, struct uvc_xu_control_query)

将UVCIOC_CTRL_QUERY 展开, 得到的定义是:

(3U << 30) | ((sizeof(struct uvc_xu_control_query)) << 16) | ('u' << 8) | (0x21)

计算得到的结果为 0xC0107521

在64位机器上, sizeof的返回类型为 long unsigned int. 所以UVCIOC_CTRL_QUERY的类型为 long unsigned int. 所以UVCIOC_CTRL_QUERY的实际值为 0x00000000C0107521

在上述code发生了两次默认转换:

  1. requet = UVCIOC_CTRL_QUERY

    • long unsigned int 转换为int

    • long unsigned int 的长度为64 bits, int 为32 bits, 直接截断

    • 转换后 request=-1072663263(0xC0107521) , 小于 0

  2. UVCIOC_CTRL_QUERY == request

    • requet 转换为 long unsigned int

    • 转换后为 0xFFFFFFFFC0107521

    • UVCIOC_CTRL_QUERY != 0xFFFFFFFFC0107521

request 参数是传给系统调用ioctl的第二个参数, 而ioctl的定义为:

int ioctl(int d, int request, ...)

所以将 requet 定义为unsigned int 也不合适.

无论在64位还是32位的机器上, _IOC的定义应该为uint32_t, 所以_IOC的定义应该加强制类型转换.

#define _IOC(dir,type,nr,size) \
        (uint32_t) (    \
        (((dir)  << _IOC_DIRSHIFT) | \
         ((type) << _IOC_TYPESHIFT) | \
         ((nr)   << _IOC_NRSHIFT) | \
         ((size) << _IOC_SIZESHIFT)))

使用nikola生成静态博客

创建静态博客

使用WrodPress管理和编辑博客, 总觉得不顺手.

  • 有点大, 不利用备份

  • 不方便做版本控制

  • 没有找到合适的编辑工具

后来有同事介绍用sphinx编辑spec. sphinx采用reStructuredText作为标记语言, 可以生成PDF, html等多种格式. 开始考虑是否可以用reStructuredText编辑内容, 然后利用sphinx生成html.尝试几个theme, 都不是太理想.

学习sphinx的过程中, 偶尔发现一个网站介绍pelican和nikola. 尝试了nikola, 发现基本满足需求. nikola提供了一个脚本可以将wordpress中的内容转换为reStructuredText格式, 随将博客迁移过来.