#52 Ubuntu 从 18.10 升级到 19.04 过程中出现的三个问题

2019-04-26

Ubuntu 19.04 与 4/19 发布,生命周期 9 个月。我提前两个月就定着日程在等,总是克制不住追新的冲动,哈哈。

好像主要就是:

  1. 内核升级到 5.0(4.x 升级到 5.0 其实没有什么大变化,主要是老人家高兴)
  2. GNOME 3.32,之前是 3.30
do-release-upgrade

由于审计过程中意外中断,导致出现了一些问题,这里做个记录。
声明:这些问题,是非正常升级流程出现的,不是说是 Ubuntu 的问题。

#51 Linux 内存占用情况分析

2019-04-04

以我本地系统(Ubuntu)上的 supervisord 为例。

  1. ps -ef | grep supervisord / pgrep supervisord
  2. sudo cat /proc/1553/maps
  3. sudo gdb attach 1553
  4. gdb 中导出指定区域内存
    dump memory /tmp/1553-heap.mem 0x564a7e667000 0x564a7eb25000
  5. 显示内存数据
    strings -n 10 /tmp/1553-heap.mem
    ASCII 格式的展示,过滤掉长度少于 10 的行。

关于 /proc/pid/maps 文件的格式

内存映射(mmap):

  • 文件映射,将整个文件或文件的一部分映射到内存中
  • 匿名映射,创建一个全为 0 的内存空间

这里的 maps 文件就是内存映射的一个情况。

  1. 内核操作集:proc_pid_maps_op,导出函数:show_map(没接触过内核开发)
  2. 可以 sudo head /proc/self/maps 试试。当前进程的内存映射信息表,软链接。
  3. Linux 内存管理单元数据结构:vm_area_struct
$ sudo head /proc/1553/maps
564a7d858000-564a7d8a5000 r--p 00000000 08:01 3018208                    /usr/bin/python2.7
564a7d8a5000-564a7da56000 r-xp 0004d000 08:01 3018208                    /usr/bin/python2.7
564a7da56000-564a7db65000 r--p 001fe000 08:01 3018208                    /usr/bin/python2.7
564a7db66000-564a7db68000 r--p 0030d000 08:01 3018208                    /usr/bin/python2.7
564a7db68000-564a7dbde000 rw-p 0030f000 08:01 3018208                    /usr/bin/python2.7
564a7dbde000-564a7dc02000 rw-p 00000000 00:00 0
564a7e667000-564a7eb25000 rw-p 00000000 00:00 0                          [heap]
7fe8e4308000-7fe8e4448000 rw-p 00000000 00:00 0
7fe8e4448000-7fe8e444c000 r--p 00000000 08:01 1840428                    /lib/x86_64-linux-gnu/libexpat.so.1.6.8
7fe8e444c000-7fe8e446d000 r-xp 00004000 08:01 1840428                    /lib/x86_64-linux-gnu/libexpat.so.1.6.8
  • 第一列:address 地址。[vm_start, vm_end),即起始地址-结束地址。
  • 第二列:perms 权限。vm_flags,前三位分别是 r/w/x,不必说,第四位有两种值:ps,分别表示私有 private 或共享 shared。
  • 第三列:offset 偏移。vm_pgoff,如果是从文件映射到内存,那么偏移值表示从这个文件的指定位置开始,否则就会是 00000000
    我猜,可能比较多的是用在拓展库之类的方面。
  • 第四列:dev 设备。主设备号:次设备号,同样适用于从文件映射到内存的情况,表示文件所存放的设备。
  • vm_file->f_dentry->d_inode->i_sb->s_dev
  • 第五列:inode FS索引节点。同样适用于从文件映射到内存的情况,表示文件所存放的 “块”(或者叫 “区域” 吧)。
  • vm_file->f_dentry->d_inode->i_ino
  • 0 表示不关联,dev 字段也应该为 00000000
  • 第六列:pathname 文件名
  • 文件名
  • 这段虚拟内存在进程中的角色,常见的:
    • [heap]
    • [stack] 栈,主线程(main process)
    • [stack:1001] 栈,线程 ID 我还没见到过这样的情况
    • [vdso]
    • [vvar]
    • [vsyscall]
  • 匿名映射
    • 不显示,其他情况

其他

  1. 据说,主线程申请内存(malloc)会显示 [heap],子线程申请则是匿名映射。
  2. 子线程的栈空间动态分配,匿名。这就是我没看到一例类似 [stack:1001] 情况的原因么?
  3. 从 maps 文件记录上看,增加一个子线程,在 maps 文件中就增加了两条记录,分别是子线程的栈空间和栈保护页的记录。默认情况下,pthread为子线程预留的栈空间大小为1MB,栈保护页为4KB(这主要跟页大小相关)。

#!/usr/bin/env python
import re
maps_file = open('/proc/self/maps', 'r')
mem_file = open('/proc/self/mem', 'r', 0)
for line in maps_file.readlines():  # for each mapped region
    m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])', line)
    if m.group(3) == 'r':  # if this is a readable region
        start = int(m.group(1), 16)
        end = int(m.group(2), 16)
        mem_file.seek(start)  # seek to region start
        chunk = mem_file.read(end - start)  # read region contents
        print chunk,  # dump contents to standard output
maps_file.close()
mem_file.close()
sudo awk -n -F '[- ]' '/\[heap\]/ {h="0x"$2-"0x"$1+1;printf("%d bytes (%.2f MB)\n",h,h/1024/1024)}' /proc/1553/maps

python -c "import sys;a,b=sys.argv[1].split('-');ai=int('0x'+a,16);bi=int('0x'+b,16);x=(bi-ai+1);y=x/(1024*1024);print('%d Bytes (%.2f MB)'%(x,y));" 55854b0f5000-55855a372000

参考资料或拓展阅读

  1. colin.guru,Dumping Ram From Running Linux Processes
  2. StackOverflow,How to identify STACK and HEAP segments in /proc/$PID/maps file?
  3. StackOverflow,How do I read from /proc/$pid/mem under Linux?
  4. CSDN,linux proc maps文件分析

#50 TeamViewer 扑街之后的远程终端解决方案

2019-03-21

从今天开始,打开 TeamViewer 就这样了。


商业用途
检测为商业用途
该软件似乎适用于商业环境。请注意:免费版仅供个人使用。
您的会话将在5分钟后终止。请登录我们的网站以获得更多信息。

商业用途
超时后连接将被阻断。
您的许可证对您与伙伴的最大会话时间有所限制,立即重新连接时将被阻断。请稍后再试或升级您的许可证。
与该伙伴的连接在07:33之前都将保持阻断。

我不喜欢下那些破解版软件,对原开发者来说,就是偷东西,总觉得有亏于人。
另一方面也不放心其安全性。

但是,这价格真心用不起。

新方案

需求

远程访问公司的工作机器

备选方案

不管什么方案,从两个内网机器想要实现通信,只能有一个双方都能连接的外网主机进行中转。

我对自己家的公网 IP 很久以前就绝望了,我打电话给电信要求分配公网 IP,之后他们说给我开了,然后我要求进入光猫最高权限,进去设置端口转发规则,不行。。。那要公网 IP 有捷豹用啊!

所以:

  1. 要么别个给免费的全套远程桌面访问解决方案(一般有些限制),比如行云管家
  2. 要么给免费的数据转发(一般也有些带宽之类的限制),或许附带专用软件。

只要能流畅使用终端,都可以接受。

在研究方案的过程中,发现了另一个好的选择:tmate.io。

tmate.io

这是 tmux 的分支。
tmux 我用过好一阵子,也很容易上手。

使用方法:

# 创建远程连接
tmate -S /tmp/tmate.sock new-session -d

# 显示 SSH 连接命令
tmate -S /tmp/tmate.sock display -p '#{tmate_ssh}'

思路

创建定时任务,定时检查并建立 tmate 连接,然后将 ssh 命令输出到文件里面。
文件位于我的坚果云文件同步目录 $HOME/Documents/Mine/,这样我在任何地方都能通过 SSH 访问公司的电脑。

/etc/cron.d/tmate

SHELL=/usr/bin/zsh
* * * * * markjour [ -f $HOME/Documents/Mine/tmate.now ] && $HOME/Documents/Mine/tmate.sh && rm $HOME/Documents/Mine/tmate.now

~/Documents/Mine/tmate.sh

#!/usr/bin/zsh

tmate -S /tmp/tmate.sock kill-session
tmate -S /tmp/tmate.sock new-session -d
sleep 3
tmate -S /tmp/tmate.sock display -p '#{tmate_ssh}' > ~/Documents/Mine/tmate.conn

我在家只需要在同步目录下创建一个名为 tmate.now 的文件,一会儿就能用上 ssh 了。

#49 Web 保存数据的特殊方案

2018-11-08

将数据通过编码存在图片里面,实现导出导入功能。
虽然我不知道什么场景下需要使用这个方案,但这个想法特有意思。

#47 Linux date 命令

2018-07-03
date
2018年 07月 03日 星期二 14:09:28 CST

# locale 格式
date +"%c"
2018年07月03日 星期二 14时09分22秒

# RFC3339 格式
date --rfc-3339=s
2018-07-03 14:09:48+08:00

# UTC 时间,ISO 8601 格式
date -u +"%Y-%m-%dT%H:%M:%SZ"

# yyyy-mm-dd hh:mm:ss,mm
date +'%Y-%m-%d %H:%M:%S,%3N'
2018-07-03 14:09:20,902

# 获取时间戳
date +%s

# 时间字符串转时间戳
date -d "2018-07-03 14:09:00" +%s
1530598140
date -d "2018-07-03 14:09:00" +%s --utc
1530626940

# 时间戳转时间字符串
date -d @1530598140
2018年 07月 03日 星期二 14:09:00 CST
date +'%Y-%m-%d %H:%M:%S' -d @1530598140
2018-07-03 14:09:00

# 获取一分钟前的时间
date --rfc-3339=s -d '1 min ago'
date --rfc-3339=s -d '1 minute ago'
date --rfc-3339=s -d '1 minutes ago'

# 获取一个小时前的时间
date --rfc-3339=s -d '1 hour ago'

#46 free 输出解读

2018-06-12
  • total 内存总数
  • used 使用内存
  • free 未使用内存
  • shared Memory used (mostly) by tmpfs (Shmem in /proc/meminfo)
  • buffers Memory used by kernel buffers (Buffers in /proc/meminfo)
  • cached Memory used by the page cache and slabs (Cached and SReclaimable in /proc/meminfo)
  • available 可用内存

#45 Logrotate

2018-05-03

配置

# cat /etc/logrotate.conf
weekly
su root adm
rotate 4
create
#dateext
#compress
include /etc/logrotate.d

以 Nginx 配置为例:

# cat /etc/logrotate.d/nginx
/var/log/nginx/*.log {
        daily       # 按日切割
        missingok   # 如果文件不存在,则不创建
        rotate 14   # 最多保留 14 个日志文件
        compress    # 压缩
        delaycompress   # 延迟压缩
        notifempty      # 如果文件为空,则不创建
        create 0640 www-data adm

        # 可能一次切割多个日志,
        # 但是后面遇到的每个脚本都只执行一次,
        # 在所有日志切割之前或之后
        sharedscripts

        prerotate
                if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
                        run-parts /etc/logrotate.d/httpd-prerotate; \
                fi \
        endscript

        postrotate
                invoke-rc.d nginx rotate >/dev/null 2>&1
        endscript
}

其他常用选项:

  • dateext 部分日志需要添加日期后缀
  • lastaction/endscript 最后执行的指令,很有用,比如最后将日志备份到某些地方

比如:

rsync -au *.gz 192.168.64.234:/backup/nginx-logs/`hostname -s`/

参考资料与拓展阅读

#44 shar: Shell Archive

2018-02-02
sudo apt install sharutils

提供四个命令:

  • shar: create a shell archive
  • unshar: unpack a shar archive
  • uudecode: decode an encoded file
  • uuencode: encode a file into email friendly text

uuencode 是一种二进制转文本编码,类似 Base64

没想到还有些包依赖这个上世纪遗留下来的编码(包括 gcc):

apt rdepends sharutils
sharutils
Reverse Depends:
  建议: file-roller
  依赖: wide-dhcpv6-client
  推荐: speechd-el
  建议: patool
  推荐: mgp
  建议: lxqt-archiver
  推荐: ldapscripts
  依赖: kpatch-build
  依赖: knews
  建议: git-dpm
  依赖: gcc-9-source
  依赖: gcc-12-source
  依赖: gcc-11-source
  依赖: gcc-10-source
  建议: engrampa
  依赖: biabam
  推荐: aespipe

python uuencode

import uu

uu.encode('/etc/passwd', '-')

注意:3.11 开始,python Deprecated 了这个 uu 模块, 可以改用 binascii.b2a_uu 代替。

import binascii

s = b''
with open('/etc/passwd', 'rb') as f:
    buf = f.read(45)
    while len(buf) > 0:
        s += binascii.b2a_uu(buf, backtick=False)
        buf = f.read(45)
print(s)

#43 Linux 文件系统

2018-01-25

物理结构

  1. 机械硬盘 Disk -> 盘片/盘面 Platter -> 磁道 Tracker -> 扇区 Physical Sector
  2. 光盘
  3. SSD -> NAND Package -> Die -> Plane -> Block -> Page
  4. 非易失性存储器(永久):NAND Flash
  5. 易失性存储器(临时):DRAM

扇区大小是厂商定的,一般是 512B 的倍数。
老的机械硬盘一般是 512B 扇区,新的机械硬盘一般是 4K 扇区(AF,Advanced Format)
光盘(CD/DVD)一般是 2K 扇区。

处于向前兼容的目的,其他类型存储设备的大小也一般是 512B。

逻辑结构

  • 逻辑扇区 Logical Sector
  • 块 Block
    Windows 下叫做 簇 Cluster,或者磁盘分配单元。
    PS:内存上的类似概念,是段 Segment 和页 Page
$ sudo fdisk /dev/sda -l
Disk /dev/sda: 40 GiB, 42949672960 bytes, 83886080 sectors
Disk model: VBOX HARDDISK
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 7EC7FA37-FE79-46C1-A404-56AA0E00CFAB

Device       Start      End  Sectors Size Type
/dev/sda1     2048     4095     2048   1M BIOS boot
/dev/sda2     4096  4198399  4194304   2G Linux filesystem
/dev/sda3  4198400 83884031 79685632  38G Linux filesystem

格式化

https://zh.wikipedia.org/wiki/磁盘格式化

  • 低级格式化、物理格式化

对于部分硬盘制造厂商,它也被称为初始化。
最早,低级格式化被用于指代对磁盘进行划分柱面、磁道、扇区的操作。
现今,随着软盘的逐渐退出日常应用,应用新的编址方法和接口的磁盘的出现,这个词已经失去了原本的含义,大多数的硬盘制造商将低级格式化定义为创建硬盘扇区(sector)使硬盘具备存储能力的操作。现在,人们对低级格式化存在一定的误解,多数情况下,提及低级格式化,往往是指硬盘的填零操作。

  • 高级格式化、逻辑格式化
    根据用户选定的文件系统,在磁盘的特定区域写入特定数据,以达到初始化磁盘或磁盘分区、清除原磁盘或磁盘分区中所有文件的一个操作。
    高级格式化包括对主引导记录中分区表相应区域的重写、根据用户选定的文件系统,在分区中划出一片用于存放文件分配表、目录表等用于文件管理的磁盘空间,以便用户使用该分区管理文件。

常见文件系统类型

  • FAT / FAT32 / exFAT
  • NTFS
  • EXT2 / EXT3 / EXT4
  • BTRFS
  • Apple HFS

参考资料与拓展阅读