目录

  1. 初级研发工程师
    1. A
      1. 修改主机名称
      2. 查询网络设定
      3. 软件源修改
      4. 使用管理器安装软件
      5. 设置NTP时间同步
      6. 用户管埋
      7. 密码管理
      8. 文件的操作
      9. 目录的管理
      10. 设置计划任务
      11. 文件的查找
      12. 磁盘分区
      13. 开机自动挂载
      14. gcc的使用
      15. gdb调试
      16. 制作静态库编译main.c
      17. 制作动态库编译main.c
      18. 编写Makefile
      19. git本地仓库管理
      20. 文件的打包与拆解
    2. B
      1. 破解root密码
      2. 修改主机名
      3. 网络
      4. 软件源修改
      5. 使用管理器安装软件
      6. 设置NTP时间同步
      7. 用户管理
      8. 文件的操作
      9. 设置计划任务
      10. 文件查找
      11. 文件操作
      12. 查找
      13. 磁盘分区
      14. RAID的创建
      15. RAID操作
      16. 格式化挂载
      17. 在线扩容
      18. 开机自动挂载
      19. 文件的打包与拆解
      20. 使用systemctl命令设置服务的开机自启动
      21. 卸载
  2. 系统工程师
    1. A
      1. 单选
      2. 多选
      3. 实操
        1. 平衡二叉树
        2. 全排列
        3. C++
        4. 文件解析工具

初级研发工程师

A

修改主机名称

  1. 修改主机名称为:uos-exam-1-106
  2. 修改root密码为:uos@exam123
1
2
sudo hostnamectl set-hostname uos-exam-1-106
sudo passwd root uos@exam123

查询网络设定

查询本机eth0网卡的如下设定信息,并按以下冒号分隔的格式填写,存放在desk用户“桌面”上命名net.txt的文件。

1
2
3
4
5
6
7
ip:
mac:
netmask:
gateway:
首选DNS:
备选DNS:
nmcli dev show

软件源修改

备份默认软件源配置文件到同级目录,名称为:106.list.bak。
修改默认软件源配置文件,源为: deb http:/mirrors.163.com/deepin/ apricot main contrib non-free

1
2
3
4
sudo cp /etc/apt/sources.list /etc/apt/106.list.bak
sudo vim /etc/apt/soures.list
# 修改内容:deb http:/mirrors.163.com/deepin/ apricot main contrib non-free
sudo apt update

使用管理器安装软件

使用apt安装 unbound

1
sudo apt install unbound

设置NTP时间同步

安装ntpdate,使用ntpdate同步cn.pool.ntp.org时间服务器,把输出的结果保存在/opt/date.txt。

1
2
sudo apt install ntpdate
sudo ntpdate cn.pool.ntp.org > /opt/date.txt

用户管埋

建立uos-exam组

  1. 添加用户uoskeeper106,指定uos-exam组为属组(基本组),指定并创建家目录为/home/uoskeeper106。
  2. 添加用户uosmaster106,指定uos-exan组为属组(基本组),指定并创建家目录为/home/uosmaster106。
  3. 添加uosnologin用户并设置不能交互式登陆。
  4. 修改uosnologin的UD为2020。
1
2
3
4
5
sudo groupadd uos-exam
sudo useradd -g uos-exam -md /home/uoskeeper106 uoskeeper106
sudo useradd -g uos-exam -md /home/uosmaster106 uosmaster106
useradd -m uosnologin -s /sbin/nologin
sudo usermod -u 2020 uosnologin

密码管理

针对uosmaster106用户做以下设置:

  1. 设置用户7天后可更改密码
  2. 设置用户90天后密码过期
  3. 用户密码过期前15天提醒
1
2
3
4
5
passwd -n 7 -x 90 -w 15 uosmaster106

chage -M 90 uosmaster106
chage -m 7 uosmaster106
chage -W 15 uosmaster106

文件的操作

  1. 复制/etc/apt106.list.bak到/opt目录下
  2. 修改/opt/106.list.bak文件的权限:
    1. 该文件属主属组为root
    2. uoskeeper106只有读权限
    3. uosmaster106只有执行权限
1
2
3
4
5
sudo cp /etc/apt/106.list.bak /opt
sudo chown -R root:root /opt/106.list.bak
sudo getfacl /opt/106.list.bak
setfacl -m u:uoskeeper106:r /opt/106.list.bak
setfacl -m u:uosmaster106:x /opt/106.list.bak

目录的管理

在/opt目录下创建uosexam目录,该目录属主为:root,属组为uos-exam,权限为775。

  1. 在/opt/uosexam目录下新创建的文件和目录属组固定为: uos-exam。
  2. 在/opt/uosexam目录下uoskeeper106和uosmaster106用户只能管理自己新创建的文件,不能删除和修改对方的文件。
    1
    2
    3
    4
    sudo chown root:uos-exam /opt/uosexam
    sudo chmod 775 /opt/uosexam
    sudo chmod g+s /opt/uosexam
    sudo chmod +t /opt/uosexam

设置计划任务

对uosmaste106设置计划任务,每天23点59分,执行/bin/echo “UOS is the best system”。

1
2
3
crontab -e -u uosmaster106
# 回车 选择3 进入Vim模式
59 23 * * * /bin/echo "UOS is the best system"

文件的查找

查找名为exam-uos-file.conf的文件,并把此文件的绝对路径写入/opt/pwdin.xt中。

1
find / -name exam-uos-file.conf > /opt/pwdin.txt

磁盘分区

  1. 对/dev/vdb磁盘设备,进行分区为/dev/vdb2,分区大小为5G。
  2. 对新增加的分区/dev/vdb2进行文件系统格式化为“ext4”。
1
2
3
4
fdisk -l
sudo fdisk /dev/vdb2
# 操作中依次输入: n 2 回车 +5G w
sudo mkfs.ext4 /dev/vdb2

开机自动挂载

  1. 创建目录/opt/data。
  2. 将/dev/vdb2挂载到/opt/data目录。
  3. 修改fstab配置文件,使用/dev/ydb2的uud配置开机自动挂载。
    1
    2
    3
    4
    5
    6
    mkdir /opt/data
    mount /dev/vdb2 /opt/data
    # 使用 blkid 找到 /dev/vdb2的uuid
    blkid /dev/vdb2
    # 在 /etc/fstab 中写入
    UUID=XXXX /opt/data ext4 defaults 00

gcc的使用

/opt/exam14目录下C源代码helo.c,实现打印输出”Hello UOS!”。

  1. 使用gcc命令,编译并连接,直接生成可执行文件hello1,执行hello1,查看结果。
  2. 使用gcc命令,先编译hello.c源文件,生成后缀为hello2.o的目标文件。通过目标文件的连接,再生成可执行文件hello2,执行hello2,查看结果。
1
2
3
gcc hello.c -o hello1
gcc -c hello.c -o hello2.o
gcc hello2.o -o hello2

gdb调试

opt/exam15目录下将test.c文件编译成包含标准调试信息的文件test。运行生成的可执行文件,观察运行结果,使用gdb调试程序,通过设置断点,单步调试。

  1. 修改源程序,输出结果第一行为:The original string is linux UOS
  2. 修改源程序,输出结果第二行为:The string afterward is SoU xunil
1
2
3
4
5
6
7
8
9
$ gcc -g test.c -o test
$ gdb test
===============
gdb > set write on

gdb > p <变量> = 100
gdb > set var <变量> = 100

==========

源程序修改如下:display2函数的for循环大括号中内容修改为

1
2
3
{
string2[size-i-1] = string1[i];
}

制作静态库编译main.c

/opt/exam16目录下有main.cpp、head.h、add.cpp、sub.cpp文件。
为add.cpp、sub.cpp文件都生成add.o、sub.o文件,制作静态库libhead.a(生成文件均在/opt/exam16/目录下)。
编译main.cpp生成main可执行文件。

1
2
3
4
5
6
gcc -c add.cpp -o add.o
gcc -c sub.cpp -o sub.o
ar crv libhead.a add.o sub.o
gcc main.cpp libhead.a -o main -lstdc++
apt install g++
g++ main.cpp libhead.a -o main

制作动态库编译main.c

/opt/exam17目录下有main.cpp、head.h、add.cpp、sub.cpp。
为add.cpp、sub.cpp生成add0、sub0文件。
用ado、sub.o文件制作动态库libhead.so文件编译main.cpp生成man可执行文件(生成文件均在/opt/exam17/目录下)

生成.o

1
2
3
4
5
6
7
8
g++ -I ./ -c add.cpp
g++ -I ./ -c sub.cpp

g++ ./*.cpp -fPIC -shared -o subhead.so
# 或者
g++ ./*.o -fPIC -shared -o subhead.so

g++ *.cpp -L -lhead -o main

编写Makefile

/opt/exam18目录下,编写Makefile文件进行编译,输出test可执行文件。
test文件由目/opt/exam18录下main.c文件、func.h文件和test*c.文件组成。
要求在源码/opt/exam18目录下执行make成功可执行文件test,执行test输出对应内容。

1
2
3
4
make:
gcc *.c -o test
clean:
rm -rf *.o

git本地仓库管理

进入/opt/exam19目录设置本地git仓库。

  1. 设置全局用户名为:Uos。
  2. 设置全局邮箱名为:UoS106@.com。
  3. 在/opt/exam19目录下,创建git本地仓库。
  4. 在/opt/exam19目录下,创建文本文件test.txt编辑文件内容为UOS is the best system。
  5. 将test.txt提交到git仓库。
1
2
3
4
5
6
7
8
9
10
11
12
git config --global user.name <user>
git config --global user.email <email>

echo "UOS is the best system" > /opt/exam19/test.txt

cd /opt/exam19

git init

git add .

git commit -m "init base"

文件的打包与拆解

对/Packages目录下Firefox.tar.bz2进行解包。

  1. 解压后的目录移动到/opt/data目录下。
  2. /opt/data目录进行打包,打包完的名称为“data.tar.gz”存放位置在/opt目录下。
1
2
tar -xjvf Firefox.tar.bz2  -C  /opt/data
tar -czvf data.tar.gz /opt/data

B

破解root密码

1030版本后,已无法使用在grub界面修改参数破解密码,请在左面新建pwd.txt文档并编辑,简要描述使用光盘或者U盘来破解root密码的过程。

  1. 1031以上系统更改密码,需要物理介质(光驱或者U盘)引导进入PE界面。
  2. 开机后进入bios选择物理介质启动。
  3. 到grup界面按tab,删除livecd-installer。
  4. 进入PE创建目录/mnt/systmp,然后将/root挂载到/mnt/systmp。
  5. chroot /mnt/systmp
  6. echo $PATH
  7. passwd命令修改密码
  8. 拔出物理介质,正常启动输入密码

修改主机名

修改主机名为uos-exam-112

1
2
sudo vim /etc/hostname
hostnamectl set-hostname uos-exam-112

网络

查询主机eth0网卡的如下信息,并按照一下冒号的格式填写,存在desk用户“桌面”上命名,net.txt文件。

1
2
3
4
5
6
Ip:			ifconfig
Mac: ifconfig -a的ether字段
Netmask: ifconfig #255.255.0.0
Gateway: ifconfig的网关 #前缀和ip一样
首选DNS: nmcli dev show或者sudo vim /etc/resolv.conf
备选DNS: nmcli dev show或者sudo vim /etc/resolv.conf

软件源修改

备份默认的软件源配置文件到同级目录,名称为:112.list.bak。
配置新的源为:deb http://mirrors.163.com/deepin/ apricot main contrib non-free

1
2
sudo cp /etc/apt/source.list  /etc/apt/112.list.bak
sudo vim /etc/apt/source.list

使用管理器安装软件

使用apt安装“unbound”

1
2
apt-get update				#更新
sudo apt-get install unbound #安装

设置NTP时间同步

安装ntpdate
使用ntpdate同步cn.pool.ntp.org时间服务器
把输出的结果保存在/opt/date.txt

1
2
3
apt-get install ntpdate	        #安装,此处出现问题待解决
ntpdate cn.pool.ntp.org > /opt/date.txt
cat /opt/date.txt #检查是否为空

用户管理

建立uos-exam组
添加用户uoskeeper112和uosmaster112到uos-exam组并指定各自的家目录为/home/uoskeeper112和/home/uosmaster112
添加uosnologin用户并设置不能交互式登陆。
修改uosnologin的UID为2020

1
2
3
4
5
groupadd uos-exam	#创建组
useradd -m -G uos-exam -d /home/uoskeeper112 uoskeeper112 #创建
useradd -m -G uos-exam -d /home/uosmaster112 uosmaster112 #创建
sudo useradd -s /usr/sbin/nologin uosnologin #创建
sudo usermod -u 2020 uosnologin #修改UID

文件的操作

复制/etc/apt/112.list.bat到/opt
修改改文件的权限:
此文件的属主属组为root
Uoskeeper112只有读权限
Uosmaster112只有执行权限

1
2
3
4
5
6
cp /etc/apt/112.list.bat /opt
chown root:root /opt/112.list.bak
setfacl -m u:uoskeeper112:r /opt/112.list.bak
getfacl 112.list.back #查看权限是否设置成功
setfacl -m u:uosmaster112:x /opt/112.list.bak
getfacl 112.list.back #查看权限是否设置成功

设置计划任务

对uosmaster112设置计划任务,每天23点59分,执行/bin/echo “UOS is the best system”

1
2
3
crontab -u uosmaster112 -e	#-u表指定用户,-e执行文字编辑器设定
# 首次按“2”或者“3”,不要按“1”
# 输入59 23 * * * /bin/echo "UOS is best system"

文件查找

查找名为“exam-uos-file.conf”的文件,并把此文件的绝对路劲写入/opt/pwdin.txt中。

1
sudo find / -name exam-uos-file.conf > /opt/pwdin.txt

文件操作

进入/opt目录,建立uniontech.txt文件,内容为“UOS is the best system”。要求该文件不能被删除,不能被修改。

1
2
3
4
vim /opt/uniontech.txt
UOS is the best system
wq
chattr +i /opt/uniontech.txt

查找

查找/usr/share目录下所有文件中包含“happyexam”的字符串,并把查出来的行号写入/opt/findcode.txt(注意:只写行号)。

1
2
3
4
5
6
7
8
grep -R -n "happyexam" /usr/share/doc/unbound/examples/unbound.conf | awk -F : '{print $2}' | sudo tee /opt/find.txt

# 查看是否为正确行数,没有其他字符
cat /opt/find.txt

# '{print $1}'中的$数字需要根据实际更改,行是1行号是2
grep -R -n "happyexam" /usr/share/doc/unbound/examples/unbound.conf | awk -F : '{print $1}' > /opt/find.txt
cat /opt/find.txt

磁盘分区

13、对22G的磁盘dev/vdb,分4个大小为5G的分区和1个2G的分区。

1
2
3
4
5
6
7
8
9
10
11
12
fdisk /dev/sdb
n
+5g
n
+5g
n
+5g
n
+5g
n
+2g
w

RAID的创建

对上一题划分的4块的分区进行RAID5创建,预留最大空间(大于14G),路径名称为“/dev/md5”
创建完成后将raid5信息写入/etc/mdadm.conf文件中。
执行update-initramfs -u,否则重启后raid5名称会发生变化。

1
2
3
4
mdadm -C /dev/md5 -a yes -l 5 -n 4 /dev/sdb5 /dev/sdb6 /dev/sdb7 /dev/sdb8
ls -l /dev/md5 #查看确认
mdadm -D /dev/md5 > /etc/mdadm.conf
update-initramfs -u

RAID操作

对新加的磁盘阵列“md5”进行逻辑卷制作
建物理卷,使用“md5”
新建卷组,名称为“uosvg”
新建逻辑卷,使用所有卷组容量(大于14G),名称“uoslv”

1
2
3
pvcreate /dev/md5	#变成逻辑卷首先要变成物理卷 pvs	查看
vgcreate uosvg /dev/md5 #变成卷组,vgs 查看
lvcreate -l +100%free uosvg -n uoslv

格式化挂载

格式化新添加的逻辑卷并挂载
对新添加的逻辑卷进行格式化“ext4”
创建目录/opt/data
挂载新添加的逻辑卷到上步新建的目录

1
2
3
mkfs.ext4 /dev/uosvg/uoslv		#格式化
mkdir /opt/data #创建挂载目录
mount /dev/uosvg/uoslv /opt/data #挂载

在线扩容

使用13题划分的2G分区,对/opt/data进行在线扩容(大于16G)

1
2
3
pvcreate /dev/sdb9				#先变成物理分区
vgextend uosvg /dev/sdb9 #对uosvg扩容
lvextend -r -l +100%free /dev/uosvg/uoslv #对uoslv扩容

开机自动挂载

修改fstab配置文件实现对新扩容的磁盘阵列的开机自动挂载

1
2
3
4
blkid /dev/uosvg/uoslv				#查找、复制uuid
vim /etc/fstab #编辑fatab
uuid /opt/data ext4 defaults 0 0 #输入内容配置自动挂载
mount -a #检查挂载

文件的打包与拆解

对/packages目录下Firefox-latest-x86_64.tar.bz2进行解包,解压后的目录移动到/opt/data。
对/opt/data目录进行打包,打包完的名称为“data.tar.gz”存放位置在/opt目录下。

1
2
3
tar -jxvf /Packages/Firefox-latest-x86_64.tar.bz2 -C /opt/data
tar -czvf /opt/data.tar.gz /opt/data

使用systemctl命令设置服务的开机自启动

1
2
sudo systemctl enable ssh
update-rc.d ssh enable 2 3 4 5

卸载

umount 路径
删除逻辑卷:

  1. 卸载:umount 挂载路径
  2. 删除逻辑卷:lvremove xxlv
  3. 删除卷组:vgremove xxvg
  4. 删除物理卷:pvremove pv的盘路径
  5. 删除分区:fdisk 盘路径
  6. d删除分区
  7. w保存

系统工程师

A

单选

  1. 申威CPU的架构是(D)
    A. x86
    B. mips
    C. ARM
    D. Alpha

申威好像是依托于Alpha架构,RISC指令集。

  1. 以下不是开源许可证的有(C)
    A. MIT
    B. GPL
    C. CC
    D. BSD

  2. 假设txt_size 是一个无参数函数,它的返回值是int;Unsigned buf_size = 1024;下面哪个定义是合法的?(B)
    A. int ia[buf_size];
    B. int ia[4*7 - 14];
    C. int ia[txt_size()];
    D. char st[11] = “fundamental”;

  3. 一个类的友元函数可以访问类的( D )成员。
    A. 私有成员
    B. 保护
    C. 公有
    D. 以上都正确

  4. 下面哪一个不是一种临界区保护机制(C)
    A. 互斥锁
    B. 信号量
    C. 条件变量
    D. 读写锁

  5. 龙芯CPU的架构是(B)
    A. x86
    B. mips
    C. ARM
    D. Alpha

  6. 下面字面值数据类型说法错误的是?(C)
    A. L’a’表示为宽字符型字面值a且类型是wchar_t
    B. 10L表示一个长整形数
    C. 3.14L表示一个long float类型的扩展精度浮点数(应该是long double)。
    D. 10. 是一个浮点数

解释以下字面值常量:
‘a’:char型字面值 L’a’:wchar_t型字面值
“a”:字符串字面值 L”a”:宽字符串字面值
10:int型字面值 10L:long型字面值
10u:unsigned型字面值 10uL:unsigned long型字面值
012:八进制表示的int型字面值 0xC:十六进制表示的int型字面值
3.14:为double型字面值 3.14f:为float型字面值
3.14L:为long double型字面值
-10.:为double型字面值 -10e-2:为double型字面值
-10u:unsigned int型字面值 -10:int型字面值

非法常量:3.14UL、1024f

  1. 使用地址作为实参传给形参,下列说法正确的是(D)。
    A. 实参是形参的备份
    B. 实参与形参无联系
    C. 形参是实参的备份
    D. 实参与形参是同一对象

  2. 以下程序运行时,若从键盘输入5,则输出结果是(C) [单选题] *

    1
    2
    3
    4
    5
    6
    7
    8
    main(){ 
        int a;
        scanf("%d", &a);
        if(a++ > 5) 
            printf("%d\n", a);
        else
            printf("%d\n", --a);
    }

    A. 7
    B. 4
    C. 5
    D. 6

  3. 他人修改源代码后必须开源的许可证有 (A) 
    A. LGPL
    B. BSD
    C. Apache
    D. MIT

  4. C语言的标识符只能由字母、数字和下划线三种字符组成,且首字符(A)
    A. 必须为字母或下划线
    B. 必须为下划线
    C. 必须为字母
    D. 可以是字母、数字和下划线中的任一种字符。

  5. 假定一个类的构造函数为“A(int i=4, int j=0) {a=i;b=j;}”, 则执行“A x (1);”语 句后,x.a和x.b的值分别为(D)
    A. 4和1
    B. 4和0
    C. 1和4
    D. 1和0

  6. 对数组名作函数的参数,下面描述正确的是(B)。
    A. 数组名作函数的参数,调用时将实参数组复制给形参数组
    B. 数组名作函数的参数,主调函数和被调函数共用一段存储单元
    C. 数组名作参数时,形参定义的数组长度不能省略
    D. 数组名作参数,不能改变主调函数中的数据

  7. 列出当前目录下所有.h的文件,不含子目录(A)。
    A. ls *.h
    B. find . -name *.h
    C. find . -name *.h$
    D. find . |grep h

  8. 以下不是开源许可证的有(C)。
    A. MIT
    B. GPL
    C. CC
    D. BSD

  9. extern关键字的作用是什么?(D)
    A. 声明外部链接
    B. 声明外部头文件引用
    C. 声明使用扩展C++语句
    D. 声明外部成员函数、成员数据

  10. 以下不是C语言提供的合法关键字为(B)
    A. switch
    B. printf
    C. case
    D. default

多选

  1. 假如有如下声明,下面哪个调用是合法的(B,C)。
    1
    2
    3
    4
    doublecacl(double);
    intcount(conststring &, char);
    intsum(vector::iterator, vector::iterator, int)
    vectorvec(10)
    A. cacl(23.4, 55.1);
    B. count(“abcda”,’a’);
    C. cacl(66);
    D. sum(vec.begin(), vec.end(), 3.8);

实操

平衡二叉树

输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回 true 。

示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
1
/ \
2 2
/ \
3 3
/ \
4 4
返回 false 。

要求:

  1. 使用纯C语言完善exam.h文件,通过所有单元测试
  2. 代码逻辑符合题目要求,判卷评分有更多单元测试项
  3. 除exam.h以外的文件不得修改,修改会被覆盖
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
#ifndef EXAM_H
#define EXAM_H

#include <algorithm>
#include <stdlib.h>
#include <string.h>

using namespace std;

struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
};

static int depth(TreeNode *node) {
if (node == NULL) {
return 0;
}
int left, right = 0;
left = depth(node->left);
if (left == -1) return -1;
right = depth(node->right);
if (right == -1) return -1;

return abs(left - right) < 2 ? max(left, right) + 1 : -1;
}

static bool tree_is_balanced(TreeNode *root) {

return depth(root) != -1;
}

#endif // EXAM_H

全排列

无重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合,字符串每个字符均不相同。并将结果按字符串从小到大排序

示例1:

  • 输入:S = “qwe”
  • 输出:[“eqw”, “ewq”, “qew”, “qwe”, “weq”, “wqe”]

示例2:

  • 输入:S = “ab”
  • 输出:[“ab”, “ba”]

要求:

  1. 使用纯C语言修改exam.h文件,通过所有单元测试。
  2. 代码逻辑符合题目要求,判卷评分有更多单元测试项。
  3. 输出结果按照字典顺序排序。
  4. exam.h以外的文件不得修改,修改会被覆盖。
    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
    /* exam.h */
    #ifndef EXAM_H
    #define EXAM_H

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <algorithm>

    int count = 0

    void swap(char *a, char *b)
    {
    char t;
    t = *a;
    *a = *b;
    *b = t;
    }

    void perm(char* p, int from, int to, char ** res)
    {
    if (from == to){
    res[res_count] = p
    // memcpy(res[res_count], p, strlen(p));
    count ++;
    }
    if(from < to){
    for(int i = from; i <= to; i++){
    swap(&p[i], &p[from]);
    perm(p, from + 1, to, res);
    swap(&p[i], &p[from]);
    }
    }
    }

    /* 返回一个以空字符串结尾的char*数组 */
    char** permute_string(const char* input)
    {
    char ** res = 0;
    int N = 1; // size of your result
    for (int i =strlen(input); i>1; i--){
    N = N * i;
    }
    res = (char**)malloc(sizeof(char*) * N);

    res[N] = 0;
    return res;
    }


    #endif // EXAM_H

C++

编写一个程序,从命令行读取一个软件包的名称,调用“dpkg -L”命令获得该软件包的文件列表,并检查所有文件。
要求:

  1. 使用cmake和c/c++开发
  2. 可执行文件名称和位置是./src/pkgverify
  3. 检查该软件包所有文件,确认:
    • 路径存在
    • 文件存在
    • 如果是符号链接,链接的文件也存在
    • /usr路径下的文件,确认文件属主都是root
  4. 输出所有有问题的文件或路径名
  5. 由于qDebug/qInfo等输出方式会添加多余字符,且不在标准输出上,与考试要求不符,请谨慎使用
  6. testHelper.sh有很少的测试用例,可以帮助做初步验证

示例:
如果/etc/cups路径被删除了,则运行结果如下:

1
2
3
pkgverify cups
/etc/cups
/etc/cups/snmp.conf

首先编辑考试目录下的CMakeLists.txt

1
2
3
4
CMAKE_MINIMUM_REQUIRED(VERSION 3.5)
PROJECT(exam)

ADD_SUBDIRECTORY(src)

编辑src目录下的CMAKELists.txt。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cmake_minimum_required(VERSION 3.5)

project(pkgverify)

SET(CMAKE_INCLUDE_CURRENT_DIR ON)
SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_BUILD_TYPE Debug)

set(exam_SOURCE
${CMAKE_CURRENT_SOURCE_DIR}/dpkg.cpp
)

add_executable(${PROJECT_NAME} ${exam_SOURCE})

在考试目录下执行cmake命令。

1
2
3
4
cmake -S . -B build
# cd build
# make
# ./src/pkgverify

编辑src/main.cpp文件

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
#include <iostream>
#include <cstring>
#include "sys/stat.h"
#include "unistd.h"

using namespace std;

int main(int argc, char **argv) {
string command = "dpkg -L ";

if (argc == 2) {
command += argv[1];
} else if (argc > 2) {
cout << "To many packages. " << endl;
return -1;
} else {
cout << "Expect one package" << endl;
return -1;
}

FILE *fstream = nullptr;
char buffer[1024];
struct stat file_stat{};
if (nullptr == (fstream = popen(command.c_str(), "r"))) {
return -1;
}

while (nullptr != fgets(buffer, sizeof(buffer), fstream)) {
buffer[strlen(buffer) - 1] = 0;
if (access(buffer, F_OK) == 0) {
if (strncmp(buffer, "/usr/", 5) == 0) {
stat(buffer, &file_stat);
if (file_stat.st_uid == 0) {
continue;
}
} else {
continue;
}
}
printf("%s\n", buffer);
}
return 0;
}

最后进入build目录执行make,再将pkgverify可执行文件复制到src下。

1
2
3
cd build
make
cp ./src/pkgverify ../src/

文件解析工具

遵循 https://specifications.freedesktop.org/desktop-entry-spec/latest/ 标准实现一个desktop文件解析工具

功能要求

  • desktop文件格式无错误时进程退出码为0
  • 实现对desktop文件Name(程序名称)、Exec(可执行文件)、Icon(图标文件)三个字段的解析
  • 需要检测文件的格式,遇到错误时以退出码 1 退出进程
  • 输入接收一个desktop文件的绝对路径,能够输出程序名称、图标文件(图标文件不考虑从系统图标主题中查找)
  • 能够在指定一个desktop文件后启动进程,且允许为其指定参数

其它要求

  • 使用cmake构建工程
  • 可执行文件位置和名称为:./src/freedesktop
  • testHelper.sh有很少的测试用例,可以帮助做初步验证

示例

  • a.desktop文件内容为:
    [Desktop Entry]
    Name=A;
    Name[zh_CN]=”我是A”;
    Exec=cat %f
    Icon=/tmp/a.png

  • 输入参数(-d指定desktop文件的绝对路径,-n表示要获取应用程序名称):
    freedesktop -d /home/a/a.desktop -n

  • 输出结果:
    A或我是A(中文环境下,注意应该去掉引号)

  • 输入参数(-i表示要获取应用程序的图标)
    freedesktop -d /home/a/a.desktop -i

  • 输出结果(如图标数据不是一个文件路径,则先将图标文件保存为文件后再返回此文件的绝对路径):
    /tmp/a.png

  • 输入参数(-e表示要启动此应用程序,其后可根一个或多个传入参数)
    freedesktop -d /home/a/a.desktop -e /home/a/test.txt

  • 输出结果:
    输出结果为 /home/a/test.txt 文件的内容,也就是Exec命令执行时对标准输出通道所写入的全部数据

安装依赖

1
2
apt install libicu-dev
apt install libsimpleini-dev

CMakeLists.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cmake_minimum_required(VERSION 3.5)

project(freedesktop)

SET(CMAKE_INCLUDE_CURRENT_DIR ON)
SET(CMAKE_CXX_STANDARD 11)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_BUILD_TYPE Debug)

set(exam_SOURCE
${CMAKE_CURRENT_SOURCE_DIR}/desktop.cpp
)

add_executable(${PROJECT_NAME} ${exam_SOURCE})

target_link_libraries(${PROJECT_NAME} simpleini)

代码

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
#include <iostream>
#include <unistd.h>
#include "SimpleIni.h"

using namespace std;

int main(int argc, char *argv[]) {
int opt;
char const *args = "d:nie::";
string run_arg;
string file_path;
bool get_name, get_icon, run = false;
while ((opt = getopt(argc, argv, args)) != -1) {
switch (opt) {
case 'd':
file_path = optarg;
break;
case 'n':
get_name = true;
break;
case 'i':
get_icon = true;
break;
case 'e':
run = true;
run_arg = optarg;
break;
default:
break;
}
}

// string validate = "desktop-file-validate " + file_path;
//
// if (system(validate.c_str()) != 0) {
// cout << "validate desktop file failed!" << endl;
// return -1;
// }

CSimpleIniA ini;
ini.SetUnicode();
SI_Error rc = ini.LoadFile(file_path.c_str());
if (rc < 0) {
cout << "error" << endl;
}

if (get_name) {
string value = ini.GetValue("Desktop Entry", "Name");
cout << value << endl;
}
if (get_icon) {
string icon = ini.GetValue("Desktop Entry", "Icon");
cout << icon << endl;
}

if (run) {
string command = ini.GetValue("Desktop Entry", "Exec");
cout << command << endl;
system((command + " " + run_arg).c_str());
}

return 0;
}