二维码

权限应用、程序之观察与基本管理

986 人阅读 | 时间:2021年12月17日 23:26

5.1:权限在目录与档案应用上的意义

从前一小节我们知道了 Linux 的文件权限设置上有三种身份,每种身份则有三种权限 (rwx)。 不过档案系统里面的档案类型很多,基本上就有一般档案与目录文件, 这两种档案类型的权限意义并不相同。

5.1.1:目录文件与一般文件的权限意义

基本上,目录与档案的'内容物'有点不太一样,这也就造成权限对目录及档案产生不同的影响作用。

  • 权限对档案的重要性

文件是实际含有数据的地方,包括一般文字文件、数据库内容文件、二进制可执行文件(binary program)等等。 因此,权限对于档案来说,他的意义是这样的:

  • r (Read):可读取此一档案的实际内容,如读取文字文件的文字内容等;

  • w (Write):可以编辑、新增或者是修改该档案的内容(但不含删除该文件);

  • x (eXecute):该文件具有可以被系统执行的权限。

可读( r) 代表可以读取文件实际的内容,可编辑( w) 的意思是可以写入/编辑/添加/修改文件的内容的权限, 但并不具备有删除该文件本身的权限

可执行(x)代表该文件具有可以被执行的权限,但该档案的代码能不能执行则是另一回事。 举例来说,一个单纯的文字档案, 内容为一封信件时,你也可以设定该档案拥有 x 的可执行权限,但该档案的内容其实不具备执行文件的功能。 因此当该档案被执行时,就会出现程序错误的情况。

对于档案的rwx来说, 主要都是针对'档案的内容'而言,与档案文件名的存在与否没有关系。

  • 权限对目录的重要性

档案是存放实际数据的所在,而目录主要的内容在记录文件名列表,文件名与目录有强烈的关连。 如果是针对目录时,rwx 的意义如下:

  • r (read contents in directory):
    表示具有读取目录结构列表的权限,所以当用户具有读取(r)一个目录的权限时,表示该用户可以查询该目录下的文件名资料。

  • w (modify contents of directory):
    当用户具有目录的 w 权限时,表示用户具有异动该目录结构清单的权限,也就是底下这些权限:

    • 建立新的档案与目录;

    • 删除已经存在的文件与目录(不论该档案的权限为何! )

    • 将已存在的档案或目录进行更名;

    • 搬移该目录内的档案、目录位置。

  • x (access directory):
    目录的x代表的是使用者能否进入该目录成为工作目录的用途!

若以较人性化的角度来思考,让档案变成文件夹、目录变成抽屉,则 rwx 的功能汇整如下表:

组件内容思考对象rwx
档案详细资料data文件文件夹读到文件内容修改文件内容执行文件内容
目录档名可分类抽屉读到档名修改文件名进入该目录的权限(key)

读者须注意,目录的 rw 与'文件名'有关,而档案的 rw 则与'档案的内容,包括代码与资料等'有关。 比较特别的是目录的 x, 该权限代表用户能否打开抽屉取得该抽屉内的文件名资料。

实际练习:关于权限在'目录'上的相关性
  1. 前提情境:有个目录的权限如下所示: 系统有个账号名称为vbird,这个账号并没有支持root群组。 现在:请问vbird对这个目录有何权限? 是否可切换到此目录中成为 vbird 的工作目录?

    drwxr--r--  3  root  root  4096   Jun 25 08:35   .ssh
  2. 因为 vbird 并非 root ,同时没有加入 root 的群组,因此对这个目录档案来说, vbird 仅具有 r 的权限。 根据上面的表格说明,目录重点在记载'文件名',因此 vbird 的权限会有点像这样:

    • 因为有 r 的权限: vbird 可以查询此目录下的文件名列表 (可以 ls -l .ssh)

    • 因为无 x 的权限: vbird 不具 x 权限,所以不能切换到此目录成为工作目录 (亦即 vbird 没有这个抽屉的钥匙)

    • 因为无 w 的权限: vbird 不能修改此目录下的任何资料 (因为连 x 都没有,所以 vbird 不能进入此目录,因此有没有 w 對 vbird 來說都一樣! 无法进行任何事情。 )

有经验的同学就会发现,虽然对目录有 r 的权限,但是其他权限都没有的话,当你使用' ls -l somedir '时,就会发现到该目录底下的文件名信息中, 某些权限属性是看不到的! 试想,如果你打开电灯,看到'被锁上的玻璃柜',你可以看到内部的所有资料,但是你没办法拿出来 (没钥匙), 所以,就无法查看玻璃柜内部物品的详细说明 (例如,制造日期写在物品的底部,结果你看不到底部啊! )

事实上,你可以使用上述的概念用在目录与档案的解析上,这样对于 r, w, x 在目录或文件上面的关系, 会更容易了解的!
实际练习:思考权限在目录及档案上面的应用
  1. 前提假设:有两个目录与档案的权限如下所示: 现在:请问 student 能不能删除 the_root_data 文件?

    drwx------ 5 student student 4096 Jul 04 11:16  /home/student/
    -rwx------ 1 root    root     128 Jul 04 11:18  /home/student/the_root_data
  2. 档案:针对 the_root_data 而言,student 因为不是 root 也假设没有加入 root 的群组,因此 student 不具备任何权限。 因此对档案来说, student 不能查看内容、不能变更内容、不能更改档案的权限、也不能执行该档案。

  3. 目录:但是针对 the_root_data 所在的目录,亦即是 /home/student/ 这个目录来思考,student 则具备所有权限, 亦即对 /home/student/ 这个目录而言, student 具有查阅文件名列表、修改建立或删除文件名、进入目录成为工作目录等等的权限。 就因为具备文件名的修订权,所以 student 『可以删除掉该档案』。

  4. 思考:叠代的方式来思考一下,有一个密封的文件夹 (the_root_data) ,放在你的私人抽屉内 (/home/student/), 你应该可以'打开抽屉、拿出这个文件夹、打不开也看不到这个文件夹,但是可以将这个文件夹丢到垃圾桶去'! 这就是目录(抽屉)的 rwx 功能。

5.1.2:用户操作功能

根据上述的权限意义,假如用户想在『/dir1/file1』这个档案与『/dir2』这个目录之间进行如下的动作时,用户应该具有哪些『最小权限』才能运作?

操作动作/dir1/dir1/file1/dir2重点
读取 file1 内容


要能够进入 /dir1 才能读到里面的文件资料!
修改 file1 内容


能够进入 /dir1 且修改 file1 才行!
执行 file1 内容


能够进入 /dir1 且 file1 能运作才行!
删除 file1 文件


能够进入 /dir1 具有目录修改的权限即可!
将 file1 复制到 /dir2


要能够读 file1 且能够修改 /dir2 内的数据
将 file1 移动到 /dir2


两个目录均需要被更改

请先思考上述表格内容的权限意义之后,再进行底下的例题:

例题 5.1.2-1:测试不同权限下的系统操作结果
  1. 请使用 root 的身份创建下面的文件和权限 :

    drwxrwxr-x  root root /dev/shm/unit05/
    drwxr-xr--  root root /dev/shm/unit05/dir1/
    -rw-r--r--  root root /dev/shm/unit05/dir1/file1 (複製來自 /etc/hosts)
    drwxr-x--x  root root /dev/shm/unit05/dir2/
    -rw-r--r--  root root /dev/shm/unit05/dir2/file2 (複製來自 /etc/hosts)
    drwxr-xr-x  root root /dev/shm/unit05/dir3/
    -rw-rw-rw-  root root /dev/shm/unit05/dir3/file3 (複製來自 /etc/hosts)
    drwxrwxrwx  root root /dev/shm/unit05/dir4/
    -rw-------  root root /dev/shm/unit05/dir4/file4 (複製來自 /etc/hosts)
  2. 底下请使用 student 的身份进行各个工作:

    1. 请使用 ls -l /dev/shm/unit05/dir[1-4] 依据输出的结果说明为何会产生这些问题?

    2. 请使用 ls -l /dev/shm/unit05/dir1/file1 ,依序将上述的文件名由 dir1/file1 ~ dir4/file4 执行,依据产生的结果说明为何会如此?

    3. 请使用 vim /dev/shm/unit05/dir1/file1 ~ vim /dev/shm/unit05/dir4/file4,尝试储存 (或强制储存),说明为何可以/不可以储存?

5.2:程序管理初探

在 Linux 系统运作中,所有在系统上面运作的都是通过触发程序成为内存中的程序后,才能够顺利的操作系统。 程序的观察与管理是相当重要的, 所以读者应该先认识程序后,才能够进一步管理。

5.2.1:什么是程式 (program) 与程序 (process)

在一般的理解中,程序与程序的关系是这样的:

  • 程序(program):通常为 binary program ,放置在存储媒体中 (如硬盘、光盘、软盘、磁带等), 为实体档案的型态存在;

  • 程序(process):程序被触发后,执行者的权限与属性、程序的代码与所需资料等都会被加载内存中,操作系统并给予这个内存内的单元一个识别码(PID),可以说,程序就是一个正在运作中的程序。

程序的触发流程与在内存当中的管理,简单的图标为:

权限应用、程序之观察与基本管理
图5.2-1、程序被加载成为程序以及相关资料的示意图

上图比较需要注意的是,同一只程序有时候会被多个用户执行触发,因此系统当中可能会有多个代码相同的'程序'存在! 那系统如何了解到底是哪只程序在运作? 此时就需要知道 PID (Process ID) 了。 PID 是系统处理内存内程序的最重要的参考依据。 如下图 5.2-2 所示,不同的用户登入都是执行 /bin/bash 这个 shell,读者也应该知道系统管理需要管理员身份的 bash 才能够运作, 一般帐号的 bash 能做的事情相对较少。 但其实两者都是执行 bash 的。

权限应用、程序之观察与基本管理
图5.2-2、不同执行者执行同一个程序产生的不同权限 PID 示意图
  • 父程序与子程序

程序是有相依性的! 举例来说,你想要执行 office 软件时,因为 office 软件是依附在图形界面上,因此你一定要启动 X server 这个图形界面服务器后, 才有办法顺利运作 office 的。 此时你可以说, X server 是父程序,而 office 就是子程序了。

此外,读者也尝试使用过su来切换身份成为root,此时su会给予一个具有root权限的bash环境,那么用户登录的bash就被称为父程序,由su-取得后的bash就是子程序,如下图来观察:

权限应用、程序之观察与基本管理
图5.2-3、父程序与子程序的相关性

5.2.2:观察程序的工具指令

程序的观察大多使用 ps, pstree, top 等指令,不过最好根据观察的对象来学习! 底下列出几个常见的观察对象与所使用的指令对应。

  • ps -l :仅观察 bash 自己相关的程序

如果用户仅想知道目前的 bash 界面相关的程序,可以使用简易的 ps -l 即可! 输出界面示意:

[student@localhost ~]$ ps -lF S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD0 S  1000 14132 14125  0  80   0 -  6860 -      pts/0    00:00:00 bash
0 R  1000 14182 14132  0  80   0 - 11191 -      pts/0    00:00:00 ps

每个项目的意义简单说明如下:

  • F (flag):代表程序的总结旗标,常见为 4 代表 root 特权程序、0 应为一般程序、1 为复制 (forked) 但未执行 (exec) 的程序。

  • S (stat):状态栏,主要的分类项目有:

    • R :(running/runnable/run queue) 正在执行或可执行的程序,或者在可执行列中的程序

    • S :(interruptible sleep) 该程序目前正在睡眠状态,但可以被其他事件唤醒来运作程序

    • D :(uninterruptible sleep) 不可被唤醒的睡眠状态,通常这支程序可能在等待 I/O 的情况(ex>打印)

    • T :(stop by job control),可能是在工作控制(背景暂停)状态;

    • t :(stop by debugger),可能是在除错 (traced) 状态;

    • Z :(Zombie) 僵尸状态,程序已经终止但却无法被移除至内存外。

  • UID/PID/PPID:代表『此程序被该 UID 所拥有/程序的 PID 号码/此程序的父程序 PID 号码』

  • C:代表 CPU 使用率,单位为百分比;

  • PRI/NI:Priority/Nice 的缩写,代表此程序被 CPU 所执行的优先级,数值越小代表该程序越快被 CPU 执行。 不过,不同的输出格式其计算方法不同,因此,读者大概只要知道 NI (nice) 值即可。

  • ADDR/SZ/WCHAN:都与内存有关,ADDR 是 kernel function,指出该程序在内存的哪个部分,如果是个 running 的程序,一般就会显示' - 』 / SZ 代表此程序用掉多少内存(Kbytes) / WCHAN 表示目前程序是否运作中,同样的, 若为 - 表示正在运作中。

  • TTY:登入者的终端位置,若为远程登录则使用动态终端接口 (pts/n);

  • TIME:使用掉的CPU时间,注意,是此程序实际花费CPU运作的时间,而不是系统时间;

  • CMD:就是 command 的缩写,造成此程序的触发程序之指令为何。

上述的PPID即是父程序之意,因此 ps 的 PID 是 14182 而 PPID 是 14132,至于 14132 这个 PID 的主人就是 bash 。 而因为 bash 大部分在提供用户一个输入的界面,因此并没有在运行 (run),故大部分的时间其实是在等待用户输入指令, 因此上面读者应该可以发现到 bash 的 S (state) 状态为 S (sleep) 。

  • 使用 pstree 与 ps aux 观察全系统的程序

观察全系统程序的方式主要有两种,一种是程序关联树,亦即 pstree ,他相对简单很多。 为了显示的方便,建议读者可以下达 -A 的选项, 以 ASCII 的显示字符输出,比较不容易出现乱码:

[student@localhost ~]$ pstree -Asystemd-+-ModemManager---2*[{ModemManager}]
        |-NetworkManager---2*[{NetworkManager}].......(中間省略)......
        |-systemd-+-(sd-pam)
        |         |-at-spi-bus-laun-+-dbus-daemon---{dbus-daemon}.......(中間省略)......
        |         |-gnome-shell-cal---5*[{gnome-shell-cal}]
        |         |-gnome-terminal--+-bash---pstree
        |         |                 `-3*[{gnome-terminal-}].......(底下省略)......

读者可以看到用户通过图形界面的 gnome-terminal 来取得 bash,然后再以 bash 来启动 pstree 的情况。 若需要加上 PID (p) 与用户资料 (u), 可以直接使用 -up 来加入即可。

[student@localhost ~]$ pstree -Aupsystemd(1)-+-ModemManager(973)-+-{ModemManager}(991)
           |                   `-{ModemManager}(998)
           |-NetworkManager(1104)-+-{NetworkManager}(1111)
           |                      `-{NetworkManager}(1113).......(中間省略)......
           |-systemd(14104,student)-+-(sd-pam)(14117)
           |                        |-at-spi-bus-laun(14804)-+-dbus-daemon(14809)---{dbus-daemon}(14810).......(中間省略)......
           |                        |-gnome-shell-cal(14924)-+-{gnome-shell-cal}(14926)
           |                        |                        |-{gnome-shell-cal}(14928)
           |                        |                        |-{gnome-shell-cal}(14944)
           |                        |                        |-{gnome-shell-cal}(14945)
           |                        |                        `-{gnome-shell-cal}(15103)
           |                        |-gnome-terminal-(15372)-+-bash(15381)---pstree(15673)
           |                        |                        |-{gnome-terminal-}(15373)
           |                        |                        |-{gnome-terminal-}(15374)
           |                        |                        `-{gnome-terminal-}(15375).......(底下省略)......

如上所示,每个程序后面多出来的括号内的数值,就是该程序的 PID。 另外需要注意的是,当父程序、子程序的所有者不同时, 在程序名称后面才会加上用户的信息,否则会省略用户的名称。 而因为同一只程序会产生多个程序,因此每个程序就会有独立的 PID,这也需要特别注意。

除了较简易的 pstree 之外,读者最好也能够记忆 ps aux 这一个指令的用途,这个指令可以将系统中的程序呼叫出来,且输出的信息较为丰富。 显示的信息有点像这样:

[student@localhost ~]$ ps auxUSER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.5 244840 10084 ?        Ss    3月16   0:04 /usr/lib/systemd/systemd --switched-root -
root         2  0.0  0.0      0     0 ?        S     3月16   0:00 [kthreadd]
root         3  0.0  0.0      0     0 ?        I<    3月16   0:00 [rcu_gp]
root         4  0.0  0.0      0     0 ?        I<    3月16   0:00 [rcu_par_gp].......(中間省略)......student  15372  0.1  2.5 823144 47796 ?        Ssl  14:44   0:00 /usr/libexec/gnome-terminal-server
student  15381  0.0  0.2  27548  5320 pts/1    Ss+  14:44   0:00 bash
student  15436  0.0  0.6 321332 12448 tty4     Sl   14:45   0:00 /usr/libexec/ibus-engine-libzhuyin --ibus.......(中間省略)......student  15747  0.0  0.2  57184  3952 pts/0    R+   14:52   0:00 ps aux

每一个项目代表的意义简易说明如下:

  • USER:该 process 属于那个用户帐号的?

  • PID :该 process 的程序识别码。

  • %CPU:该 process 使用掉的 CPU 资源百分比;

  • %MEM:该 process 所占用的物理内存百分比;

  • VSZ :该 process 使用掉的虚拟内存量 (Kbytes)

  • RSS :该 process 占用的固定的内存量 (Kbytes)

  • TTY :该 process 是在那个终端机上面运作,若与终端机无关则显示 ?,另外, tty1-tty6 是本机上面的登入者程序,若为 pts/0 等等的,则表示为由网络连接进主机的程序。

  • STAT:该过程目前的状态,状态显示与 ps -l 的 S 旗标相同 (R/S/T/Z)

  • START:该 process 被触发启动的时间;

  • TIME :该 process 实际使用 CPU 运行的时间。

  • COMMAND:该程序的实际指令为何?

  • top 动态观察程序

读者亦可以透过 top 这个指令来观察程序的动态资讯。 top 可以协助读者未来在管理程序的 CPU 使用量上面的一个很重要的工具。 直接输入 top 即可每 5 秒钟更新一次程序的现况,如下表所示:

[student@localhost ~]$ toptop - 15:12:55 up 6 days, 25 min,  3 users,  load average: 0.14, 0.04, 0.01
Tasks: 287 total,   1 running, 284 sleeping,   2 stopped,   0 zombie
%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni, 99.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :   1828.4 total,    207.4 free,   1129.2 used,    491.8 buff/cache
MiB Swap:   2048.0 total,   1999.5 free,     48.5 used.    519.0 avail Mem        <==這一行是指令列!  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND             14845 student   20   0 4388328 235688  84132 S   0.2  12.6   0:09.16 gnome-shell
14990 root      20   0  204224  30028   9072 S   0.2   1.6   0:02.59 sssd_kcm
15931 student   20   0   64020   4940   4040 R   0.2   0.3   0:00.04 top
15878 root      20   0       0      0      0 I   0.1   0.0   0:00.04 kworker/4:3-events_freezable_power_
    1 root      20   0  244840  10084   6268 S   0.0   0.5   0:04.70 systemd

离开 top 可以使用 q 来离开即可。 至于 top 每一行的意义说明如下:

top - 15:12:55 up 6 days, 25 min,  3 users,  load average: 0.14, 0.04, 0.01

代表目前时间为15:12:55,本系统开机了6天25分钟这么久的时间,目前有3为用户登入,工作负载为0.14,0.04及0.01。 那三个数据代表 1, 5, 15 分钟内的平均工作负载。 所谓的工作负载为'单一时间内,CPU 需要运作几个工作'之意,并非 CPU 使用率。 如果 CPU 数量有 8 核心,那么此数据低于 8 是可接受的 (每一个核心全力负责一个工作之意)。

Tasks: 287 total,   1 running, 284 sleeping,   2 stopped,   0 zombie

目前共有 287 个程序,其中 1 个在执行,284 个睡着了,2 个停止的,没有僵尸程序。

%Cpu(s):  0.0 us,  0.0 sy,  0.0 ni, 99.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st

这里才是 CPU 的使用率百分比,比较需要注意 id (idle) 与 wa (I/O wait),id 越高代表系统越闲置, wa 越高代表程序卡在读写磁盘或网络等 I/O 上,此时系统效能会比较糟糕。

MiB Mem :   1828.4 total,    207.4 free,   1129.2 used,    491.8 buff/cache
MiB Swap:   2048.0 total,   1999.5 free,     48.5 used.    519.0 avail Mem

分别代表物理内存(Mem)与内存置换(Swap)的总量,与使用量。 需要注意的是,上表中虽然free仅有207.4MiB,但是后续有491.8buff/cache(快取)的量,所谓的快取指的是Linux会将系统曾经取用的文件暂存在内存,以加速未来存取该档案的效能(内存的速度比磁盘快了10倍以上),当内存不足时,系统就会将快取回收,以保持系统的可用性。 右下角那个 avail Mem 指的大致就是 free + buff/cache 的量, 因此,目前可用的内存量还有 519MiBytes 这么多喔!

不同时期的系统在硬件、软件的配置上都有不同,CentOS 8 默认的输出数据为 MiB,而不是 CentOS 7 以前的 KiB 量! 因此,查阅时,要注意数据的单位才好!
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND

top 程序执行的状态栏,每个项目的意义为:

  • PID :每个 process 的标识符 (PID)

  • USER:该 process 所属的用户;

  • PR :P riority 的简写,程序的优先执行顺序,越小越早被执行;

  • NI :Nice 的简写,与 Priority 有关,也是越小越早被执行;

  • %CPU:CPU 的使用率;

  • %MEM:内存的使用率;

  • TIME+:CPU 使用时间的累加;

  • COMMAND:指令

在预设的情况下,top所显示的程序会以CPU的使用率来排序,这也是管理员最需要的一个观察任务。 许多时候系统发生资源不足或者是效能变差的时候, 最简易的方法为使用 top 观察最忙碌的几只程序,借以处理程序的效能问题。 此外,也能透过 top 观察 I/O wait 的 CPU 使用率, 可以找到 I/O 最频繁的几只程序,藉以了解到哪些程序在进行哪些行为,或者是系统效能的瓶颈,藉以作为未来升级硬件的依据。

例题 5.2.2-1:实际观察与搜寻程序相关信息,包括找出程序名称与 PID 等信息
  1. 过程搜索 :

    1. 透过各种方法,找到 PID 为 1 的那只程序的指令名称为何?

    2. 写出至少两种方法,找出名为 crond 的程序的 PID 号码。

  2. 程序相关性的判断:

    1. 使用 student 身份登录系统后,(1)使用su - 切换身份,再 (2)使用su - student,再(3)su - 切换成root,此时再以 ps -l 观察目前相关的程序情况

    2. 根据分析上述的程序相依性,你需要使用几次 exit 才能回到原本的 student 帐号?

  3. 查询 ps 命令的输出用法 :

    1. 由于管理员仅需要知道 PID, PRI, NI 及指令名称四个字段,请使用 man ps 找到 example 的范例,透过 ps 搭配适当的选项来列出这四个字段程序输出。

    2. 使用 man ps 找到 sort 排序的选项,然后以指令 (comm) 为排序的标准来排序输出 PID, PRI, NI 与指令。

  4. 使用 top

    1. 如何以 top 每两秒钟更新一次画面。

    2. 进入 top 的观察界面后,可以按下哪两个按键,在 CPU 排序与内存使用量排序间切换?

5.2.3:程序的优先序PRI与 NI

系统运作时,存储器内的程序量非常的大,但每个程序的重要性都不一样。 为了让系统比较快速的执行重要的程序,因此设计上增加了 Priority (PRI) 这个优先序的设置。 基本上,PRI 越低代表系统会执行较多次该程序,也就是该程序会比较早被执行完毕 (因为同一周期会被执行较多次)。 简单的运作示意图如下:

权限应用、程序之观察与基本管理
图5.2-4、具有优先级的程序列示意图

但是 PRI 是系统自行弹性规划的,用户并不能更改 PRI。 为此,Linux 提供一个名为 Nice (NI) 的数值来让用户'影响'程序的 PRI。 基本上, PRI 与 NI 的关系如下:

PRI(new) = PRI(old) + NI

所以读者可以知道 NI 越小会让 PRI 变小,则程序的优先序会往前挪,相反的,NI 越大会造成 PRI 越大,就让程序的优先序变落后了。 但是 NI 的使用是有限制的,基本限制如下:

  • nice 值可调整的范围为 -20 ~ 19 ;

  • root 可随意调整自己或他人程序的 Nice 值,且范围为 -20 ~ 19 ;

  • 一般用户仅可调整自己程序的 Nice 值,且范围仅为 0 ~ 19 (避免一般用户抢占系统资源);

  • 一般用户仅可将 nice 值越调越高,例如本来 nice 为 5 ,则未来仅能调整到大于 5;

要影响 NI 主要透过 nice 与 renice 来处理,也能够透过 top 来处理已经存在的程序的 NI。

  • 一开始执行程序就立即给予一个特定的 nice 值:用 nice 指令;

  • 调整某个已经存在的 PID 的 nice 值:用 renice 指令或 top 指令。

  • 不同软件的 PRI 输出情境

不同的软件在计算和输出 priority (PRI) 的方式并不一样,例如:

  • ps -l 的输出:PRI 默认值为 80,然后如果修改了 Nice 值之后,PRI 就会以 80 来累加

  • top 的输出:PRI 默认值为 20,修改 Nice 之后则 PRI 以 20 来累加

  • ps -eo pri 的输出:PRI 默认为 19 ,然后以 PRI(new) = PRI(old) - Ni 来修改,因此 Nice 值越低, 反而 PRI 会越高! 这与前两项输出情境并不相同。

实际练习:了解 PRI 在不同软件间的计算依据
  1. 先以 studnet 的身份,观察自己的 bash 程序的 PID, PRI 与 NI 数值 现在,再以 top -d2 -p 17663 来单独观察这个 bash 的相关信息: (每个人的 PID 都不会一样喔! ) 所以可以很明显的发现, ps -l 以及 top 的输出,对于 PRI 的基准值就不一样了! 现在,再来查看一下 ps -eo pid,ni 的结果: 所有的输出情境中,NI 的数值不会改变,但是 PRI 的数值都不一样! ps -eo 的输出结果,PRI 的基准数据则是 19 喔!

    [student@station10-101 ~]$ ps -lF S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
    0 S  1000 17663 17657  1  80   0 -  6860 -      pts/0    00:00:00 bash
    0 R  1000 17714 17663  0  80   0 - 11191 -      pts/0    00:00:00 ps
    [student@station10-101 ~]$ top -d2 -p 17663top - 17:58:01 up 6 days,  3:11,  3 users,  load average: 0.00, 0.00, 0.00
    Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
    %Cpu(s):  0.1 us,  0.0 sy,  0.0 ni, 99.9 id,  0.0 wa,  0.1 hi,  0.0 si,  0.0 st
    MiB Mem :   1828.4 total,    164.3 free,   1128.4 used,    535.7 buff/cache
    MiB Swap:   2048.0 total,   1999.7 free,     48.2 used.    519.4 avail Mem  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND  17663 student   20   0   27440   5476   3604 S   0.0   0.3   0:00.02 bash
    [student@station10-101 ~]$ ps -eo pid,pri,ni,comm | grep 1766317663  19   0 bash
  2. 再来,先尝试修改 NI 成为 -5 看看: 看起来并不成功! 因为一般用户只能调整为比 0 还大的 NI 值,亦即只能调降自己的优先序~

    [student@station10-101 ~]$ man reniceNAME
           renice - alter priority of running processes
    
    SYNOPSIS       renice [-n] priority [-g|-p|-u] identifier...# 所以語法是 renice -n NI -p PID 的情境![student@station10-101 ~]$ renice -n -5 -p 17663renice: failed to set priority for 17663 (process ID): 拒絕不符權限的操作
  3. 再将 NI 改为 10 看看:

    [student@station10-101 ~]$ renice -n 10 -p 1766317663 (process ID) old priority 0, new priority 10# 看起來修改成功了!所以來查閱一下![student@station10-101 ~]$ ps -lF S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
    0 S  1000 17663 17657  0  90  10 -  6860 -      pts/0    00:00:00 bash
    0 R  1000 17855 17663  0  90  10 - 11191 -      pts/0    00:00:00 ps# 果然從 80 ,經過 80+10 於是 PRI 得到 90 這樣的數據![student@station10-101 ~]$ top -d2 -p 17663top - 18:05:54 up 6 days,  3:18,  3 users,  load average: 0.00, 0.00, 0.00
    Tasks:   1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
    %Cpu(s):  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    MiB Mem :   1828.4 total,    163.2 free,   1129.3 used,    535.9 buff/cache
    MiB Swap:   2048.0 total,   1999.7 free,     48.2 used.    518.4 avail Mem  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND17663 student   30  10   27440   5484   3604 S   0.0   0.3   0:00.05 bash# top 的 PRI 則是從 20 增加到 30 了!亦即是 20+10 得到 30[student@station10-101 ~]$ ps -eo pid,pri,ni,comm | grep 1766317663   9  10 bash# 這個輸出比較可惡~他是從 19 - 10 來得到 9 這個數據的!
  4. 尝试再将 NI 改为 5 看看

    [student@station10-101 ~]$ renice -n 5 -p 17663renice: failed to set priority for 17663 (process ID): 拒絕不符權限的操作

也就是说,NI 值在各个软件之间的观察并无不同,但是 PRI 在各个软件之下就不一样了。 top 与 ps -l 的结果都发现, PRI 越低, 优先序越高。 但是 ps -eo 里面的输出,则是 PRI 越高,执行序越高! 完全是两码子事... 所以,主要是要记得 NI 即可! PRI 作为简易的参考之用即可。 另外,用户只能将 NI 越调越高~不能调降~即使调降后依旧是正值也不行!

例题 5.2.3-1:使用 nice, renice 与 top 等指令来設定、修改 Nice 數值 (請使用 root 的身份進行下列動作)
  1. 通过 ps 的处理来理解 NI 和 PRI 的查询和配置:

    1. 使用 ps 搭配适当的选项,输出 PID, PRI, NI 和 COMMAND 等字段

    2. 承上,找到 crond 这个程序的 PID 号码

    3. 承上,透过 renice 指令,将 crond 的 NI 改成 -15 ,并重新观察是否顺利更改了?

  2. 理解 Nice 值是会继承的

    1. 使用 nice 值搭配 NI 成為 10 來執行 su - student 這個指令

    2. 使用 ps -l 查询属于 student 这次执行的程序中,每一只程序的 NI 值,并讨论 NI 有没有继承?

  3. 应用 top 画面中的指令行为:

    1. 使用 top 搭配 -p PID (自行 man top 找到说明),其中 PID 使用 student 的 bash 来处理。

    2. 承上,在 top 画面中按下『 r 』,依据屏幕的显示说明逐一输入正确的资料,最后请确认 student 能否将 NI 更改为 0 以及 15 ?

5.2.4:bash 的工作管理

工作管理 (job control) 是用在 bash 环境下的,也就是说:'当用户登录系统取得 bash shell 之后,在单一终端机界面下同时进行多个工作的行为管理 '。 举例来说,用户在登入bash后,可以一边复制档案、一边进行资料搜寻、一边进行编译,还可以一边进行vim程序撰写之意。 不过要进行 job control 时,需要特别注意到几个限制:

  • 这些工作所触发的程序必须来自于你shell的子程序(只管理自己的bash);

  • 前景:你可以控制与下达指令的这个环境称为前景的工作 (foreground);

  • 背景:可以自行运作的工作,你无法使用 [ctrl]+c 终止他,可使用 bg/fg 呼叫该工作;

  • 背景中'执行'的程序不能等待 terminal/shell 的输入(input)

常见的工作管理使用的符号和组合按键如下:

  • command & :直接将 command 丢到背景中执行,若有输出,最好使用数据流重导向输出到其他文件

  • [ctrl]+z :将目前正在前景中的工作丢到背景中暂停

  • jobs [-l]:列出目前的工作信息

  • fg %n :将第 n 个在背景当中的工作移到前景来操作

  • bg %n :将第 n 个在背景当中的工作变成执行中

常见的系统操作也会用到这方面的技术! 看看底下的例题就知道了:

例题 5.2.4-1:应用 bash 的工作管理 (job contorl) 功能 (请使用 student 的身份执行底下的任务)
  1. 执行『 find / 』,然后快速的按下『 [ctrl]+z 』让该指令丢到背景中

  2. 使用 jobs -l 观察该背景的工作号码与 PID 号码

  3. 让该工作在背景中执行,此时你能否中断 (ctrl+c) 或暂停 (ctrl+z) 该工作? 为什么?

  4. 使用『 find / & 』指令,此时快速按下『 ctrl+z 』有没有作用? 为什么?

  5. 若使用『 find / &> /tmp/findroot.txt & 』,然后快速的按下 jobs -l ,能否观察到该工作是否在运作中?

  6. 输入' sleep 60s',让屏幕停止 60 秒。 在结束前按下' ctrl+z ',之后按下 jobs -l 观察 sleep 这个工作是否运作中?

  7. 让sleep工作在背景中开始执行,静待一段时间,在背景运作的sleep运作结束后,屏幕上会出现什么讯息?

  8. 输入 vim 之后,按下' ctrl + z '并查看 vim 的运作状态

  9. 让 vim 在背景中执行,观察 vim 能否更改状态成为执行? 说明为什么。

  10. 将 vim 挪到前景中,并将它正常的结束工作。

5.3:特殊权限 SUID/SGID/SBIT 的功能

某些权限主要是针对'运作当下所需要的权限'来设计的,这些权限无法以传统权限来归类,且与操作者的所需要的特权权限 (root 身份或额外群组) 有关。 这就是 SUID, SGID 与 SBIT 的设计。

5.3.1:SUID/SGID/SBIT 的观察与功能说明

一般用户可以通过 passwd 来修改自己的密码,只是需要输入原始的密码,且密码的变动需要严格的规范。

例题 5.3.1-1:用户自行修改密码的方式 (请用 student 身份处理底下的例题)
  1. 先尝试使用 passwd 修改自己的密码,假设要改成123456

  2. 先使用' openssl rand -base64 8 '这个指令来猜测一个较为严格的密码

  3. 直接输入' passwd '这个指令来修改 student 的密码,更改密码时,先输入原本的密码,再输入两次上一个指令提供的密码

  4. 使用' ls -l /etc/shadow '查看一下该档案是否有被更动到目前的日期与时间。

  5. 检查一下 /etc/shadow 的权限,student 是否有权限可以更动该档案?

  6. 最后请用 root 的身份将 student 的密码改回来

  • SUID 的功能与观察

如上例题,系统的密码纪录在 /etc/shadow 内,但是用户并没有权限可以更改,不过一般用户确实有自己修改密码的需求。 此时 Linux 使用一种称为 Set UID (SUID) 的技术来处理这方面的疑问。 系统设定一个SUID的权限标志到passwd执行挡上, 当用户执行passwd指令时,就能够通过SUID来切换执行权限。 SUID 的基本功能为:

  • SUID 权限仅对二进制程序(binary program)有效;

  • 执行者对于该程序需要具有 x 的可执行权限;

  • 本权限仅在执行该程序的过程中有效(run-time);

  • 执行者将具有该程序所有者(owner)的权限。

观察 /usr/bin/passwd 的权限资料,如下所示:

[student@localhost ~]$ ls -l /usr/bin/passwd-rwsr-xr-x. 1 root root 34928  5月 11  2019 /usr/bin/passwd

读者可发现用户权限的x 变成了 s,此即 SUID 的权限旗标。 由SUID的定义来看,passwd设定了SUID,且passwd的所有者为root这个人,因此只要任何人具有x的执行权,当用户执行passwd时,就会自动透过SUID转换身份成为owner,亦即变成了root的身份。 所以 student 执行 passwd 的过程中,身份会自动的变成 root。 简单的绘图如下说明:

--bash(student)--+..................+---bash(student)--->
                 |                  |
                 |--passwd(root)----|

亦即只有在执行 passwd 这个指令的过程中,student 身份暂时变成了 root 了! 等到 passwd 执行完毕后,就又回复到原本的 student 身份。 这就是 SUID 的功能了!

例题 5.3.1-2:观察用户执行 passwd 的程序变化
  1. 以 student 的身份执行 passwd

  2. 将命令丢进后台后暂停( 输入组合按钮后,可能需要再按一次 enter)

  3. 使用 pstree -pu 观察 passwd 与前、后程序的所有者变化。

  4. 将 passwd 拉到前景中,然后中断 passwd 。

  • SGID 的功能与观察

与SUID类似的,SGID为将特殊的权限旗标设定在群组的x上。 对文件来说, SGID 的功能为:

  • SGID 对二进制程序有用;

  • 程序执行者对于该程序来说,需具备 x 的权限;

  • 执行者在执行的过程中将会获得该程序组支持!

例题 5.3.1-3:使用 locate 查询系统文件名,进一步了解 SGID 用于指令的情境
  1. 请使用 student 身份查询名为 passwd 的文件有哪些 (使用 locate passwd 即可)

  2. locate 所取用的文件名数据库放置于 /var/lib/mlocate 当中,请使用 ll -d 的方式观察该目录的权限

  3. 承上,请问 student 有没有权限可以进入该目录?

  4. 使用 which locate 查询 locate 这个指令的完整文件名 (了解 which 的功能为何)

  5. 查询 locate 的权限,是否具有 SGID 的权限旗标? locate 的拥有群组为何? 为何 student 操作 locate 可以进入 /var/lib/mlocate 目录?

除了二进制文件外,SGID 亦可设定于目录上,当一个目录设定了 SGID 之后,会具有如下的功能:

  • 用户若对于此目录具有 r 与 x 的权限时,该用户能够进入此目录;

  • 用户在此目录下的有效群组(effective group)将会变成该目录的群组;

  • 用途:若用户在此目录下具有 w 的权限(可以新建档案),则使用者所建立的新档案,该新档案的群组与此目录的群组相同。

例题 5.3.1-4:使用 SGID 于目录的情境,相当重要的概念! (请使用 root 的身份进行如下的动作)
  1. 观察 /run/log/journal 这个目录本身的权限为何? 尤其是群组的权限资料

  2. 使用 touch /tmp/fromroot ,观察 /tmp/fromroot 的权限,尤其是群组的名称为何?

  3. 使用 touch /run/log/journal/fromroot,观察 /run/log/journal/fromroot 的权限,尤其是群组的名称为何?

以人类社团的社办来说,当你在童军社的社办公室撰写出一份活动草案时,这份活动草案的著作者应该是属于你的,但是草案的拥有群组应该是'童军社', 而不是'属于你的原生家庭'吧? 这就是 SGID 的主要功能。 在前一堂课中,管理员曾经建立一个共享目录 /srv/project1/, 当时的权限设定为 770 是有问题的,因为每个用户在该目录下产生的新档案所属群组并非共享群组。 因此,共享目录底下新建的数据应属于共享群组才对, 所以应该加上 SGID 的权限旗标设定才对。

  • SBIT 的功能与观察

前几堂课谈过 /tmp 是所有帐号均可写入的一个暂存目录,因此 /tmp 理论上应该是 777 的权限才行。 但是如果是777的权限,代表任何人所建立的任何数据,都可能被随意的删除,这就有问题。 因此 /tmp 会加上一个 Sticky bit 的特殊权限旗标,该旗标的功能为:

  • 当用户对于此目录具有 w, x 权限,亦即具有写入的权限时;

  • 当用户在该目录下建立文件或目录时,仅有自己与 root 才有权力删除该档案

例题 5.3.1-5:观察 SBIT 的权限功能
  1. 观察 /tmp 的权限,看其他人的权限当中的 x 变成什么?

  2. 以 root 登录系统,并且进入 /tmp 当中;

  3. 将 /etc/hosts 复制成为 /tmp/myhosts ,并且更改 /tmp/myhosts 权限成为 777 ;

  4. 以 student 登入,并进入 /tmp;

  5. student 能不能使用 vim 编辑这个文件? 为什么?

  6. student 能不能删除这个文件? 为什么?

5.3.2:SUID/SGID/SBIT 权限的设定

SUID/SGID/SBIT 的权限旗标是在 Linux 的传统三个身份三个权限之外的,因此会有第四个权限分数产生。 而这个权限分数的计算方式为:

  • 4 为SUID

  • 2 为 SGID

  • 1 为 SBIT

因此,观察底下的CentOS Linux的文件权限分数:

[student@localhost ~]$ ll -d /usr/bin/passwd /usr/bin/locate /tmpdrwxrwxrwt. 12 root root     4096  3月 23 13:59 /tmp
-rwx--s--x.  1 root slocate 48552  5月 11  2019 /usr/bin/locate
-rwsr-xr-x.  1 root root    34928  5月 11  2019 /usr/bin/passwd

若有小写 s 或 t 存在时,该字段需要加入 x 的权限,因此 /tmp 的传统权限为『 drwxrwxrwx (777) 』外加一个 SBIT,因此分数为『 1777 '。 而 /usr/bin/locate 传统权限会成为『 -rwx--x--x (711) '外加一个 SGID,因此分数会成为' 2711 '。 至于 /usr/bin/passwd 的传统权限是『 -rwxr-xr-x (755) 』,外加一个 SUID,因此分数成为' 4755 '。

除了数字法之外,符号法的使用上,可以使用类似底下的方式分别给予 SUID/SGID/SBIT:

  • SUID: chmod u+s filename

  • SGID: chmod g+s filename

  • SBIT: chmod o+t filename

例题 5.3.2-1:设定 SUID/SGID 的权限
  1. 一般用户执行 /usr/local/bin/mycat2 时,可以产生与 /usr/bin/cat 相同的结果。 但是一般用户在执行 mycat2 的时候,可以在运作的过程当中取得 root 的权限, 因此一般用户执行 mycat2 /etc/shadow 会顺利执行成功。

  2. 承袭前一堂课的实做成果,请到 /srv/ 目录下,观察 project1 这个目录的权限,若要让'所有在该目录底下建立的新档案,新档案的所属群组要跟 project1 相同, 亦即群组默认要成为 progroup 才行。

5.4:课后练习操作

  • 上课的课后练习,非作业:

  1. 因为某些缘故,你必须要在 prouser1 的家目录中建立一个名为 for_student 的目录,且,这个目录可以让 student 这个用户具有完整权限, 同时 prouser1 也需要具有完整权限,其他人则不具备任何权限! 你该如何设计'最小权限'给 prouser1 与 student 用户?

  2. 因为某些缘故,你必须要在 prouser1 的家目录底下建立一个名为 for_read 的目录,这个目录可以让 prouser1 完整读写, 而对于其他人来说,仍然具有可浏览文件名与读取内部档案的权限。

  3. 由于某些缘故,你需要延迟执行某个指令,并且是在目前的终端机上面,这个指令可以是' sh -c "sleep 60s; head -n 1 /etc/passwd" 』。 但是, 你需要让这串指令的 NI 值为 15,降低执行的优先序,请问该如何处理?

  4. 系统中有个正在执行且名为 gdm 的程序,这个程序似乎有点重要,所以在这次的运作中,我要将它调整成为最佳执行优先序,该如何调整?

  • 作业 (不提供学生答案,仅提供教师参考答案)

作业硬盘操作帮助:

  • 开启云端虚拟机前,请务必确认你开启的硬盘是'unit05',否则就会做错题目

  • 若要使用图形界面,请务必使用 student 身份登入,若需要切换身份,再启用终端机处理。

  • 若有简答题需要使用中文,请自行以第一堂课的动作自行处理输入法安装。

  • 每部虚拟机均有独特的网卡地址,请勿使用他人硬盘上传,否则计分为 0 分。

  • 每位同学均有自己的 IP 尾数,请先向老师询问您的 IP 尾数,才可以进行作业上传。

  • 最终上传作业结果,请务必使用 root 身份上传。

  • 进入操作硬盘后,先用 root 身份执行 vbird_book_setup_ip, 执行流程请参考:vbird_book_setup_ip

作业当中,某些部份可能为简答题~若为简答题时,请将答案写入 /home/student/ans.txt 当中,并写好正确题号,方便老师订正答案。 请注意,文件名写错将无法上传!


请使用 root 的身份进行如下实做的任务。 直接在系统上面操作,操作成功即可,上传结果的程序会主动找到你的实做结果。

  1. (18%)观察系统上面相关的档案信息后,尝试回答下列问题,并将答案写入 /home/student/ans.txt 当中:

    1. 系统上面有个名为 /opt/checking.txt 的文件,student 能否读, 写该文件? 为什么? (说明是哪种权限的影响)

    2. 承上,student 能不能将这个档案复制到 /tmp 去? 为什么? (说明是哪种权限的影响)

    3. student 能不能删除 /opt/checking.txt 这个档案? 为什么? (说明是哪种权限的影响)

    4. student 能不能用 ls 去查看 /opt/checkdir/ 这个目录内的文件名资料? 为什么? (说明是哪种权限的影响)

    5. student 能不能读取 /opt/checkdir/myfile.txt 档案? 为什么? (说明是哪种权限的影响)

    6. student 能不能删除他家目录底下,一个名为 fromme.txt 的文件? 为什么? (说明是哪种权限的影响)

  2. (12%)基础帐号管理,请创建如下的组和账户数据:

    1. 群组名称为: mygroup, nogroup

    2. 账号名称为: myuser1, myuser2, myuser3 ,通通加入 mygroup,且密码为 MyPassWord

    3. 账号名称为: nouser1, nouser2, nouser3 ,通通加入 nogroup,且密码为 MyPassWord

  3. (30%)管理组共享数据的权限设计:

    1. 创建一个名为 /srv/myproject 的目录,此目录可以让 mygroup 组内的用户完整使用,且【新建的文件拥有组】为 mygroup 。 不过其他人不能有任何权限

    2. 暂时切换成为 myuser1 的身份,并前往 /srv/myproject 目录,尝试建立一个名为 myuser1.data 的档案,之后注销 myuser1。

    3. 虽然 nogroup 群组内的用户对于 /srv/myproject 应该没有任何权限,但当 nogroup 内的用户执行 /usr/local/bin/myls 时,可以产生与 ls 相同的信息,且暂时拥有 mygroup 群组的权限,因此可以查询到 /srv/myproject 目录内的文件名信息。 也就是说,当你使用 nouser1 的身份执行【myls /srv/myproject】时,应该是能够查阅到该目录内的文件名信息。

    4. 让一般用户执行 /usr/local/bin/myless 产生与 less 相同的结果。 此外,只有 mygroup 的群组内用户可以执行,其他人不能执行,同时 myuser1 等人执行 myless 时,执行过程中会暂时拥有 root 的权限。

    5. 建立一个名为 /srv/nogroup 的空白档案,这个档案可以让 nouser1, nouser2, nouser3 读、写,但全部的人都不能执行。 而 myuser1, myuser2, myuser3 只能读不能写入。

  4. (30%)程序的觀察與簡易管理

    1. 使用程序觀察的指令,搭配 grep 的關鍵字查詢功能,將找到的 rsyslog 相關的程序的 PID, PRI, NI, COMMAND 等資訊轉存到 /root/process_syslog.txt 檔案中;

    2. 使用任何你知道的程序觀察指令,找到名為 sleep 的程序,找出他的 NI 值是多少?然後寫入 /root/process_sleep.txt 的檔案中

    3. 承上,請將該 NI 值改成 -10 。

    4. 以 myuser1 登入 tty3 終端機,然後執行『 sleep 5d 』這個指令,請注意,這個指令必須要在『背景以下運作』才行;

    5. 承上,在 tty3 的 myuser1 持續同時運作 vim ~/.bashrc 這個指令在前景運作。保留此環境,然後回到你原本的 tty 中。 (意思就是說,在 tty3 有個 vim 在前景執行,但你已經回到圖形界面或者是你的終端機環境中)

    6. 使用 root 執行『 sleep 4d 』這個指令,且這個指令的 NI 值必須要設定為 -5

  5. (10%)使用 find 找出 /usr/bin 及 /usr/sbin 兩個目錄中,含有 SUID 或/及 SGID 的特殊檔案檔名, 並使用 ls -l 去列出找到的檔案的相關權限後,將螢幕資料轉存到 /root/findsuidsgid.txt 檔案中。

作業結果傳輸:請以 root 的身分執行 vbird_book_check_unit 指令上傳作業結果。 正常執行完畢的結果應會出現【XXXXXX_aa:bb:cc:dd:ee:ff_unitNN】字樣。若需要查閱自己上傳資料的時間, 請在作業系統上面使用瀏覽器查詢: http://192.168.251.254 檢查相對應的課程檔案。 相關流程請參考: vbird_book_check_unit


©著作权归作者所有:来自ZhiKuGroup博客作者没文化的原创作品,如需转载,请注明出处,否则将追究法律责任 来源:ZhiKuGroup博客,欢迎分享。

评论专区
  • 昵 称必填
  • 邮 箱选填
  • 网 址选填
◎已有 0 人评论
搜索
作者介绍
30天热门
×
×
本站会员尊享VIP特权,现在就加入我们吧!登录注册×
»
会员登录
新用户注册
×
会员注册
已有账号登录
×