Linux进程控制编程

任务1:

要求:

编写一个进程创建实验程序task51.c,创建如图所示的进程族亲结构,其中p1是程序启动时由加载程序创建第一个进程。各进程的输出信息分别如下:

      p1:I am father process

      p11: 当前时间是< 年 月 日 时 分 秒>

      p12: I am young brother process

      p121:我的学号是<您的学号xxx>

      p122:我的姓名是<您的姓名xxx>

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
int main()
{
    int p11, p12, p121, p122;
    struct tm *newtime;
    time_t t;
    char str[80];
    p11 = fork();
    if (p11 > 0)
        printf("p1:I am fatherprocess\n");
    if (p11 == 0)
    {
        t = time(NULL);
        newtime = localtime(&t);
        strftime(str, 100, "p11:当前时间是<%Y年%m月%d日%H时%M分%S秒>\n", newtime);
        printf("%s", str);
        exit(0);
    }
    else
    {
        p12 = fork();
        if (p12 == 0)
        {
            printf("p12:I am young brother process\n");
            p121 = fork();
            if (p121 == 0)
            {
                printf("p121:我的学号是<201944>\n");
                exit(0);
            }
            else
            {
                p122 = fork();
                if (p122 == 0)
                {
                    printf("p122:我的姓名是<泠霖凛>\n");
                    exit(0);
                }
                exit(0);
            }
        }
        exit(0);
    }
}

任务2:

要求:

参考教材shellex.c代码,实现一个简单的交互式shell程序task52.c,具备的功能至少有:

(1)打印提示符%;获取用户输入指令;解析指令;寻找命令文件,执行指令

(1)显示命令提示符%;

(2)获取用户输入指令;解析指令;寻找命令文件,执行指令;

(3)前一个命令完成后才继续显示命令提示符%,等待用户输入下一条命令;

(3)如果输入“exit”或“logout”,则退出shell.

(4)允许命令参数间有多个空格,也允许命令前后有空格

(5)支持输出重定向和管道功能。

设计思想:

    当输入“Gdup”后,会进入Gdup函数,该函数通过重定向和管道命令传输特定的数据。

源代码:

#include "wrapper.h"
void execute(char *cmdline);
int builtin_command(char **argv);
int parseline(char *buf, char **argv);
void Gdup();
int main()
{
    char cmdline[MAXLINE]; /* 命令行缓冲区 */
    while (1)
    {
        printf("%%");
        fgets(cmdline, MAXLINE, stdin); /* 读取命令行 */
        if (feof(stdin))
            exit(0);
        execute(cmdline); /* 执行命令 */
    }
}
void execute(char *cmdline)
{
    char *argv[MAXLINE]; /*execve()参数表 */
    char buf[MAXLINE];   /* 保存修改后的命令行 */
    int bg;              /* 是否在后台执行 */
    pid_t pid;           /* 子进程PID*/
    strcpy(buf, cmdline);
    bg = parseline(buf, argv); /* 解析命令行 */
    if (argv[0] == NULL)
        return; /* 如果第1个参数为空,则忽略命令 */
    if (!builtin_command(argv))
    {
        if ((pid = fork()) == 0)
        { /* 创建子进程 */
            if (execvp(argv[0], argv) < 0)
            {
                printf("%s:Command not found.\n", argv[0]);
                exit(0);
            }
        }
        if (!bg)
        { /* 前台执行 */
            int status;

            if (waitpid(pid, &status, 0) < 0)
                perror("waitpid error");
        }
        else
            printf("%d%s", pid, cmdline);
    }
    return;
}
/* 判断和执行内置命令 */
int builtin_command(char **argv)
{
    if (!strcmp(argv[0], "exit")) /* 内置命令exit */
        exit(0);
    if (!strcmp(argv[0], "logout")) /* 内置命令logout */
        exit(0);
    if (!strcmp(argv[0], "Gdup"))
    { /* 重定向 */
        Gdup();
        return 1;
    }
    if (!strcmp(argv[0], "&")) /* 忽略由&开始的命令串 */
        return 1;
    return 0; /* 非内置命令 */
}
void Gdup()
{
    int fds[2];
    const char data[] = "已经得到数据!";
    char buf[1024];
    pid_t pid;
    pipe(fds);
    pid = fork();
    if (pid == 0)
    {
        dup(0);
        close(0);
        dup(fds[0]);
        read(fds[0], buf, 1024);
        printf("\b%s\n", buf);
        close(fds[0]);
        close(fds[1]);
    }
    else
    {
        close(fds[0]);
        write(fds[1], data, strlen(data));
        printf("重定向后数据通过管道发送完成!\n");
        close(fds[1]);
        dup2(4, 0);
    }
}
int parseline(char *buf, char **argv)
{
    char *delim;                  /* 指向第1个分隔符 */
    int argc;                     /* 字符串数组args中命令行参数个数 */
    int bg;                       /* 后台作业 */
    buf[strlen(buf) - 1] = ' ';   /* 用空格替换行末换行符 */
    while (*buf && (*buf == ' ')) /* 删除行首空格 */
        buf++;
    /* 创建 argv数组 */
    argc = 0;
    while ((delim = strchr(buf, ' ')))
    {
        argv[argc++] = buf;
        *delim = '\0';
        buf = delim + 1;
        while (*buf && (*buf == ' ')) /* 忽略空格,查找下一个参数起始位置 */
            buf++;
    }
    argv[argc] = NULL;
    if (argc == 0) /* 忽略空行*/
        return 1;
    /* 命令是否应在后台执行 */
    if ((bg = (*argv[argc - 1] == '&')) != 0)
        argv[--argc] = NULL;
    return bg;
}

任务3:

要求:

写一个子进程管理程序task54.c,借鉴sigmask.c方法管理子进程,父进程循环读取用户输入的操作命令,创建子进程、显示相关信息和终止子进程等。具体用户命令为:

1) 命令1:功能是创建一批子进程,格式为“create <进程数>” ,命令执行成功后,显示所有新创建子进程PID。比如“create 10”表示创建10个子进程,子进程执行的代码可以为:“while(1){};exit(100);”

2)命令2:终止一批子进程,格式为“kill <P1> <P2> …”(如“kill 123 456 789”为终止PID号为123、456、789的三个子进程),子进程显示“killed by parent”后终止,父进程通过SIGCHLD信号处理程序等待子进程终止,显示终止的子进程PID。

3)命令3:显示当前子进程列表,命令格式为:“ps  -u”

4)命令4:父进程终止命令,格式为“exit”,当所有子进程都结束后,才允许执行该命令。

#include "wrapper.h"
#include <sys/stat.h>

int hashCode;
int fileInfo_daemon(void)
{
    pid_t pid;
    FILE *fp;
    int fd;
    struct stat buf;
    char rd[4];
    int i;
    pid = fork(); /*创建新的进程*/
    if (pid == -1)
        return -1;
    else if (pid != 0)
        exit(EXIT_SUCCESS);

    fp = fopen("data.txt", "r");
    if (NULL != fp)
    {

        int tempHashcode = 0;
        while ((fread(rd, sizeof(char), 4, fp)) != 0)
        {
            for (i = 0; i < sizeof(rd); i++)
                tempHashcode += (int)rd[i];
        }
        printf("Hashcode = %d\n", tempHashcode);
        fd = fileno(fp);
        fstat(fd, &buf);
        int size = buf.st_size;          //get file size (byte)
        long access_time = buf.st_atime; //latest access time
        long modify_time = buf.st_mtime; //latest modification time (seconds passed from 01/01/00:00:00 1970 UTC)
        printf("size = %d\n", size);
        printf("access_time = %ld\n", access_time);
        printf("modify_time = %ld\n", modify_time);
        fclose(fp);
        return modify_time;
    }
    printf("function error\n");
    return 0;
}

int main(void)
{
    while (1)
    {
        fileInfo_daemon();
        sleep(60);
    }
    return 0;
}

任务4:

要求:

写一个关键目录和关键文件属性与内容监控的daemon程序task5-3.c,该程序每隔1分钟读取目录/etc及其中所有文件的最后访问时间与最后修改时间,读取用户数据库文件/etc的内容,如有变化,则将变化情况如入日志文件,测试程序的正确性。提示:可监控文件内容是否修改,可由文件内容计算一个hash值(又称数字指纹),比较hash值是否发生变化,一种简单的hash值计算方法是将一个文件划分为一系列四字节整数,把各个整数相加的和作为hash值。

#include "wrapper.h"
#include <stdio.h>
#include <string.h>
void execute(char *cmdline);           /*执行命令*/
int builtin_command(char **argv);      /*检查是否为用户内置命令*/
int parseline(char *buf, char **argv); /*将命令切割成标准格式的若个部分*/
void create(int num);                  /*创建子进程num个*/
void Exit();
void stop();
void waitBack();
void MyKill(char **argv);
int n;
int mask;
static int count = 0; /*父进程下面的子进程数量,若为0才能调用Exit()函数*/

int main()
{
    char cmdline[MAXLINE]; /* 命令行缓冲区 */
    signal(SIGCHLD, waitBack);

    while (1)
    {
        printf("%%");
        fgets(cmdline, MAXLINE, stdin); /* 读取命令行 */
        if (feof(stdin))
            exit(0);

        execute(cmdline); /* 执行命令 */
        //usleep(100);/*每次执行完任务,就停止100微秒*/
    }
}

void execute(char *cmdline)
{
    char *argv[MAXLINE]; /*execve()参数表 */
    char buf[MAXLINE];   /* 保存修改后的命令行 */
    pid_t pid;           /* 子进程PID*/
    strcpy(buf, cmdline);
    parseline(buf, argv); /* 解析命令行 */
    if (argv[0] == NULL)
        return; /* 如果第1个参数为空,则忽略命令 */
    if (!builtin_command(argv))
    {
        if ((pid = fork()) == 0)
        { /* 创建一个临时进程,因为调用execvp后的进程就不会回来了 */
            count++;
            if (execvp(argv[0], argv) < 0)
            {
                printf("%s:Command not found.\n", argv[0]);
                exit(0); /*立即放弃该临时进程*/
            }
        }
        else
        {
            usleep(200);
            waitpid(pid, NULL, 0);
        }
    }
}
/* 判断和执行内置命令 */
int builtin_command(char **argv)
{
    if (!strcmp(argv[0], "exit"))
    { /* 内置命令exit */
        Exit();
        return 1;
    }

    if (!strcmp(argv[0], "create"))
    { /* 内置命令create */
        create(atoi(argv[1]));
        return 1;
    }
    if (!strcmp(argv[0], "kill"))
    { /* 内置命令kill */
        MyKill(argv);
        return 1;
    }
    if (!strcmp(argv[0], "&")) /* 忽略由&开始的命令串 */
        return 1;

    return 0; /* 非内置命令 */
}

int parseline(char *buf, char **argv)
{
    char *delim;                  /* 指向第1个分隔符 */
    int argc;                     /* 字符串数组args中命令行参数个数 */
    int bg;                       /* 后台作业 */
    buf[strlen(buf) - 1] = ' ';   /* 用空格替换行末换行符 */
    while (*buf && (*buf == ' ')) /* 删除行首空格 */
        buf++;
    /* 创建 argv数组 */
    argc = 0;
    while ((delim = strchr(buf, ' ')))
    {
        argv[argc++] = buf;
        *delim = '\0';
        buf = delim + 1;
        while (*buf && (*buf == ' ')) /* 忽略空格,查找下一个参数起始位置 */
            buf++;
    }
    argv[argc] = NULL;
    n = argc;      /*记录命令中出现的参数个数*/
    if (argc == 0) /* 忽略空行*/
        return 1;

    /* 命令是否应在后台执行 */
    if ((bg = (*argv[argc - 1] == '&')) != 0)
        argv[--argc] = NULL;
    return bg;
}
void create(int num)
{ /* 命令1:创建num个子进程 */
    int pid, i;
    if (num <= 0)
    {
        return;
    }
    if ((pid = fork()) > 0)
    {
        create(num - 1);
        count++;
        //printf("%d\n",count); //测试
    }
    else
    {
        signal(10, stop);
        printf("新创建的子进程PID=%d\n", getpid());
        mask = 1;
        while (mask)
            ; /*持续循环,等待终止信号10*/
        printf("%d killed by parent\n", getpid());
        exit(100);
    }
}
void MyKill(char **argv)
{
    int i = 1;
    while (i < n)
    {                            /*向命令中出现的所有Pid进程发送信号10*/
        kill(atoi(argv[i]), 10); /* 10 用户自定义信号,我定义为终止信号*/
        i++;
    }
    //sleep(1); //测试
}
void Exit()
{ /* 命令4 */
    if (count <= 0)
        exit(0);
    else
    {
        printf("error!还有子进程没有终止\n");
    }
}
void stop()
{ /*子进程停止循环*/
    mask = 0;
}
void waitBack()
{ /*父进程回收子进程资源,并显示子进程的pid*/
    int a;
    while ((a = waitpid(-1, NULL, 0)) > 0)
    {
        printf("终止的子进程PID=%d\n", a);
        count--;
        //printf("%d\n",count); //测试
    }
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值