20145312 《信息安全系统设计基础》第12周学习总结
20145312 《信息安全系统设计基础》第12周学习总结
代码总结
ls命令
- ls功能:读取文件名和文件属性,按照字典序排序后输出。
- 常用的命令行选项:
ls -l 以长格式的形式查看当前目录下所有可见文件的详细属性
ls -a 列出的内容包含以“.”开头的文件
ls -lu 最后访问时间
ls -s 以块为单位的文件大小
ls -t 按时间排序
ls -F 显示文件类型
ls -l
- ls -l 的输出每行都包含7个字段
模式 每行的第一个字符表示文件类型,“-”代表普通文件,“d”代表目录文件。
链接数 指该文件被引用的次数
文件所有者 指出文件所有者的用户名
组 指出文件所有者所在的组
大小 显示文件的字节数
最后修改时间 文件的最后修改时间
文件名 文件名
- ls -l可以显示当前目录下目录或文件的详细属性信息
cp命令
- 查看帮助文档
man cp
- cp的作用就是读取一个文件的内容到存储器,在新的地址创建空白文件,再从存储器将内容写入新文件。(如下图把ls1.c复制,存为lc.c文件)
ls1和ls2
- ls1程序的作用是在当前目录显示文件名(未带参数直接显示,带参数的存入argc)
- ls2不仅显示了文件名,还用来显示文件的详细信息,比如用户名、群组名、大小、创建时间、读写权限等。
echostate.c和setecho.c
echostate.c
- 功能:查看在命令行中输入命令时是否可见,可见返回1,否则返回0
setecho.c
- 设置回显位的状态,命令行参数为y则开启,否则关闭。
- 标准输入的文件描述符为0.
- 使用tcgetattr()函数和termios结构体可获得标准输入的属性。
- 使用tcsetattr()函数和termios结构体可以将更改后的属性设置重新写回标准输入。
ioctl函数
- ioctl是设备驱动程序中对设备的I/O通道进行管理的函数。
- ioctl函数是文件结构中的一个属性分量,就是说如果你的驱动程序提供了对ioctl的支持,用户就可以在用户程序中使用ioctl函数控制设备的I/O通道。
- 查看帮助文档
man isatty
man ioctl
- isatty:判断一个文件描述符是否指向一个终端
- ioctl:控制驱动器
- 程序运行结果
filesize
- filesize代码用st_size成员来计算文件的字节数大小,gcc后有一个警告,调用正常。
fileinfo
- fileinfo代码这个功能用来实现显示文件信息,建立了一个stat数据结构。先判断命令是否有操作数,有的话才能继续进行下去,如果没有报错就打印出来相关文件信息,报错就用perror将报错信息打印出来。
spwd命令
- spwd的功能是列出当前目录。
who命令
- 这个代码的思想是,从UTMP_FILE文件中读取想要的信息到存储器中,然后再用标准输出函数打印到屏幕上,最后关闭文件。
-程序运行结果
exec1
- 代码如下:
#include <stdio.h>
#include <unistd.h>
int main()
{
char *arglist[3];
arglist[0] = "ls";
arglist[1] = "-l";
arglist[2] = 0 ;//NULL
printf("* * * About to exec ls -l\n");
execvp( "ls" , arglist );
printf("* * * ls is done. bye");
return 0;
}
-
可以看到这个代码中用了execvp函数。
-
表头文件:#include<unistd.h>
-
定义函数:int execvp(const char file ,char const argv []);
-
execvp()会从PATH 环境变量所指的目录中查找符合参数file 的文件名,找到后便执行该文件,然后将第二个参数argv传给该欲执行的文件。
如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno中。
运行结果如下:
exec2
- 它与exec1的区别就在于exevp函数的第一个参数,exec1传的是ls,exec2直接用的arglist[0],不过由定义可得这两个等价,所以运行结果是相同的。
运行结果如下:
exec3
- 此程序指定了环境变量,然后依然执行了ls -l指令,成功后没有返回,所以最后一句话不会输出,结果依然相同。
- 相关代码
#include <stdio.h>
#include <unistd.h>
int main()
{
char *arglist[3];
char*myenv[3];
myenv[0] = "PATH=:/bin:";
myenv[1] = NULL;
arglist[0] = "ls";
arglist[1] = "-l";
arglist[2] = 0 ;
printf("* * * About to exec ls -l\n");
execlp("ls", "ls", "-l", NULL);
printf("* * * ls is done. bye\n");
}
- 函数说明:execlp()会从PATH 环境变量所指的目录中查找符合参数file的文件名,找到后便执行该文件,然后将第二个以后的参数当做该文件的argv[0]、argv[1]……,最后一个参数必须用空指针(NULL)作结束。如果用常数0来表示一个空指针,则必须将它强制转换为一个字符指针,否则将它解释为整形参数,如果一个整形数的长度与char * 的长度不同,那么exec函数的实际参数就将出错。如果函数调用成功,进程自己的执行代码就会变成加载程序的代码,execlp()后边的代码也就不会执行了.
- 返回值:如果执行成功则函数不会返回,执行失败则直接返回-1,失败原因存于errno 中。也就是说,这个代码指定了环境变量,然后依然执行了ls -l指令,成功后没有返回,所以最后一句话不会输出。运行结果同exec1.
运行结果如下:
forkdemo1
- 使用fork创建子进程的父进程,调用fork一次,打印两个输出行
- 相关代码
#include "csapp.h"
int main()
{
pid_t pid;
int x = 1;
pid = Fork(); //line:ecf:forkreturn//父进程和子进程中x的值都为1
if (pid == 0) { /* Child */
printf("child : x=%d\n", ++x); //子进程增加并输出它的x的拷贝
exit(0);
}
/* Parent */
printf("parent: x=%d\n", --x); //父进程减少和输出它的x的拷贝
exit(0);
}
运行结果如下:
forkdemo3
- 父进程返回调用进程子进程的PID,不为0,输出 i am the parent……
- 相关代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int fork_rv;
printf("Before: my pid is %d\n", getpid());
fork_rv = fork();
if ( fork_rv == -1 )
perror("fork");
else if ( fork_rv == 0 ){
printf("I am the child. my pid=%d\n", getpid());
exit(0);
}
else{
printf("I am the parent. my child is %d\n", fork_rv);
exit(0);
}
return 0;
}
运行结果如下:
forkdemo4
- getpid返回调用进程的PID
- getppid返回它的父进程的PID
- 相关代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int fork_rv;
printf("Before: my pid is %d\n", getpid());
fork_rv = fork(); //fork产生子进程
if ( fork_rv == -1 )
perror("fork");
else if ( fork_rv == 0 ){
printf("I am the child. my pid=%d\n", getpid());
printf("parent pid= %d, my pid=%d\n", getppid(), getpid());
exit(0);
}
else{
printf("I am the parent. my child is %d\n", fork_rv);
sleep(10);
exit(0);
}
return 0;
}
运行结果如下:
forkgdb
- 父进程和子进程这两个线程是并发运行的独立进程,一个在休眠时另一个在执行,两个相互独立不干扰。
- 相关代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int gi=0;
int main()
{
int li=0;
static int si=0;
int i=0;
pid_t pid = fork();
if(pid == -1){
exit(-1);
}
else if(pid == 0){
for(i=0; i<5; i++){
printf("child li:%d\n", li++);
sleep(1);
printf("child gi:%d\n", gi++);
printf("child si:%d\n", si++);
}
exit(0);
}
else{
for(i=0; i<5; i++){
printf("parent li:%d\n", li++);
printf("parent gi:%d\n", gi++);
sleep(1);
printf("parent si:%d\n", si++);
}
exit(0);
}
return 0;
}
运行结果如下:
psh1
- 代码分析:这个代码就相当于你输入要执行的指令,回车表示输入结束,然后输入的每个参数对应到函数中,再调用对应的指令。
运行结果如下:
psh2
- 比起psh1来,多了循环判断,不退出的话就会一直要你输入指令。
运行结果如下:
testbuf1:
- 效果是先输出hello,然后换行。之后不退出。
运行结果如下:
testbuf2
- 效果同上
- 由此可知:fflush(stdout)的效果和换行符\n是一样的。
testbuf3
- 代码分析:将内容格式化输出到标准错误、输出流中。
运行结果如下:
20145312 《信息安全系统设计基础》第12周学习总结
代码总结
testpid
- 代码分析:输出当前进程pid和当前进程的父进程的pid。
运行结果如下:
testsystem
- 代码分析:system()——执行shell命令,也就是向dos发送一条指令。这里是后面可以跟两个参数,然后向dos发送这两个命令,分别执行。如下图,输入ls和dir两个指令后,可以看到分别执行了。
运行结果如下:
waitdemo1
- 代码分析:如果有子进程,则终止子进程,成功返回子进程pid。
运行结果如下:
waitdemo2
- 代码分析:这个比起waitdemo1来就是多了一个子进程的状态区分,把状态拆分成三块,exit,sig和core。