作者归档:Neil

排除不受信任的根证书列表:cnnic, alibaba

今天心血来潮, 检查一下我的根证书列表:

certmgr.msc

排除了一些垃圾流氓证书到不受信任的列表, 以下是我的列表:

a

其中 'CNNIC ROOT' 自不必多说.

其中有三个证书值得一说:

  1. 首先说说前两个, 一个是 'Alibaba.com Corporation Root CA', 另一个是: 'ALIPAY_ROOT'. 作为一个第三方的电子商务公司, 我实在想不通他为什么要在我的机器里面装入 根证书. 而且可以看到这两个根证书的用途都是 "所有". 就是权限最大的根证书. 不光可以做普通证书做的事,比如签名,加密,时间戳等等. 甚至还能签发次级CA.

首先, alibaba 网站上使用的证书都是 来自第三方的verisign的. 这没有任何问题. 那他还要给我装权限如此之高的根证书的目的是什么? 除了耍流氓还有什么解释. 你当用户的电脑是韭菜园子吗? 你视用户的安全如空气吗? 有一天要逼我在虚拟机中使用 支付宝吗? 去年买了个包. 流氓.

  1. 再说说另一个, 就是图中的'ROOTCA', 名字看起来很唬人. 以为是正规的根证书.
    但是我们点开详细信息看看:
    b

发现他的 C=CN

原来, 这货和 CNNIC 是一路货色.果断禁用之.

最后分享一下禁用方法.
在"受信任的根证书颁发机构"中找到他们之后, 不能直接删除, 删除之后,有些会自动安装比如alibaba, 有些会通过windows自动更新重新装入, 比如CNNICroot. 正确的做法是, 用鼠标把他们拖到下面的 "不信任的证书" 分支里面.
这样就算重新安装了, 他们仍然是不受信的.

我很喜欢淘宝, alibaba, 支付宝, 也是马云的粉丝. 但是,无论是谁,耍流氓就不行. 让流氓证书滚粗.

php 操作数组 add_assoc_string 导致 崩溃

使用php内核的方法 操作数组时 导致 php崩溃。

int add_assoc_string ( zval* $arg, char* $key, char* $str, int $duplicate )*

http://php.undmedlibrary.org/manual/en/zend-api.add-assoc-string.php

原因是:第三个参数, 添加的字符串不能使NULL。

添加之前要先判。 如果是NULL, 应该使用专门加NULL的api:

int add_assoc_null ( zval* $arg, char* $key )

http://php.undmedlibrary.org/manual/en/zend-api.add-assoc-null.php

解决:fatal error C1902: Program database manager mismatch; please check your installation

重装系统后,VS2008编译出现错误。

fatal error C1902: Program database manager mismatch; please check your installation

可能是多版本共存引起的问题。

找到这篇文章:http://wordrump.com/how-to-fix-the-error-fatal-error-c1902-program-database-manager-mismatch-please-check-your-installation/

简单暴力, copy 这三个文件:

mspdb80.dll
mspdbcore.dll
mspdbsrv.exe


C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE

c:\windows

解决。

添加Access-Control-Allow-Origin主机头, 授权资源跨站访问

Access-Control-Allow-Origin 是html5 添加的新功能, chrome貌似前几天更新之后支持了这一特性.

基本上, 这是一个http的header, 用在返回资源的时候, 指定这个资源可以被哪些网域跨站访问.

比方说, 你的图片都放在 res.byneil.com 这个域下, 如果在返回的头中没有设置 Access-Control-Allow-Origin, 那么别的域是不能外链你的图片的.

当然这要取决于浏览器的实现是否遵守规范. 因为chrome最近的升级开始检查这个头了, 所以导致一些网站资源加载不进来.

解决方法就是 在资源的头中 加入 Access-Control-Allow-Origin 指定你授权的域. 我这里无所谓,就指定星号 * , 任何域都可以访问我的资源.

Access-Control-Allow-Origin: *

具体操作方法, 就是在nginx的conf文件中加入以下内容:

location / {
  add_header Access-Control-Allow-Origin *;
}

这样就好了.

linux 清理磁盘,查找大文件

查看磁盘的占用:

df  -h
neil@dedia:~$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda2       139G   37G   96G  28% /
none            4.0K     0  4.0K   0% /sys/fs/cgroup
udev            983M  4.0K  983M   1% /dev
tmpfs           199M  500K  198M   1% /run
none            5.0M     0  5.0M   0% /run/lock
none            992M     0  992M   0% /run/shm
none            100M     0  100M   0% /run/user
/dev/sda1       180M   34M  134M  20% /boot

如果需要清理磁盘的话, 用 find 命令找出大文件,然后酌情删除:

find / -size +100M -exec ls -lh {} \;

这就是要查找磁盘上大于100m 的文件.

参考:

http://lovesoo.org/linux-system-to-find-clean-the-disk-file.html

安装 jekyll 记录

* 安装 ruby

apt-get install ruby1.9.1

* 一定要再安装 ruby dev

apt-get install ruby1.9.1-dev

* 安装 jekyll

gem install jekyll

查看是否安装成功:

jekyll --version
  • 如果出现错误,找不到javascript 运行时, 类似:
execJs: 'Could not find a JavaScript runtime' but execjs AND therubyracer are in Gemfile

请安装 nodejs:

wget wget http://nodejs.org/dist/v0.10.31/node-v0.10.31.tar.gz

tar xf node-v0.10.31.tar.gz

cd node-v0.10.31

./configure

make && make install

* 如果一切顺利的话, 顺便再把markdown也装上吧:

gem install rdiscount

7z文件格式及其源码的分析(六)-完结篇

上一篇在这里 7z文件格式及其源码的分析(五)

这一篇主要介绍7z的流式压缩和解压原理.

对于流式处理来讲, 主要问题是要处理好文件头的问题. 因为是流式的, 所以,不可能走回头路. 也就不可能说压缩完了之后回到开头来修改头的信息.

7z文件的文件头其实是分为两部分的, 这两部分文件头在前面的几篇分析中都有介绍:

  1. 头Header, 就是写在文件前面的 Header. 这个头比较小, 主要记录了文件的版本信息, 以及尾header的位置偏移和校验和等等. 其主要作用是文件类型识别和查找到尾Header

  2. 尾Header, 就是写在文件末尾的 Header. 这里记录了 7z 文件的全部压缩信息, 解压主要就靠这里面的信息了.

7z 常见的压缩过程是: 先把 头Header 的一些位置保留, 然后压缩数据. 压缩完之后, 尾Header 写完之后, 再把 尾Header 的大小,偏移,校验和写回到 头Header 中去.

在流式环境下, 最后一步回头写 头Header 的过程显然不可能完成. 因为已经流过了.

那 7z 是怎么处理这个问题的呢? 7z 支持流式压缩吗?

7z 的文档里,并没有明确的回答这个问题. 我们还是让它的代码回答吧.

我们找到 7z 的解压代码, 7zIn.cpp 文件. 找到 HRESULT CInArchive::ReadDatabase2() 函数. 大概在 1136 行.

这个函数就是在读取 头Header 信息, 并查找 尾Header 位置.

我们截取它开头的一部分代码片段:

HRESULT CInArchive::ReadDatabase2(
    DECL_EXTERNAL_CODECS_LOC_VARS
    CArchiveDatabaseEx &db
    #ifndef _NO_CRYPTO
    , ICryptoGetTextPassword *getTextPassword, bool &passwordIsDefined
    #endif
    )
{
  db.Clear();
  db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;

  db.ArchiveInfo.Version.Major = _header[6];
  db.ArchiveInfo.Version.Minor = _header[7];

  if (db.ArchiveInfo.Version.Major != kMajorVersion)
    ThrowUnsupportedVersion();

  UInt32 crcFromArchive = Get32(_header + 8);
  UInt64 nextHeaderOffset = Get64(_header + 0xC);
  UInt64 nextHeaderSize = Get64(_header + 0x14);
  UInt32 nextHeaderCRC = Get32(_header + 0x1C);
  UInt32 crc = CrcCalc(_header + 0xC, 20);

  #ifdef FORMAT_7Z_RECOVERY
  if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)
  {
    UInt64 cur, cur2;
    RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur));
    const int kCheckSize = 500;
    Byte buf[kCheckSize];
    RINOK(_stream->Seek(0, STREAM_SEEK_END, &cur2));
    int checkSize = kCheckSize;
    if (cur2 - cur < kCheckSize)
      checkSize = (int)(cur2 - cur);
    RINOK(_stream->Seek(-checkSize, STREAM_SEEK_END, &cur2));

    RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize));

    int i;
    for (i = (int)checkSize - 2; i >= 0; i--)
      if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] == 0x04)
        break;
    if (i < 0)
      return S_FALSE;
    nextHeaderSize = checkSize - i;
    nextHeaderOffset = cur2 - cur + i;
    nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize);
    RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL));
  }
  else
  #endif
  {
    if (crc != crcFromArchive)
      ThrowIncorrect();
  }

  db.ArchiveInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;


(...)

}

可以看到, 下面这几句是在从 头Header 上读取 尾Header 信息.

  UInt32 crcFromArchive = Get32(_header + 8);
  UInt64 nextHeaderOffset = Get64(_header + 0xC);
  UInt64 nextHeaderSize = Get64(_header + 0x14);
  UInt32 nextHeaderCRC = Get32(_header + 0x1C);
  UInt32 crc = CrcCalc(_header + 0xC, 20);

紧接着, 后面又有一句判断:

if (crcFromArchive == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)

如果这几个都读不到怎么办.

看代码, 接下来, 它会从文件末尾开始, 倒着向前查找特征字符:

if (buf[i] == 0x17 && buf[i + 1] == 0x6 || buf[i] == 0x01 && buf[i + 1] == 0x04)

这就是在找 0x17 0x06 或者 0x01 0x04 这两个特征串.

代码已经很明确了:

如果找到这其中之一, 就算是找到 尾Header 了.

为什么能这么做呢, 这两个串代表什么呢?

通过查看7z的文档(事实上, 前面讲的 尾Header 的结构的时候也能发现)知道.

  1. 0x17 是代表压缩Header的标记 kEncodedHeader. 后面的 0x06 是 packstream 的标记 kPackInfo.
  2. 0x01 是代表普通Header的标记 kHeader. 而 0x04 是 mainstream 的标记 kMainStreamsInfo.

这正是 7z 的两种 尾Header 的格式.

到这里, 可以总结一下了:

7z 流式压缩
压缩时可以把 头Header 中的 偏移量和 crc 和等 留空.
在解压时, 如果检测到这些留空了, 则会从文件末尾开始查找 尾Header 特征串.

这种方法可以一定程度实现 流式压缩. 虽然 7z 的文件结构本身,限制它不适合流式压缩的.

欢迎大家讨论交流: Neil 的博客

Ubuntu 启用磁盘配额 quota

quota 可以为用户或用户组设置磁盘配额. 限制用户或用户组能使用的磁盘大小.

1. 安装 quota :

sudo apt-get install quota

2. 编辑 /etc/fstab 文件,启用 quota

vi  /etc/fstab

添加 usrjquota=aquota.user,grpjquota=aquota.group,jqfmt=vfsv0 到需要启用 quota 的分区. 比如 /:

# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point>   <type>  <options>       <dump>  <pass>
# / was on /dev/sda2 during installation
UUID=7cf8dc2b-2541-4684-8931-844b6bd01e9c /               ext4    errors=remount-ro,usrjquota=aquota.user,grpjquota=aquota.group,jqfmt=vfsv0 0       1
# /boot was on /dev/sda1 during installation
UUID=4541b27d-84d6-4f70-9077-7cb9308634b6 /boot           ext4    defaults        0       2
# swap was on /dev/sda3 during installation
UUID=ccae84a6-7423-4e60-9448-0cf05a053fbc none            swap    sw              0       0

3. 重新挂载分区:

touch /aquota.user /aquota.group
chmod 600 /aquota.*
mount -o remount /

4. 启用 quota :

quotacheck -avugmc
quotaon -avug

参考:

http://www.howtoforge.com/how-to-set-up-journaled-quota-on-debian-lenny
http://manpages.ubuntu.com/manpages/hardy/zh_CN/man1/quota.1.html

sed 命令的简单用法

我们在编写shell的时候, 可能需要修改一些配置文件, 比如需要修改mysql的配置文件, 在里面添加一些设置,修改一些或者删除一些.

怎么在shell中来编辑 文本文件呢.

在交互式环境下, 使用vi就可以了. 手动去修改. 但是在无人值守的shell中呢?

这里,就要用到 sed 命令了.

sed 的意思是: stream editor, 就是流式编辑器.

跟很多命令行工具(比如awk)一样, 他的功能及其强大, 当然用法和参数也及其复杂. 这里以极简的方式记录几种用法, 常用的编辑功能基本都能满足了.

sed 处理的基本方式

它的基本命令格式大概是这个样子的:

sed -options /patterns  file

它的意思是要处理 文件 file, 并且把处理结果直接回显到屏幕上. 所以通常需要配合重定向来保存处理结果.

它通常的工作样式是这样的:

sed -options  /patterns  file > saved.txt

当然, 可以不用重定向, 而直接指定保存文件名. 这里用到 -i 参数.
比如:
sed -i saved.txt -options /patterns file
这样在-i后面跟上一个文件名,就可以了.
如果 -i 后面没有跟文件名, 那么, 编辑结果将会保存到原文件.
sed -i -options /patters file
这样, 就是直接修改原文件了.
因为我通常都是想直接修改原文件的, 所以下面我都加上-i 参数了.

sed 的基本编辑操作.

替换 是我们最常用的操作.
他的命令样式为:

sed -i  "s/aaaa/bbbb"  file

这个命令就是把file中的所有字符串aaaa替换成bbbb, 并保存到原文件中(因为有-i 参数).

前插入 就是在某个特征字符串的前面插入内容.

命令为:

sed -i  "/aaa/i bbbb"  file  

这个命令是在aaa的前面插入一行bbbb, 注意中间的那个字母 i, 表示insert.

后插入 就是在某个特征字符串的后面插入内容.

命令为:

sed -i  "/aaa/a bbbb" file 

这个命令是在aaa的后面插入一样bbbb, 注意中间那个字母a, 表示append.


欢迎访问我的个人博客: http://byNeil.com

mysql免密码登录, 及使用-e 参数执行sql脚本

我们在编写shell脚本的时候,经常需要和 mysql 交互.

如果是交互环境,可能使用这样的命令登录到mysql

#mysql –uroot –p

然后按提示输入密码, 登录. 如果在脚本中, 我们就不得不把密码写在 –p 参数后面. 这样 很容易暴露密码.

幸好mysql提供的有解决方案. 在 “~/.my.cnf” 文件中保存密码就行了.

MySQL官方文档

文件内容大概如下:

[client]

password="MySQL密码"

user=MySQL用户名

其中user 行可以省略, 默认使用当前的用户名填充mysql的登录用户名

再次使用 mysql 命令的时候,就无需输入用户名和密码了,可以自动登录.

还可以给 mysql 命令使用 --defaults-file 参数来指定特定的配置文件路径:

mysql --defaults-file=/folder1/folder2/filename -u 用户名

实现了免密码登录之后, 在脚本中就可以直接使用 -e 参数来执行sql脚本了, 而不用像交互式一样登录到mysql之后执行了.

mysql -e "CREATE DATABASE test" 

到这里, 基本上就可以实现完全的无值守 mysql脚本操作了.

参考: http://yzs.me/2142.html