信息安全系统设计基础第十二周学习总结
1.argv(文件夹)-argtest.c文件
#include <stdio.h>
#include <stdlib.h>#include "argv.h"//该函数库中包括freemakeargv.c及makeargv.c函数的调用int main(int argc, char *argv[])
{ char delim[] = " \t";//制表符 int i; char **myargv;//见下方解释 int numtokens;if (argc != 2)//如果输入的命令字符个数不等于2,就输出标准错误
{ fprintf(stderr, "Usage: %s string\n", argv[0]); return 1; } if ((numtokens = makeargv(argv[1], delim, &myargv)) == -1) { fprintf(stderr, "Failed to construct an argument array for %s\n", argv[1]);//翻译过来就是无法构造一个参数数组 return 1; } printf("The argument array contains:\n"); for (i = 0; i < numtokens; i++) printf("%d:%s\n", i, myargv[i]); execvp(myargv[0], myargv);return 0;
}另附加 freemakeargv.c及makeargv.c函数#include <stdlib.h>
#include "argv.h"void freemakeargv(char **argv) {
if (argv == NULL) return; if (*argv != NULL) free(*argv); free(argv);}/*-----------------------------------------------------------------------------*/#include <errno.h>#include <stdlib.h>#include <string.h>#include "argv.h"int makeargv(const char *s, const char *delimiters, char ***argvp)//见下方解释
{ int error; int i; int numtokens; const char *snew; char *t;if ((s == NULL) || (delimiters == NULL) || (argvp == NULL))
{ errno = EINVAL; return -1; } *argvp = NULL;//把字符串数组置为空 snew = s + strspn(s, delimiters);//返回字符串s开头连续包含字符串delimiters内的字符数目 if ((t = malloc(strlen(snew) + 1)) == NULL) return -1; strcpy(t, snew); numtokens = 0; if (strtok(t, delimiters) != NULL)//关于strtok函数的用法见下方 for (numtokens = 1; strtok(NULL, delimiters) != NULL; numtokens++) ;if ((*argvp = malloc((numtokens + 1)*sizeof(char *))) == NULL)
{//malloc函数请求分配了numtokens+1个字节的空间;如果是返回值是NULL说明分配不成功 error = errno; free(t);//释放malloc函数给指针变量分配的内存空间的函数。使用后该指针变量一定要重新指向NULL。 errno = error; return -1; } if (numtokens == 0) free(t); else { strcpy(t, snew); **argvp = strtok(t, delimiters); for (i = 1; i < numtokens; i++) *((*argvp) + i) = strtok(NULL, delimiters); } *((*argvp) + numtokens) = NULL; return numtokens;} 关于该系列代码的难点理解【1.为什么是* *myargv?】
经过查阅得知,比较准确的说法是: **相相当于二级指针,char **就是指向字符型指针的指针。最常使用的地方就是 int main(int argc,char **argv),相当于int main(int argc,char *argv[])。也就是说,可以看作是指向了字符串数组
【2.为什么是 int makeargv(const char *s, const char *delimiters, char * **argvp)】
把最后一个参数理解为向字符串数组取地址(从左到右,第一个代表取地址,后两个 **代表上文中说过的字符串数组)
【3.关于strtok函数?】
strtok函数用来将字符串分割成一个个片段,它的原型是char *strtok(charr s[],const char *delim)。只要在s中遇到delim中包含的字符(不一定是delim),就把这个字符改成\0。每次调用成功后返回的都是被分割出的片段的指针。
【4.errno与error?】
前者是记录系统最后一次错误的函数;后者是系统错误
2.env文件夹-environ.c文件
#include <stdio.h>
#include <stdlib.h>int main(void)
{ printf("PATH=%s\n", getenv("PATH"));//getenv函数用来取得参数PATH环境变量的值,执行成功则返回该内容的指针 setenv("PATH", "hello", 1);//见下方解释 printf("PATH=%s\n", getenv("PATH"));#if 0 printf("PATH=%s\n", getenv("PATH")); setenv("PATH", "hellohello", 0); printf("PATH=%s\n", getenv("PATH")); printf("MY_VER=%s\n", getenv("MY_VER"));//版本 setenv("MY_VER", "1.1", 0); printf("MY_VER=%s\n", getenv("MY_VER"));#endif return 0;}【setenv函数的作用?】setenv用来在本次函数运行的过程中增加或者修改环境变量。当最后一个参数不为0的时候,原来的内容会被修改为第二个参数所指的内容。
3.env文件夹-environvar.c文件
#include <stdio.h>
int main(void){ extern char **environ; int i; for(i = 0; environ[i] != NULL; i++) printf("%s\n", environ[i]);return 0;
}【environ变量是什么?】该变量指向一个叫“environment”的字符串数组。包括USER(登录用户的名字),LOGNAME(与user类似),HOME(用户登录目录),LANG(地域名),PATH等
4.pipe文件夹-consumer.c文件
#include <stdio.h>
#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <limits.h>#include <sys/types.h>#include <sys/stat.h>#define FIFO_NAME "/tmp/myfifo"
#define BUFFER_SIZE PIPE_BUFint main(){ int pipe_fd;int res;int open_mode = O_RDONLY;
char buffer[BUFFER_SIZE + 1];int bytes = 0;memset(buffer, 0, sizeof(buffer));
printf("Process %d opeining FIFO O_RDONLY \n", getpid());
pipe_fd = open(FIFO_NAME, open_mode);printf("Process %d result %d\n", getpid(), pipe_fd);if (pipe_fd != -1) {
do { res = read(pipe_fd, buffer, BUFFER_SIZE); bytes += res; } while (res > 0); close(pipe_fd);} else { exit(EXIT_FAILURE);}printf("Process %d finished, %d bytes read\n", getpid(), bytes);
exit(EXIT_SUCCESS);}【1.PIPE_BUF的值是多少?】4096字节
【2.memset函数用法?】
原型:memset(void *s,int ch,size_t n);将s中前n个字节用ch替换并返回s
【3.open函数用法?】
open(const char *pathname,int flags);第一个参数是欲打开的文件路径字符串,第二个参数是打开方式
【4.FIFONAME是什么?】
这里需要补充一下fifo的含义,它是一种文件类型,可以通过查看文件stat结构中的stmode成员的值来判断文件是否是FIFO文件。fifo是用来在进程中使用文件来传输数据的,也具有管道特性,可以在数据读出的时候清除数据。
5.env文件夹-producer文件
#include <stdio.h>
#include <stdlib.h>#include <string.h>#include <fcntl.h>#include <limits.h>#include <sys/types.h>#include <sys/stat.h>#define FIFO_NAME "/tmp/myfifo"
#define BUFFER_SIZE PIPE_BUF#define TEN_MEG (1024 * 1024 * 10)int main()
{ int pipe_fd;int res;int open_mode = O_WRONLY;int bytes = 0;
char buffer[BUFFER_SIZE + 1];if (access(FIFO_NAME, F_OK) == -1) {//检查文件是否有相应的权限
res = mkfifo(FIFO_NAME, 0777);//依据FIFO_NAME创建fifo文件,0777依次是相应权限 if (res != 0) { fprintf(stderr, "Could not create fifo %s \n", FIFO_NAME); exit(EXIT_FAILURE); }}printf("Process %d opening FIFO O_WRONLY\n", getpid());
pipe_fd = open(FIFO_NAME, open_mode);printf("Process %d result %d\n", getpid(), pipe_fd);if (pipe_fd != -1) {
while (bytes < TEN_MEG) { res = write(pipe_fd, buffer, BUFFER_SIZE); if (res == -1) { fprintf(stderr, "Write error on pipe\n"); exit(EXIT_FAILURE); } bytes += res; } close(pipe_fd);} else { exit(EXIT_FAILURE);}printf("Process %d finish\n", getpid());
exit(EXIT_SUCCESS);}
6.env文件夹-testmf.c文件
#include <stdio.h>
#include <stdlib.h>#include <sys/types.h>#include <sys/stat.h>int main()//就是创建fifo文件
{ int res = mkfifo("/tmp/myfifo", 0777); if (res == 0) { printf("FIFO created \n"); } exit(EXIT_SUCCESS);}(修改testmf.c代码)
(修改之后的执行结果)
7.pipe文件夹-pipe.c文件#include <stdio.h>
#include<stdlib.h>#include <unistd.h>#define oops(m,x) //当linux系统执行代码遇到问题时,就会报告oops
{ perror(m); exit(x); }int main(int ac, char **av)
{ int thepipe[2], newfd,pid;if ( ac != 3 ){//输入的命令长度不等于3
fprintf(stderr, "usage: pipe cmd1 cmd2\n"); exit(1); } if ( pipe( thepipe ) == -1 ) //以下是各种错误 oops("Cannot get a pipe", 1);if ( (pid = fork()) == -1 )
oops("Cannot fork", 2);if ( pid > 0 ){
close(thepipe[1]);if ( dup2(thepipe[0], 0) == -1 )
oops("could not redirect stdin",3);close(thepipe[0]);
execlp( av[2], av[2], NULL); oops(av[2], 4); }close(thepipe[0]);
if ( dup2(thepipe[1], 1) == -1 )
oops("could not redirect stdout", 4);close(thepipe[1]);
execlp( av[1], av[1], NULL); oops(av[1], 5);}8.pipe文件夹-stdinredir1.c文件
#include <stdio.h>
#include <fcntl.h>int main()
{ int fd ; char line[100];fgets( line, 100, stdin ); printf("%s", line );//就是打印输入的字符串
fgets( line, 100, stdin ); printf("%s", line ); fgets( line, 100, stdin ); printf("%s", line );close(0);
fd = open("/etc/passwd", O_RDONLY); if ( fd != 0 ){//打开或者创建失败的时候才会执行 fprintf(stderr,"Could not open data as fd 0\n"); exit(1); }fgets( line, 100, stdin ); printf("%s", line );
fgets( line, 100, stdin ); printf("%s", line ); fgets( line, 100, stdin ); printf("%s", line );}9.pipe文件夹-testtty.c文件
#include <unistd.h>
int main(){ char *buf = "abcde\n"; write(0, buf, 6);}【write函数】write(int handle,void *buf,int nbyte); 第一个参数是文件描述符,第二个参数是指向一端内存单元的指针,第三个参数是要写入指定文件的字节个数;成功时返回字节个数,否则返回-1。
10.signal文件夹-sigactdemo1.c文件
#include <stdio.h>
#include<unistd.h>#include <signal.h>#define INPUTLEN 100void inthandler(); int main(){ struct sigaction newhandler;//见下方解释 sigset_t blocked; //信号集,用来描述信号的集合,与信号阻塞相关函数配合使用 char x[INPUTLEN]; newhandler.sa_handler = inthandler; //函数指针 newhandler.sa_flags = SA_RESTART|SA_NODEFER |SA_RESETHAND; //sa_flags是一个位掩码。这里,第一个参数使得被信号打断的一些原语“正常返回” sigemptyset(&blocked); sigaddset(&blocked, SIGQUIT); newhandler.sa_mask = blocked; if (sigaction(SIGINT, &newhandler, NULL) == -1) perror("sigaction"); else while (1) { fgets(x, INPUTLEN, stdin); printf("input: %s", x); } return 0;}void inthandler(int s){ printf("Called with signal %d\n", s); sleep(s * 4); printf("done handling signal %d\n", s);}具体参见http://www.cnblogs.com/gogly/articles/2416989.html【sigaction结构体,用来查询或设置信号处理方式。比如它指定了对特定信号的处理,信号所传递的信息,信号处理函数执行过程中应该屏蔽掉哪些函数等。】
11.signal文件夹-sigdemo1.c文件夹
#include <stdio.h>
#include <signal.h>void f(int); int main(){ int i; signal( SIGINT, f ); for(i=0; i<5; i++ ){ printf("hello\n"); sleep(2); }return 0;
}void f(int signum)
{ printf("OUCH!\n");}这样的代码是无法在输出的时候体现出对f的调用的。我认为其中signal( SIGINT, f );这一句中,因为f的返回值是“void”,所以无法体现。补充:signal函数,原型 signal(参数1,参数2);,其中参数1是我们进行处理的信号,参数2是我们处理的方式。
后来我对代码进行了修改,体现了对f函数的调用
12.signal文件夹-sigdemo3.c文件
#include <stdio.h>
#include<string.h>#include <signal.h>#include<unistd.h>#define INPUTLEN 100
int main(int argc, char *argv[])
{ void inthandler(int); void quithandler(int); char input[INPUTLEN]; int nchars;signal(SIGINT, inthandler);//^C
signal(SIGQUIT, quithandler);//^\do {//输入什么,就输出什么(在read函数不发生错误的情况下)
printf("\nType a message\n"); nchars = read(0, input, (INPUTLEN - 1)); if (nchars == -1) perror("read returned an error"); else { input[nchars] = '\0'; printf("You typed: %s", input); } } while (strncmp(input, "quit", 4) != 0);//只有输入quit的时候才会退出 return 0;}void inthandler(int s)
{ printf(" Received signal %d .. waiting\n", s); sleep(2); printf(" Leaving inthandler \n");}void quithandler(int s)
{ printf(" Received signal %d .. waiting\n", s); sleep(3); printf(" Leaving quithandler \n");}13.exec3.c文件
#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");// execv( "/bin/ls" , arglist );// execvp( "ls" , arglist );// execvpe("ls" , arglist, myenv);execlp("ls", "ls", "-l", NULL);
printf("* * * ls is done. bye\n");}【execlp函数?】从PATH环境变量中查找文件并执行。原型:int execlp(const char *file,const char *arg,……); 从PATH环境变量所指的目录中查找符号参数file的文件名,然后将第二个及以后的参数当作该文件的argv[0],argv[1],……,最后一个参数必须用NULL结束。
【execv函数?】
原型:int execv(const char *pathname,char *const argv[]);装入并运行其他程序 对比:execvp函数原型: int execvp(const char *file,char *const argv[]);