简介:这是一份面向Linux零基础初学者的系统性入门教程,聚焦操作系统核心概念与终端实操能力培养,帮助读者快速建立对Linux的认知框架并掌握日常运维必备技能。资源为单文件PDF文档(915KB),内容结构完整、讲解精炼,涵盖Linux与GNU关系辨析、四种安装方式对比、常用命令(mkdir/cd/ls等)详解、标准目录结构(/home、/etc、/bin等)功能说明、inode与硬/软链接原理、磁盘挂载机制、用户组与chmod/chown权限管理、bash/shell基础、grep/find/tee等文本处理工具、makefile构建逻辑,以及ssh、samba、gcc等关键服务与开发工具。内容预览显示其从Unix家族演化史切入,深入浅出梳理Linux诞生背景与技术脉络,兼具理论深度与实践导向。目前已有4413人学习下载,是适合自学、备课或教学参考的精品基础总结材料。
1. Linux 不是“操作系统”——它只是个内核,而你每天敲的ls其实来自 GNU
你刚在终端里输入ls -l /home,回车,一串带颜色的文件列表刷出来。你可能觉得:“这不就是 Linux 吗?”
但真相是:这个ls命令根本不是 Linux 写的,它来自 GNU 项目;你看到的整个命令行环境、bash、gcc、cp、mv、甚至man手册系统——全都不属于 Linux 内核本身。Linux 只是一个内核(kernel),一个负责调度 CPU、管理内存、驱动硬件、提供进程和文件系统抽象的“黑匣子”。它不自带命令,不画窗口,不解析.bashrc,也不认识root用户密码——这些全是外部拼装上去的。
为什么这个事实如此关键?因为它是理解所有“Linux 发行版差异”“为什么 Red Hat 和 Ubuntu 命令行为略有不同”“为什么有些系统没有systemd”“为什么嵌入式 Linux 能小到 2MB”的底层支点。这份《Linux 操作系统基础教程.pdf》之所以被称作“小白课里的精品总结”,正因为它从第一章就撕开了这个常见幻觉:它没教你“怎么装 Ubuntu”,而是带你回到 1991 年那个凌晨——Linus 在 MINIX 上敲出第一行fork()测试代码时,他手里只有内核骨架;真正让这个骨架站起来走路、说话、联网、编译程序的,是 GNU 工程十年间攒下的整套工具链。没有 GNU,Linux 只是一具无法交互的躯体;没有 Linux,GNU 的 Hurd 内核至今仍未成熟。它们的结合不是偶然,而是协议级绑定:GPL 许可证强制要求衍生作品也必须开源,这才让成千上万开发者敢把真实业务代码跑在上面——你今天能放心用docker run ubuntu,根源就在这里。搞懂这一点,你才真正跨过了“会用 Linux”和“理解 Linux 生态”的分水岭。
2. GNU + Linux = 可运行的操作系统:从许可证约束到二进制兼容的硬性耦合
2.1 GPL 如何用“传染性”倒逼生态统一:不是道德号召,而是链接时的编译期绑定
很多人把 GPL 理解为一种“开源精神宣言”,但它的真正力量藏在链接(linking)这一编译环节。我们来看一个具体场景:某公司开发了一个闭源监控代理monitor-agent,它需要调用libc中的gettimeofday()获取时间戳,同时又想调用 GNU Coreutils 提供的sha256sum计算文件哈希。如果它静态链接glibc和coreutils.a,根据 GPL v2 第6条,整个monitor-agent二进制必须以 GPL 发布——因为静态链接使目标码与 GPL 代码在最终可执行文件中不可分割。即使它改用动态链接,只要分发时附带了 GPL 库(如/lib/x86_64-linux-gnu/libc.so.6),FSF 仍主张其构成“聚合体”(aggregate),需提供对应库的源码(GPL v2 §3)。这不是法律恐吓,而是 ELF 文件格式层面的现实:readelf -d monitor-agent | grep NEEDED会清晰列出它依赖的每个共享库名称,其中libc.so.6和libcoreutils.so(若存在)的许可证状态直接决定整个分发包的合规边界。
提示:Linux 发行版默认不提供
libcoreutils.so,因为 Coreutils 工具(ls,cp,rm)设计为独立可执行文件,而非动态库。但glibc是强制动态链接的——这意味着任何 C 程序,无论是否使用 GNU 工具,只要用gcc编译,就自动落入 GPL 的作用域。这是 GNU 工具链成为事实标准的技术锚点。
2.2ls的真实身世:从/usr/bin/ls到src/ls.c的完整溯源
翻开教程第三章提到的ls命令,它并非 Linux 内核的一部分,而是 GNU Coreutils 的核心组件。我们可以通过源码验证其血统:
# 在任意现代 Linux 发行版(如 Ubuntu 22.04)中执行: $ ls --version ls (GNU coreutils) 8.32 Copyright (C) 2020 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. $ which ls /usr/bin/ls $ readelf -d /usr/bin/ls | grep 'Shared library' 0x0000000000000001 (NEEDED) Shared library: [libc.so.6]这段输出揭示了三层事实:
- 作者归属:明确标注
GNU coreutils,版本 8.32,版权属于自由软件基金会; - 二进制依赖:它只依赖
libc.so.6(glibc),不依赖任何 Linux 内核模块或专有驱动; - 许可证落地:
--version输出直接嵌入 GPL v3+ 文本,这是 GPL 要求的“显著声明”。
再深入一层,查看其源码逻辑(GNU Coreutils 8.32src/ls.c关键片段):
// src/ls.c: 主循环处理命令行参数并调用 do_ls() int main (int argc, char **argv) { // ... 参数解析(-l, -a, -R 等)... if (optind == argc) { // 默认列出当前目录 argv = (char **) &cwd; argc = 1; } // 核心:对每个参数调用 do_ls(),该函数封装了 stat(), readdir() 等系统调用 for (int i = optind; i < argc; i++) do_ls (argv[i]); return exit_status; } // do_ls() 内部实际调用的是内核提供的系统调用 // 但 ls 本身不实现 stat() 或 opendir(),它通过 libc 封装调用这里的关键洞察是:ls代码里没有文件系统遍历算法,没有 inode 解析逻辑,没有权限位计算——它只是libc的客户端。libc提供readdir()、stat()、lstat()等 POSIX 接口,而libc自己则通过syscall(__NR_getdents64)、syscall(__NR_statx)等方式陷入内核。ls的“颜色显示”“长格式时间解析”“符号链接处理”,全部在用户态完成,与内核无关。这解释了为什么同一份ls二进制可以在不同内核版本(2.6.x / 4.19 / 6.1)上无缝运行:它只依赖稳定的 syscall ABI,而非内核内部数据结构。
2.3 为什么“Linux 发行版”必须打包 GNU 工具?——ABI 兼容性比许可证更致命
假设某厂商想打造“纯 Linux”发行版,只包含 Linus 发布的linux-x.y.z.tar.xz内核源码 + 自研 shell + 自研ls。它立刻会撞上三堵墙:
- ABI 断裂:内核只提供
open(),read(),write()等原始 syscall,但应用程序需要fopen(),fgets(),printf()—— 这些由glibc实现。自研 libc 必须完全重写stdio、malloc、pthread,且保证与内核 syscall 行为 100% 一致(例如epoll_wait()超时精度、mmap()大页对齐规则)。历史上只有少数项目(如 musl libc)做到,但 musl 本身也是 GNU 生态的衍生品; - 工具链缺失:没有
gcc,无法编译任何 C 程序;没有binutils(ld,as,objdump),连汇编都写不了;没有make,连内核自己都编译不过(Linux Makefile 重度依赖 GNU Make 特性); - 生态拒绝:Docker Hub 上 99% 的镜像基于
debian:slim或alpine,它们预装的是 GNU Coreutils 或 busybox(后者刻意兼容 GNU 语义)。你的“纯 Linux”系统跑不了apt update,因为apt是 Python 写的,依赖glibc和python3(而python3又依赖glibc)。
因此,“GNU/Linux”不是命名偏好,而是技术必然性。这份教程在第一章就强调“Linux 93 年加入 GNU,奉行 GPL 版权”,正是点明:许可证定义了协作边界,而 ABI 定义了技术下限——两者共同锁死了今日所有主流发行版的构成公式。
3. 引导装载器:Grub 如何在开机瞬间接管硬件控制权,绕过 BIOS/UEFI 的“安全护栏”
3.1 从加电到grub>提示符:BIOS/UEFI、MBR/GPT、Stage 1.5 的三级跳
当你按下电源键,CPU 复位后跳转到0xFFFF0(实模式),开始执行 BIOS/UEFI 固件代码。固件的任务是初始化硬件(内存、PCIe、USB),然后读取启动设备(硬盘/SSD)的引导扇区(Boot Sector)。这里就是 Grub 登场的第一现场:
传统 BIOS + MBR 模式:
BIOS 读取硬盘第 0 扇区(512 字节)的 MBR(Master Boot Record)。MBR 前 446 字节是启动代码,后 64 字节是分区表。Grub 的 Stage 1 就被烧录在这 446 字节里——它唯一能做的事是:加载硬盘上某个固定位置(通常是/boot/grub/stage1.5)的第二阶段代码。因为 MBR 太小,Stage 1 不认识文件系统,只能靠“扇区号”硬编码定位stage1.5。UEFI + GPT 模式:
UEFI 固件直接读取 EFI System Partition(ESP,通常是 FAT32 格式)中的\EFI\redhat\grubx64.efi。这个.efi文件是 PE/COFF 格式,可直接被 UEFI 加载执行,无需 MBR 那种扇区寻址。Grub 的 UEFI 版本(grubx64.efi)内置 FAT32 驱动,能直接按路径打开/boot/grub/grub.cfg。
注意:教程中提到 “Grub 支持大硬盘、支持开机画面、可在选择开机前动态改变参数”,这些能力全部源于 Stage 1.5 或 UEFI 版本具备文件系统驱动。传统 LILO 的 Stage 1 没有文件系统驱动,所以
lilo.conf修改后必须运行lilo命令重写 MBR——因为它要把内核路径(如/boot/vmlinuz-5.15.0)转换成物理扇区号硬编码进 MBR;而 Grub 可以在运行时解析 ext4/fat32,直接按文件名加载内核。
3.2grub.cfg的生成机制:grub-mkconfig如何从/etc/default/grub和/etc/grub.d/构建启动菜单
教程提到 “编辑/boot/grub/grub.conf可改变 grub 的默认值”,但现代 Grub(2.x)实际使用/boot/grub/grub.cfg,且禁止手动编辑——因为它是自动生成的。其构建流程如下:
# 1. 用户配置入口:/etc/default/grub(关键参数) GRUB_DEFAULT=0 # 默认启动第一个菜单项 GRUB_TIMEOUT=5 # 菜单停留5秒 GRUB_CMDLINE_LINUX="quiet splash" # 传给内核的参数 GRUB_DISABLE_RECOVERY="true" # 禁用恢复模式 # 2. 脚本模板:/etc/grub.d/ 目录下的可执行脚本 $ ls /etc/grub.d/ 00_header # 生成 grub 环境变量、加载模块 10_linux # 扫描 /boot/vmlinuz-* 生成 Linux 启动项 30_os-prober # 探测其他操作系统(Windows) 40_custom # 用户自定义启动项(空模板) # 3. 生成命令:grub-mkconfig 依次执行上述脚本,拼接输出到 /boot/grub/grub.cfg $ sudo grub-mkconfig -o /boot/grub/grub.cfg Generating grub configuration file ... Found linux image: /boot/vmlinuz-5.15.0-86-generic Found initrd image: /boot/initrd.img-5.15.0-86-generic Found Windows Boot Manager on /dev/sda1@/EFI/Microsoft/Boot/bootmgfw.efi donegrub.cfg的核心是menuentry块,例如:
menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-1234abcd' { recordfail load_video gfxmode $linux_gfx_mode insmod gzio insmod part_gpt # 加载 GPT 分区模块 insmod ext2 # 加载 ext2/3/4 文件系统模块 set root='hd0,gpt2' # 设定根分区(GPT 分区2) if [ x$feature_platform_search_hint = xy ]; then search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2 1234abcd-5678-90ef-1234-567890abcdef fi linux /boot/vmlinuz-5.15.0-86-generic root=UUID=1234abcd-5678-90ef-1234-567890abcdef ro quiet splash $vt_handoff initrd /boot/initrd.img-5.15.0-86-generic }这段配置揭示了 Grub 的真实能力:
- 动态分区识别:
insmod part_gpt和insmod ext2让 Grub 能在内存中挂载文件系统,无需 BIOS 硬编码; - UUID 定位:
search --fs-uuid通过文件系统 UUID 查找根分区,避免因磁盘顺序变化(如 USB 插拔)导致hd0,gpt2失效; - 内核参数透传:
linux行末尾的ro quiet splash会原样传给内核,ro表示以只读方式挂载根文件系统——这是防止文件系统损坏的关键保护。
3.3 避坑:Grub 启动失败的五大高频现象与根因诊断
现象 1:开机卡在grub rescue>提示符,无法输入任何命令
原因:Grub 的core.img(Stage 1.5)损坏或丢失,导致 Stage 1 加载失败。常见于dd误操作覆盖 MBR、Windows 重装破坏 ESP 分区、或grub-install未指定正确设备。
解决:用 Live CD 启动,执行sudo grub-install /dev/sda(注意是/dev/sda,不是/dev/sda1),再sudo update-grub。
现象 2:菜单显示正常,但选择 Ubuntu 后黑屏或报错error: no such device: xxx-xxxx
原因:grub.cfg中的search --fs-uuid指向的 UUID 与当前/boot分区实际 UUID 不符。可能因mkfs.ext4重建分区、rsync备份未保留 UUID、或 LVM 逻辑卷重命名导致。
解决:在grub rescue>下手动定位:
grub rescue> ls (hd0) (hd0,gpt1) (hd0,gpt2) grub rescue> ls (hd0,gpt2)/boot/ ./ ../ grub/ vmlinuz-5.15.0-86-generic ... grub rescue> set root=(hd0,gpt2) grub rescue> linux /boot/vmlinuz-5.15.0-86-generic root=UUID=... grub rescue> initrd /boot/initrd.img-5.15.0-86-generic grub rescue> boot启动成功后,在系统内运行sudo blkid确认新 UUID,再sudo update-grub。
现象 3:更新内核后,旧内核菜单项消失,新内核无法启动
原因:/etc/default/grub中GRUB_DISABLE_OS_PROBER=true或10_linux脚本未扫描到新内核。常见于/boot独立分区空间不足,导致apt install linux-image失败但未报错。
解决:检查/boot使用率df -h /boot,清理旧内核sudo apt autoremove --purge,再sudo update-grub。
现象 4:UEFI 模式下 Grub 启动 Windows 成功,但启动 Linux 报错error: unknown filesystem
原因:Grub 的ext2.mod模块未被grub-install正确嵌入grubx64.efi。UEFI 固件加载.efi文件时,若模块缺失,无法识别 ext4 分区。
解决:重新安装 Grub 并强制嵌入模块:
sudo grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ubuntu --recheck --force sudo update-grub现象 5:修改/etc/default/grub后update-grub无反应,菜单仍是旧配置
原因:/etc/grub.d/下的脚本(如10_linux)被 chmod 去掉可执行位,或grub-mkconfig被 alias 重定向到空命令。
解决:检查脚本权限ls -l /etc/grub.d/10_linux(应为-rwxr-xr-x),并确认which grub-mkconfig指向/usr/sbin/grub-mkconfig。
4. 文件系统视角:ls -l显示的权限位、inode、硬链接,如何映射到 ext4 磁盘布局
4.1ls -l第一列的 10 个字符:从符号表达到磁盘 inode 的比特位翻译
执行ls -l /etc/passwd,输出首列为-rw-r--r--。这 10 个字符不是字符串,而是对 inode 中i_mode字段的十六进制值(如0x81ed)的 ASCII 解码。我们来逐位拆解 ext4 inode 的i_mode结构:
| 位域 | 长度 | 含义 | 对应ls -l位置 |
|---|---|---|---|
S_IFMT | 4 bit | 文件类型掩码 | 第1位(-/d/l/c/b) |
S_ISUID | 1 bit | Set UID 位 | 第2位(s/S/-) |
S_ISGID | 1 bit | Set GID 位 | 第5位(s/S/-) |
S_ISVTX | 1 bit | Sticky 位 | 第8位(t/T/-) |
S_IRWXU | 3 bit | 用户读写执行 | 第2-4位(rwx) |
S_IRWXG | 3 bit | 组读写执行 | 第5-7位(rwx) |
S_IRWXO | 3 bit | 其他读写执行 | 第8-10位(rwx) |
以/etc/passwd为例,其i_mode = 0x81b6(十进制 33206):
0x8000→S_IFREG→ 普通文件 →ls显示-;0x01b6 & 0x01ff = 0x01b6→ 用户权限0600(rw-),组权限044(r--),其他权限044(r--)→ 拼成-rw-r--r--;S_ISUID/S_ISGID/S_ISVTX均为 0 → 无特殊位。
关键洞察:
chmod 644 /etc/passwd实际是向 inode 的i_mode字段写入0x81b6。这个值存储在磁盘的 inode 表(inode table)中,与文件内容所在的 data block 物理分离。这也是为什么ls -l能瞬时返回权限信息——它只读 inode,不读文件内容。
4.2 硬链接的本质:多个目录项(dirent)指向同一个 inode number
创建硬链接:ln /etc/passwd /tmp/passwd.hard。此时ls -li输出:
$ ls -li /etc/passwd /tmp/passwd.hard 1234567 -rw-r--r-- 2 root root 2912 Jan 1 10:00 /etc/passwd 1234567 -rw-r--r-- 2 root root 2912 Jan 1 10:00 /tmp/passwd.hard两行显示相同的 inode number(1234567)和 link count(2)。其磁盘布局如下:
ext4 文件系统结构: ├── Superblock(超级块):记录总 inode 数、空闲 inode 数等 ├── Group Descriptors(组描述符):每个块组的元数据 ├── Block Bitmap(块位图):标记哪些 data block 已用 ├── Inode Bitmap(inode 位图):标记哪些 inode 已用 ├── Inode Table(inode 表):第1234567号 inode 存储: │ ├── i_mode = 0x81b6 │ ├── i_uid = 0 (root) │ ├── i_size = 2912 │ ├── i_blocks = 8 │ └── i_block[0..14] = [data_block_123, data_block_456, ...] ← 文件内容所在块 └── Data Blocks(数据块):存储实际字节而目录/etc/和/tmp/各自的 data block 中,存有 dirent 结构:
// ext4 dirent 格式(简化) struct ext4_dir_entry_2 { __le32 inode; // 指向的 inode number(1234567) __le16 rec_len; // 该 dirent 占用字节数 __u8 name_len; // 文件名长度(8 for "passwd") __u8 file_type; // 文件类型(1=regular) char name[255]; // 文件名("passwd") };/etc/的 dirent 中inode=1234567,/tmp/的 dirent 中inode=1234567—— 它们共享同一个 inode,因此i_links_count为 2。删除/etc/passwd时,ext4 只是将/etc/目录中的该 dirent 标记为无效,并将i_links_count减 1;只要i_links_count > 0,inode 和 data block 就不会被回收。这就是硬链接“删除一个不影响另一个”的底层原理。
4.3 符号链接的另类实现:一个 60 字节的“快捷方式”文件
ln -s /etc/passwd /tmp/passwd.soft创建符号链接。ls -li显示:
$ ls -li /tmp/passwd.soft 7890123 lrwxrwxrwx 1 root root 12 Jan 1 10:05 /tmp/passwd.soft -> /etc/passwdinode number(7890123)与/etc/passwd不同,且 link count 为 1。其 inode 的i_block[0]不指向 data block,而是直接存储字符串/etc/passwd(长度 ≤ 60 字节)。ext4 称之为 “fast symlink” —— 符号链接的目标路径就存在 inode 本身,无需额外 data block。readlink /tmp/passwd.soft系统调用直接从 inode 读出该字符串,然后由 VFS 层递归解析/etc/passwd。
避坑提示:当符号链接目标路径超过 60 字节,ext4 会分配一个 data block 存储路径,并在 inode 中标记
EXT4_INODE_EXTENTS。此时ls -l仍显示-> target,但stat会显示Blocks: 8(一个 block)。这种情况下,rm /tmp/passwd.soft需要释放 data block,性能略低于 fast symlink。
5. 权限模型的双重枷锁:DAC(自主访问控制)与 capabilities(能力分解)如何协同防御
5.1chmod/chown仅控制 DAC,而ping能发包是因为 capabilities,不是 setuid
教程第三章教chmod 4755 /usr/bin/ping,说这是“设置 SUID 位,让普通用户能以 root 身份运行”。但这是过时的解释。现代 Linux(内核 2.2+)已用capabilities替代大部分 SUID。验证:
$ ls -l /usr/bin/ping -rwxr-xr-x 1 root root 64424 Mar 1 10:00 /usr/bin/ping $ getcap /usr/bin/ping /usr/bin/ping = cap_net_raw+ep $ ping -c1 127.0.0.1 # 普通用户可执行cap_net_raw+ep表示该二进制被授予CAP_NET_RAW能力(+ep= effective + permitted)。CAP_NET_RAW允许进程绕过内核的SOCK_RAW权限检查,直接构造 IP 包。而传统 SUID 方案会让ping以 root 身份运行,拥有全部 38 个 capabilities,存在巨大攻击面(如execve("/bin/sh")可获得 root shell)。
capabilities的本质是将 root 的上帝权限拆解为 38 个原子能力(cap_chown,cap_dac_override,cap_net_admin等),通过libcap库在 exec 时注入。ping只需cap_net_raw,chown命令只需cap_chown,netstat只需cap_net_admin。这种细粒度授权大幅缩小了提权漏洞的影响范围。
5.2ls -l显示的s和t:SUID/SGID/Sticky 位在 inode 中的存储与触发时机
回顾ls -l权限字符串:-rwsr-xr-x(SUID)、-rwxr-sr-x(SGID)、drwxrwxrwt(Sticky)。它们对应 inodei_mode的三个比特位:
| 位 | 名称 | 触发条件 | 典型用途 |
|---|---|---|---|
0x800 | S_ISUID | 执行普通文件时,进程 euid 设为文件所有者 uid | 旧版ping、sudo |
0x400 | S_ISGID | 执行普通文件时,进程 egid 设为文件所有者 gid;创建目录时,新文件继承父目录 gid | 共享目录(如/var/mail) |
0x200 | S_ISVTX | 对目录设置时,仅文件所有者/目录所有者/root 可删除该目录下的文件 | /tmp目录防删他人文件 |
关键机制:这些位只在execve()系统调用时生效,且受securebits限制。例如,若进程已设置SECBIT_NO_SETUID_FIXUP,则S_ISUID不会改变 euid。ls -l显示的s(小写)表示该位已设且对应权限位(x)也置位;S(大写)表示该位已设但x未置位(如chmod 4644 file→-rwSr--r--),此时 SUID 无效。
5.3 避坑:权限失效的四大隐形陷阱
陷阱 1:挂载选项nosuid/noexec/nodev覆盖文件权限
现象:chmod 4755 /mnt/usb/myapp,但在/mnt/usb上执行./myapp报错Permission denied。
原因:/mnt/usb是用mount -o nosuid,noexec /dev/sdb1 /mnt/usb挂载的。nosuid忽略所有 SUID/SGID 位,noexec禁止执行任何二进制。
解决:重新挂载mount -o remount,suid,exec /mnt/usb,或改用mount -o bind,defaults /path/to/app /mnt/usb/app。
陷阱 2:SELinux/AppArmor 强制策略拦截合法权限
现象:ls -l显示-rwxr-xr-x,id显示用户在wheel组,但sudo systemctl restart nginx报错Operation not permitted。
原因:SELinux 策略httpd_can_network_connect未启用,或 AppArmor profile/usr/bin/nginx未授权network inet stream。
解决:sudo ausearch -m avc -ts recent | audit2why(SELinux)或sudo aa-status(AppArmor)排查。
陷阱 3:umask在进程创建时覆盖默认权限
现象:touch newfile创建的文件权限是-rw-r-----,而非预期的-rw-rw-r--。
原因:当前 shell 的umask是002(umask -S显示u=rwx,g=rx,o=rx),touch调用open("newfile", O_CREAT, 0666),内核计算0666 & ~0002 = 0664→-rw-rw-r--;但若umask是007,则得0660→-rw-rw----。
解决:umask 002临时修改,或在~/.bashrc中设置umask 002。
陷阱 4:NFS 挂载的root_squash导致 root 权限降级
现象:NFS 服务器上/export/data的 owner 是root:root,客户端 root 用户cp /etc/passwd /export/data/后,ls -l显示nobody:nogroup。
原因:NFS 服务端配置了root_squash(默认开启),将客户端 root 的 uid/gid 映射为nobody。
解决:服务端/etc/exports改为no_root_squash(不推荐),或客户端用sudo -u nobody cp模拟。
6. 从init 0到systemd:关机流程如何从信号广播演变为事务化服务依赖图
6.1 教程中的init 0是 System V init 的遗存,现代系统已由systemd接管
教程第三章教init 0关机、init 6重启,这是 System V init 的运行级别(runlevel)机制。但自 2010 年起,主流发行版(RHEL 7+, Ubuntu 15.04+, Debian 8+)已切换至systemd。init 0在 systemd 系统中只是systemctl poweroff的别名,其背后是完全不同的事务模型。
Systemd 的关机流程不是“广播 SIGTERM 给所有进程”,而是:
- 构建停止序列:
systemctl list-dependencies --reverse poweroff.target显示所有依赖poweroff.target的单元(unit); - 拓扑排序:按服务依赖关系(
After=/Before=)和类型(.service>.socket>.mount)排序; - 事务执行:对每个单元执行
stop,若失败则回滚(rollback); - **内核
本文还有配套的精品资源,点击获取