0%

linux相关知识

一、系统知识

1. profilebashrcbash_profile之间的关系

  • /etc/profile: 此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行. 并从/etc/profile.d目录的配置文件中搜集shell的设置。
  • /etc/bashrc: 为每一个运行bash shell的用户执行此文件.当bash shell被打开时,该文件被读取。
  • ~/.bash_profile: 每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!默认情况下,他设置一些环境变量,执行用户的.bashrc文件。
  • ~/.bashrc: 该文件包含专用于你的bash shell的bash信息,当登录时以及每次打开新的shell时,该该文件被读取。
  • ~/.bash_logout: 当每次退出系统(退出bash shell)时,执行该文件. 另外,/etc/profile中设定的变量(全局)的可以作用于任何用户,而~/.bashrc等中设定的变量(局部)只能继承/etc /profile中的变量,他们是”父子”关系。
  • ~/.bash_profile是交互式、login 方式进入 bash 运行的
  • ~/.bashrc 是交互式 non-login 方式进入 bash 运行的通常二者设置大致相同,所以通常前者会调用后者。

2. service的几个知识

2.1. service linux服务管理

  • service有两种管理方式,一个是用service命令,一个使用systemctl,自己感觉没啥区别,都需要写一个service文件
  • service文件位置: /usr/lib/systemd/system/
  • 服务文件内容一般如下,具体作用查看man systemd.service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[Unit]
Description=OpenBSD Secure Shell server
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755

[Install]
# 这个是用来配置开机启动的目标,在multi-user模式下启动服务
WantedBy=multi-user.target
Alias=sshd.service
  • 配置了WantedBy后,使用systemctl enable xxx可以设置服务在某个模式下启动,会创建一个连接到/etc/systemd/system/xxx.target.wanted/
  • 一般配置开机启动设置WantedBy为multi-user.target,然后执行上一行的命令即可
  • Type=forking会检测pidfile的进程状态

2.2. 查看服务启动日志

1
2
# -f 跟踪日志
journalctl -u [service_name] -f

3. 开机启动脚本

update-rc.d enable/disable/defaults

4. 设备event事件查看

  • 使用下面命令可以查看键盘插入或者触摸板移动等信息
1
2
# -w 跟踪
dmesg -w
  • 使用下面命令查看usb拔插事件
1
udevadm monitor --environment --udev

5. 用户组

5.1. 几个基本用法

1
2
3
4
5
6
# 将用户变更主组到group_name
usermod -g [group_name] [user_name]
# 添加用户组属性,不修改原有所属组
usermod -a -G [group_name] [user_name]
# 查看用户所属组
groups [user_name]

6. 查看系统启动时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
########## who命令 ##########
# 查看最后一次系统启动时间
=> who -b
系统引导 2022-01-06 10:22
# 查看当前系统运行时间
=> who -r
运行级别 3 2022-01-06 10:24

########## last命令 ##########
=> last reboot
reboot system boot 4.19.181 Thu Jan 6 10:22 still running
reboot system boot 4.19.181 Sat Dec 18 20:06 - 10:20 (18+14:14)
reboot system boot 4.19.181 Sat Dec 18 19:26 - 20:04 (00:38)
reboot system boot 4.19.181 Tue Dec 7 13:49 - 20:04 (11+06:15)
reboot system boot 4.19.163 Mon Nov 22 22:41 - 13:47 (14+15:06)

wtmp begins Mon Nov 22 10:40:48 2021

########## uptime命令 ##########
# 只能看当前时间和启动了多久
=> uptime
10:37:02 up 3 days, 17:50, 0 users, load average: 5.29, 5.16, 5.04

########## /proc/uptime ##########
# 展示从系统启动到现在经过多少s
=> cat /proc/uptime
16235.69 22108.34

7. 定时任务

7.1. cron格式说明

1
2
3
4
5
6
7
8
9
*    *    *    *    *    *
┬ ┬ ┬ ┬ ┬ ┬
│ │ │ │ │ |
│ │ │ │ │ └ 星期 (0 - 7) (0或7都是星期日)
│ │ │ │ └───── 月份 (1 - 12)
│ │ │ └────────── 日期 (1 - 31)
│ │ └─────────────── 小时 (0 - 23)
│ └──────────────────── 分钟 (0 - 59)
└───────────────────────── 秒 (0 - 59, optional)

8. 进程的几种状态

top进程状态解析

9. /dev 介绍

9.1. /dev/random/dev/urandom

  • 用于产生真随机数,其中/dev/random依赖系统中断,所以较慢,但是随机性更好
  • /dev/urandom不依赖系统中断,随机性较差
  • 它们都依赖一个系统熵
    • 熵足够,两个都是真随机
    • 熵不足,/dev/random会阻塞,/dev/urandom不会阻塞,依赖算法
  • 查看熵池大小: /proc/sys/kernel/random/poolsize
  • 查看熵池可用的数量: /proc/sys/kernel/random/entropy_avail
  • /dev/random/dev/urandom都是字符型设备,可以当作文件直接读取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
=> stat /dev/random
File: /dev/random
Size: 0 Blocks: 0 IO Block: 4096 character special file
Device: 0,5 Inode: 8 Links: 1 Device type: 1,8
Access: (0666/crw-rw-rw-) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2022-03-22 09:53:37.442304649 +0800
Modify: 2022-03-22 09:53:37.442304649 +0800
Change: 2022-03-22 09:53:37.442304649 +0800
Birth: -
=> stat /dev/urandom
File: /dev/urandom
Size: 0 Blocks: 0 IO Block: 4096 character special file
Device: 0,5 Inode: 9 Links: 1 Device type: 1,9
Access: (0666/crw-rw-rw-) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2022-03-22 09:53:37.442304649 +0800
Modify: 2022-03-22 09:53:37.442304649 +0800
Change: 2022-03-22 09:53:37.442304649 +0800
Birth: -

如果不存在,可以通过下面命令挂载

1
2
mknod /dev/random c 1 8
mknod /dev/urandom c 1 9

10. /proc介绍

  • /proc内存放了进程的信息

10.2. /proc/[pid] 进程信息

  • /proc/self为当前进程信息,可以直接在程序中进行读取

1) fd 保存当前进程打开的句柄

  • 0: 标准输入
  • 1: 标准输出
  • 2: 标准错误输出

2) maps 进程内存空间信息

  • 加载了什么库及其地址
  • 进程的基地址信息

3) limits 显示进程的一些限制

  • unlimited就是没有限制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
=> cat /proc/self/limits
Limit Soft Limit Hard Limit Units
Max cpu time unlimited unlimited seconds
Max file size unlimited unlimited bytes
Max data size unlimited unlimited bytes
Max stack size 8388608 unlimited bytes
Max core file size unlimited unlimited bytes
Max resident set unlimited unlimited bytes
Max processes 14993 14993 processes
Max open files 1024 4096 files
Max locked memory 16777216 16777216 bytes
Max address space unlimited unlimited bytes
Max file locks unlimited unlimited locks
Max pending signals 14993 14993 signals
Max msgqueue size 819200 819200 bytes
Max nice priority 0 0
Max realtime priority 0 0
Max realtime timeout unlimited unlimited us

硬限制和软限制

  • 硬限制只能由root用户进行扩大
  • 软限制由用户自己修改,不能超过硬限制

4) cwd 当前工作目录

  • cwd是一个软连接,指向对应的工作目录
  • 查看进程当前工作目录
1
2
=> ll /proc/57733/cwd
lrwxrwxrwx 1 test test 0 Aug 16 09:29 /proc/57733/cwd -> /home/test

10.3. /proc/sys 保存内核的参数

1) 列举几个内核参数含义

  • /proc/sys/fs/file-max: 系统最多能打开的文件句柄数
  • /proc/sys/kernel/threads-max: 系统最大线程数量
  • /proc/sys/kernel/pid-max: pid的最大数

2) /proc/sys/net/ipv4/conf/interface/rp_filter

rp_filter在内核代码如何生效

  • 对应sysctl变量net.ipv4.conf.[interface].rp_filter
  • 内核取值会取all和当前进入的网卡较大的那个值
  • rp_filter设置成1则会在当前网卡收包处理时,如果发现源地址作为目的地址路由不是指向此网卡,将会丢包,具体原理看上面链接
  • 设置值的说明见 rp_filter|sysctl-explorer.net

11. 管道

  • 进程间通信可以使用管道
  • 管道的本质是起了两个子进程,一个进程的标准输出为另一个进程的标准输入

11.1. 示例

  • 使用read让管道两边的进程阻塞
1
2
=> { echo "aaa"; read n } | { cat; read p }
aaa
  • 查看进程树
1
2
3
4
5
6
=> ps -auxf
...
test_user 2262 0.0 0.0 16840 8192 pts/2 Ss 11:41 0:01 | \_ -zsh
test_user 10342 0.0 0.0 16840 3412 pts/2 S+ 14:20 0:00 | | \_ -zsh
test_user 10343 0.0 0.0 10792 976 pts/2 S+ 14:20 0:00 | | \_ cat
...
  • 明显看到父进程起了两个子进程
  • 再查看它们的句柄
1
2
3
4
5
6
7
8
9
10
11
=> ls -l /proc/10342/fd
total 0
lrwx------ 1 test_user test_user 64 Jun 20 14:27 0 -> /dev/pts/2
l-wx------ 1 test_user test_user 64 Jun 20 14:27 1 -> 'pipe:[224646]'
lrwx------ 1 test_user test_user 64 Jun 20 14:27 10 -> /dev/pts/2
lrwx------ 1 test_user test_user 64 Jun 20 14:27 2 -> /dev/pts/2
=> ls -l /proc/10343/fd
total 0
lr-x------ 1 test_user test_user 64 Jun 20 14:27 0 -> 'pipe:[224646]'
lrwx------ 1 test_user test_user 64 Jun 20 14:27 1 -> /dev/pts/2
lrwx------ 1 test_user test_user 64 Jun 20 14:27 2 -> /dev/pts/2
  • 左边进程的标准输出到管道,右边进程的标准输入为管道

12. 文件类型

  • linux下存在很多种文件类型,一切皆文件
  • 使用ls -l可以查看文件类型

几种类型

  • -: 普通文件,文本或二进制
  • d: 目录
  • l: 链接
  • b: 块设备,磁盘就是块设备,可以向前向后读
  • c: 字符型设备,比如/dev/zero/dev/random等,只能读取当前
  • s: 套接字文件,用于链接建立等
  • p: 管道文件,不过一般是命名管道,正常的管道一般不可见

13. 进程

13.1. 最多能创建多少线程

  • 取决于进程的虚拟内存大小和每个线程需要占用的栈大小
  • 32位系统下,4G虚拟内存,内核占用1G,剩余3G。每个线程栈大小,由ulimit -s可以查看,假设8M。那么最多创建300多个线程就会内存不足
  • 64位系统下,取决于linux系统下的线程最大数量、全局pid号数量限制、进程可以拥有的VMA数量

13.2. 最大能打开的文件句柄数

14. 可执行文件的结构

14.1. 查看可执行文件的大小

1
2
3
4
5
#include <stdio.h>

int main(int argc, char **argv) {
printf("Hello, world");
}
1
2
3
4
=> gcc -g main.cpp
=> size a.out
text data bss dec hex filename
1576 616 8 2200 898 a.out

14.2. 解析

1) bss 未初始化数据区

  • Block Started by Symbol 以符号开始的段,通常指未初始化的数据段
  • 代码中定义的未初始化的全局变量和静态变量存放到此区域
  • 此区域会被内核初始化成0,所以为什么没有初始化的全局变量和静态变量会是0的原因
1
2
3
4
5
6
7
#include <stdio.h>

int a[1000];

int main(int argc, char **argv) {
printf("Hello, world");
}
1
2
3
4
=> gcc -g main.cpp
=> size a.out
text data bss dec hex filename
1576 616 4008 6200 1838 a.out
  • 可以看到bss段增加了4 * 1000字节

2) data 静态数据和全局初始化的数据区

  • 初始化的静态变量和全局变量会放到此区域
  • 初始化成0的变量会被编译器优化放到bss段
1
2
3
4
5
6
7
8
#include <stdio.h>

int a = 100;
int b = 0;

int main(int argc, char **argv) {
printf("Hello, world");
}
1
2
3
4
=> gcc -g main.cpp
=> size a.out
text data bss dec hex filename
1576 620 12 2208 8a0 a.out
  • 可以看到定义了两个int型变量,一个增加了data段,一个增加了bss段,各4个字节

3) text 代码段,存放代码指令

1
2
3
4
5
6
#include <stdio.h>

int main(int argc, char **argv) {
printf("Hello, world");
printf("Hello, world1");
}
1
2
3
4
=> gcc -g main.cpp
=> size a.out
text data bss dec hex filename
1605 616 8 2229 8b5 a.out
  • bss和data都没增加,text段增加了代码指令

二、有用的几个技巧

1. linux启动到文本界面和到图形界面

1
2
3
4
# 启动到文本界面
systemctl set-default multi-user.target
# 启动到图形界面
systemctl set-default graphical.target

2. 修改硬盘的uuid

1
2
3
4
# 随机生成uuid写入
uuidgen | xargs tune2fs /dev/sda5 -U
# 写入自己生成uuid
tune2fs -U c1b9d5a2-f162-11cf-9ece-0020afc76f16 /dev/sdb1

3. hostname立即生效

1
hostname "$(cat /etc/hostname)"

4. bpf 主要用于网络数据分析

原理参考 Linux超能力BPF技术介绍及学习分享

  • 新版tcpdump就是基于bpf技术实现的

5. 设置无操作用户自动退出

  • 修改/etc/profile,添加
1
2
export TMOUT=15   # 无操作15秒自动退出
readonly TMOUT # 不允许用户修改此变量

6. 系统时间和硬件时间同步

  • 使用hwclock命令
  • 下面是几种基本用法
1
2
3
4
5
6
7
# 显示硬件时间,启动就会读取的时间,和系统不一致就是每次重启时间都不对
=> sudo hwclock --show
2022-12-09 17:35:28.288827+08:00
# 硬件时间同步到系统时间,开机会自动执行
=> sudo hwclock --hctosys
# 系统时间同步到硬件时间,可以在同步系统时间后进行执行,保证重启后和当前一致
=> sudo hwclock --systohc

7. 设置时区

1
ln -sf /usr/share/zoneinfo/Asia/Beijing /etc/localtime

8. 添加一个用户

1
2
3
4
5
6
7
8
9
# 添加用户
# -d 设置home目录
# -s 设置shell
useradd test -d /home/test -s /bin/zsh
# 设置密码
passwd test
# 添加目录
mkdir /home/test
chown test:test /home/test

8.1. 给用户执行sudo的权力

  • 需要安装sudo包,然后执行visudo
  • 在打开的sudoers文件中,找到以下行:root ALL=(ALL) ALL
  • 在该行下面添加以下内容:username ALL=(ALL) ALL,其中username是你要授予管理员权限的用户名。
  • 保存并关闭sudoers文件。

9. journalctl 检查服务日志

9.1. 选项

  • -u <unit>: 显示具体服务当前的日志

10. 命令行配置socks5代理

1
2
export http_proxy="socks5://127.0.0.1:1080"
export https_proxy="socks5://127.0.0.1:1080"

三、c/c++编程

1. 获取系统信息

  • sysinfo结构体定义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// sysinfo.h
struct sysinfo {
__kernel_long_t uptime; /* Seconds since boot */
__kernel_ulong_t loads[3]; /* 1, 5, and 15 minute load averages */
__kernel_ulong_t totalram; /* Total usable main memory size */
__kernel_ulong_t freeram; /* Available memory size */
__kernel_ulong_t sharedram; /* Amount of shared memory */
__kernel_ulong_t bufferram; /* Memory used by buffers */
__kernel_ulong_t totalswap; /* Total swap space size */
__kernel_ulong_t freeswap; /* swap space still available */
__u16 procs; /* Number of current processes */
__u16 pad; /* Explicit padding for m68k */
__kernel_ulong_t totalhigh; /* Total high memory size */
__kernel_ulong_t freehigh; /* Available high memory size */
__u32 mem_unit; /* Memory unit size in bytes */
char _f[20-2*sizeof(__kernel_ulong_t)-sizeof(__u32)]; /* Padding: libc5 uses this.. */
};
  • 获取系统信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <sys/sysinfo.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>

int main() {
struct sysinfo info;
// 操作成功返回0,失败返回-1
if (sysinfo(&info)) {
printf("failed to get sysinfo, errno: %u, reason: %s\n", errno, strerror(errno));
return 1;
}
// do something
return 0;
}

2. 获取进程id

1
2
// unistd.h
__pid_t getpid (void) __THROW;

3. 获取系统时间

  • 一般获取系统时间有两个函数gettimeofdayclock_gettime
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// /usr/include/time.h
/* Get current value of clock CLOCK_ID and store it in TP. */
extern int clock_gettime (clockid_t __clock_id, struct timespec *__tp)
__THROW __nonnull((2));

// /usr/include/time.h
/* Get the current time of day, putting it into *TV.
If TZ is not null, *TZ must be a struct timezone, and both fields
will be set to zero.
Calling this function with a non-null TZ is obsolete;
use localtime etc. instead.
This function itself is semi-obsolete;
most callers should use time or clock_gettime instead. */
#ifndef __USE_TIME_BITS64
extern int gettimeofday (struct timeval *__restrict __tv,
void *__restrict __tz) __THROW __nonnull ((1));
#else
# ifdef __REDIRECT_NTH
extern int __REDIRECT_NTH (gettimeofday, (struct timeval *__restrict __tv,
void *__restrict __tz),
__gettimeofday64) __nonnull ((1));
# else
# define gettimeofday __gettimeofday64
# endif
#endif
  • clock_gettime有下面几种类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// /usr/include/bits/time.h
/* Identifier for system-wide realtime clock. */
# define CLOCK_REALTIME 0 // 从1970.01.01到现在的时间
/* Monotonic system-wide clock. */
# define CLOCK_MONOTONIC 1 // 系统启动到现在的时间
/* High-resolution timer from the CPU. */
# define CLOCK_PROCESS_CPUTIME_ID 2 // 进程所消耗的时间,sleep不再计时
/* Thread-specific CPU-time clock. */
# define CLOCK_THREAD_CPUTIME_ID 3 // 线程消耗时间,sleep不再计时
/* Monotonic system-wide clock, not adjusted for frequency scaling. */
# define CLOCK_MONOTONIC_RAW 4 // 硬件时间
/* Identifier for system-wide realtime clock, updated only on ticks. */
# define CLOCK_REALTIME_COARSE 5 // 不精确的realtime,速度更快精度更低
/* Monotonic system-wide clock, updated only on ticks. */
# define CLOCK_MONOTONIC_COARSE 6 // 不精确的MONOTONIC,速度更快精度更低
/* Monotonic system-wide clock that includes time spent in suspension. */
# define CLOCK_BOOTTIME 7
/* Like CLOCK_REALTIME but also wakes suspended system. */
# define CLOCK_REALTIME_ALARM 8
/* Like CLOCK_BOOTTIME but also wakes suspended system. */
# define CLOCK_BOOTTIME_ALARM 9
/* Like CLOCK_REALTIME but in International Atomic Time. */
# define CLOCK_TAI 11 // 原子钟的时间,与CLOCK_REALTIME类似,不可被更改,没有闰秒

4. errno

  • errno线程唯一,不用担心多线程问题
  • errno在头文件unistd.h
  • strerror()在头文件string.h

四、虚拟内存

1. 基础知识

  • 虚拟内存是每个进程有自己的虚拟地址空间,不同的进程之间的虚拟地址空间一样,但是对应的物理地址空间不一样
  • 32位下,每个进程拥有4G虚拟地址空间,其中1G为内核空间,3G为用户空间
  • 每个进程有一个页表,存放在进程的信息中,mmu处理每个进程的虚拟地址到物理地址映射时要读取不同进程的页表,通过页表寄存器指定页表地址

五、进程

1. 进程间通信

  • 进程间通信有管道、命名管道、信号、信号量、消息队列、共享内存、套接字

1.1. 管道

1) 特点

  • 数据只能向一个方向流动
  • 只能用于父子进程或兄弟进程
  • fifo的读出和写入
  • 缓冲区有限,本身存在于内存中,分配了一个page大小

2) 创建

  • 通过shell的|创建
  • 通过代码的创建
1
int pipe(int fd[2]);
  • 管道的创建需要在父进程,然后再fork出子进程使用,或给两个兄弟子进程使用

1.2. 命名管道

1) 特点

  • 需要提供一个文件路径,两个进程通过路径进行联系,所以可以没有亲缘关系的进程通信
  • 内部没有fifo,读写会阻塞
  • 其他和管道一致

2) 创建

  • shell通过mkfifo xxx创建管道,使用><进行读取写入
  • 通过代码创建,正常按照文件一样打开和读写即可
1
int mkfifo(const char *pathname, mode_t mode);

1.3. 信号

1) 特点

  • 进程不知道信号什么时候来,类似于中断
  • 信号通俗讲就是系统定义的信号,也就是kill可以发出的信号

2) 使用

  • 代码注册信号
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
* 函数名:BR_SignalRegister
* 功 能:BugReport信号注册函数
*/
static int BR_SignalRegister(int sig) {
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = (__sighandler_t)BR_SignalHandler;
act.sa_flags = 0;
(void)sigemptyset(&act.sa_mask);

while (sigaction(sig, &act, NULL) < 0) {
if (errno != EINTR) {
(void)fprintf(stderr, "[BugReport]sigaction %s failed: %s\n",
BR_signals[sig], strerror(errno));
return -1;
}
}

return 0;
}

1.4. 信号量

1) 特点

  • 主要用于进程间共享资源访问控制机制
  • 两种类型
    • 二值信号量:只能0和1
    • 计算信号量:非负值

2) 使用

  • 创建使用
1
int semget(key_t key, int num_sems, int sem_flags)
  • 操作函数
1
2
3
4
// 改变信号量
int semop(int sem_id, struct sembuf *sem_opa, size_t num_sem_ops);
// 控制信号量
int semctl(int sem_id, int sem_num, int command, ...);

1.5. 消息队列

1) 特点

  • 就是在命名管道上加了个fifo,避免阻塞
  • 可以通过消息类型有选择的接收数据

2) 使用

1
2
3
4
5
6
// 创建或获取已存在的消息队列
int msgget(key_t key, int msgflg);
// 发送
int msgsnd(int msqid, void *msgp, int msgsz, int msgflg);
// 接收
int msgrcv(int msgid, void *msgp, int msgsz, long msgtyp, int msgflg);

1.6. 共享内存

1
int shmget(key_t key, size_t size, int shmflg);

1.7. 套接字

六、nss: Name Service Switch

Name Service Switch(NSS)是一个在Linux和其他类Unix操作系统中使用的系统组件,它提供了一种机制来管理系统中各种名称服务的配置。名称服务包括用户帐户、组、主机名、网络协议、服务和其他系统信息。NSS允许系统管理员配置系统以使用不同的名称服务,例如本地文件、NIS、LDAP等。NSS还提供了一种机制来缓存名称服务数据,以提高系统性能。在Linux系统中,NSS通常由glibc库实现。

1. 配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
=> cat /etc/nsswitch.conf
# Name Service Switch configuration file.
# See nsswitch.conf(5) for details.

passwd: files systemd
group: files [SUCCESS=merge] systemd
shadow: files systemd
gshadow: files systemd

publickey: files

hosts: mymachines resolve [!UNAVAIL=return] files myhostname dns
networks: files

protocols: files
services: files
ethers: files
rpc: files

netgroup: files
  • 上面配置的files等对应一个个插件,对应命名libnss_xxx.so
  • 修改了之后,从glibc 2.33后,会自动重新加载此文件,之前的版本只在进程起来的时候加载一次

2. 插件位置

1
2
3
4
=> ls /usr/lib/libnss_*
/usr/lib/libnss_compat.so /usr/lib/libnss_db.so.2 /usr/lib/libnss_hesiod.so /usr/lib/libnss_libvirt.so.2 /usr/lib/libnss_resolve.so.2 /usr/lib/libnss_wins.so.2
/usr/lib/libnss_compat.so.2 /usr/lib/libnss_dns.so.2 /usr/lib/libnss_hesiod.so.2 /usr/lib/libnss_myhostname.so.2 /usr/lib/libnss_systemd.so.2
/usr/lib/libnss_db.so /usr/lib/libnss_files.so.2 /usr/lib/libnss_libvirt_guest.so.2 /usr/lib/libnss_mymachines.so.2 /usr/lib/libnss_winbind.so.2

3. 自定义插件

  • 可以自定义so库,满足此命名,然后放到系统库路径后,添加到配置文件中
  • 需要满足nss对应的库的符号要求

3.1. 自定义dns解析库

  • dns解析由hosts处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <stddef.h>
#include <nss.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <syslog.h>
#include <zconf.h>
#include <stdio.h>

enum nss_status _nss_hs_gethostbyname4_r(
const char *name,
struct gaih_addrtuple **pat,
char *buffer, size_t buflen,
int *errnop, int *h_errnop,
int32_t *ttlp) {

fprintf(stdout, "_nss_hs_gethostbyname4_r ns hook domain:%s pid:%d\n", name, getpid());

return NSS_STATUS_NOTFOUND;
}

enum nss_status _nss_hs_gethostbyname3_r(
const char *name,
int af,
struct hostent *host,
char *buffer, size_t buflen,
int *errnop, int *h_errnop,
int32_t *ttlp,
char **canonp) {

fprintf(stdout, "_nss_hs_gethostbyname3_r ns hook domain:%s pid:%d\n", name, getpid());

return NSS_STATUS_NOTFOUND;
}

enum nss_status _nss_hs_gethostbyname2_r(
const char *name,
int af,
struct hostent *host,
char *buffer, size_t buflen,
int *errnop, int *h_errnop) {

return _nss_hs_gethostbyname3_r(
name,
af,
host,
buffer, buflen,
errnop, h_errnop,
NULL,
NULL);
}

enum nss_status _nss_hs_gethostbyname_r(
const char *name,
struct hostent *host,
char *buffer, size_t buflen,
int *errnop, int *h_errnop) {

return _nss_hs_gethostbyname3_r(
name,
AF_UNSPEC,
host,
buffer, buflen,
errnop, h_errnop,
NULL,
NULL);
}

void _nss_hs_init(void (*cb)(size_t, struct traced_file*)) {
fprintf(stdout, "_nss_hs_init...");
}
  • 编译
1
gcc -shared -fPIC -o libnss_test.so.2 -Wl,-soname,libnss_test.so.2 test_nss.c
  • 放到/usr/lib下后,重启要使用gethostbyname的进程就好了

4. hosts dns解析服务

  • mymachines: 由systemd提供,应该是处理容器类型的dns解析
  • resolve: 由systemd提供,是systemd-resolved.service的处理服务
  • files: 由glibc提供,处理/etc/hosts
  • myhostname: 由systemd提供,处理localhost_gateway_outbound等域名使用,主要是查本地网卡的一些信息
  • dns: 由glibc提供,处理dns的网络请求使用

七、二进制文件格式

参考 ELF文件格式

1. 链接视图和执行视图

  • 链接视图是以节(section)为单位,用于在链接时使用,可以是静态库、编译过程文件、动态库等
  • 执行视图是以段(segment)为单位,是在执行时用到的视图。
  • 目标文件.o里的代码段.text 是section(汇编中.text同理),当多个可重定向文件最终要整合成一个可执行的文件的时候(链接过程),链接器把目标文件中相同的 section 整合成一个segment,在程序运行的时候,方便加载器的加载

2. elf文件

小技巧和踩坑记

1. 报错[xxxx] pcieport 0000:00:1c.5 xxxx刷屏,无法关机

  1. /etc/defaults/grub里面修改,在GRUB_CMDLINE_LINUX_DEFAULT=后面追加splash pci=nomsi

2. 报错perl: warning: Falling back to the standard locale ("C").

  • 由于系统设置的语言包,系统不识别,需要安装
1
2
# 这个可以解决不识别 zh_CN.UTF-8
sudo apt get install language-pack-zh-hans

3. 分辨率怎么调都不行,总是达不到1080

  • 可以考虑下是线的问题,被一根VGA线坑了一年的人真诚提醒

4. 中文乱码

  • 部分中文出现乱码很有可能时中文字体没有安装,一般安装wqy-microhei就可以解决

5. vmware在linux下偶现虚拟机卡死

6. 调整分区大小导致无法mount分区

  • 使用分区管理器调整大小的时候,如果连续调整同时生效,很有可能出现调整失败,原分区也无法mount的情况
  • 报错提示超级块里面的大小和分区表的大小不一致

解决

  • 使用parted命令处理分区,使用resizepart将分区大小调整到原来的大小,和报错里面的一致就基本可以了

7. 查看机器内存情况

  • 下面命令查看几个插槽插了几个内存条
  • 可以看到四个插槽,插了两个DDR4的16G内存,速度3200 MT/s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
=> sudo dmidecode | grep -A16 "Memory Device$"
Memory Device
Array Handle: 0x003B
Error Information Handle: Not Provided
Total Width: Unknown
Data Width: Unknown
Size: No Module Installed
Form Factor: Unknown
Set: None
Locator: Controller0-ChannelB-DIMM0
Bank Locator: BANK 1
Type: Unknown
Type Detail: None
--
Memory Device
Array Handle: 0x003B
Error Information Handle: Not Provided
Total Width: 64 bits
Data Width: 64 bits
Size: 16 GB
Form Factor: DIMM
Set: None
Locator: Controller0-ChannelA-DIMM1
Bank Locator: BANK 0
Type: DDR4
Type Detail: Synchronous
Speed: 3200 MT/s
--
Memory Device
Array Handle: 0x003B
Error Information Handle: Not Provided
Total Width: Unknown
Data Width: Unknown
Size: No Module Installed
Form Factor: Unknown
Set: None
Locator: Controller0-ChannelB-DIMM0
Bank Locator: BANK 1
Type: Unknown
Type Detail: None
--
Memory Device
Array Handle: 0x003B
Error Information Handle: Not Provided
Total Width: 64 bits
Data Width: 64 bits
Size: 16 GB
Form Factor: DIMM
Set: None
Locator: Controller0-ChannelB-DIMM1
Bank Locator: BANK 1
Type: DDR4
Type Detail: Synchronous
Speed: 3200 MT/s