c - 带有后台任务的 C shell
问题描述
我即将在 C 中实现一个 shell,我有一些问题。
它应该能够在前台或后台运行程序。如果在命令前输入“job”,它应该在后台运行,我想将这些后台任务组织在一个列表中。使用命令“list”,所有后台任务都应显示在命令行上。
如果我使用作业命令添加一些后台任务,我会遇到 pid 始终为 0 的问题,例如当我添加两个任务然后执行 list-command 时,两者的 pid 都是 0。我的错误是什么?
另一个问题是,我想为新的列表元素设置属性“命令”,但列表中每个元素的命令总是会设置为这个值。我在这里错在哪里?我该如何解决这个问题?
这是我的代码:
shell.c(主类):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include "dll.h"
#define MAXIMUM_INPUT 256
struct proc_info {
struct list_head head;
pid_t pid;
char* command;
char* running;
int number;
int status;
};
void print_procs(struct proc_info *proc_list);
void executecmd(char* command);
int makeargv(const char *s, const char *delimiters, char ***argvp);
void freemakeargv(char **argv);
int main() {
//Initialize list
struct list_head anchor;
list_init(&anchor);
int count = 0;
char input[256];
pid_t newProcess;
while(1) {
//Prompt
printf("tsh> ");
//Read input
if (fgets(input, 256, stdin) == NULL)
continue;
int len = strlen(input);
if(len == 1) //Only the "\n", fgets puts "\n" at the end of the string
continue;
else if (input[len - 1] == '\n')
input[len - 1] = 0;
//Make a list of strings with each argument out of the string of all arguments
char** args;
makeargv(input , " ", &args);
char* firstArgument = *args;
if(strcmp(firstArgument, "job") == 0) {
char *command;
strncpy(command, input+4, len-4);
struct proc_info *new_proc;
new_proc = malloc(sizeof(struct proc_info));
new_proc->command = command;
new_proc->number = count;
new_proc->running = "running";
count++;
list_add_tail(&(new_proc->head), &anchor);
if ((newProcess = fork()) == -1)
perror("Error when trying to fork");
else if (newProcess == 0) {
new_proc->pid = getpid();
execvp(args[1], args+1);
perror("Cannot execute command");
printf("tsh>");
exit(1);
}
} else if(strcmp(firstArgument, "list") == 0) {
print_procs((struct proc_info *) &anchor);
} else if(strcmp(firstArgument, "info") == 0) {
printf("ToDo");
} else if(strcmp(firstArgument, "wait") == 0) {
printf("ToDo");
} else if(strcmp(firstArgument, "kill") == 0) {
printf("ToDo");
} else if(strcmp(firstArgument, "quit") == 0) {
return 0;
} else {
int status = system(input);
if(status != 0) {
printf("--->[invalid command]<---\n");
}
printf("--->[status=%d]<---\n", status);
}
//Free allocated memory for the arguments
freemakeargv(args);
}
}
void print_procs(struct proc_info *proc_list) {
struct proc_info *elem = proc_list;
elem = (struct proc_info *) elem->head.next;
printf(" No | PID | Running | Status | Command\n");
while(proc_list != elem) {
printf("%3d | %6d | %8s | %6d | %s\n", elem->number, elem->pid, elem->running, elem->status, elem->command);
elem = (struct proc_info *) elem->head.next;
}
}
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); /* snew is real start of string */
if ((t = malloc(strlen(snew) + 1)) == NULL)
return -1;
strcpy(t, snew);
numtokens = 0;
if (strtok(t, delimiters) != NULL) /* count the number of tokens in s */
for (numtokens = 1; strtok(NULL, delimiters) != NULL; numtokens++) ;
/* create argument array for ptrs to the tokens */
if ((*argvp = malloc((numtokens + 1)*sizeof(char *))) == NULL) {
error = errno;
free(t);
errno = error;
return -1;
}
/* insert pointers to tokens into the argument array */
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; /* put in final NULL pointer */
return numtokens;
}
void freemakeargv(char **argv) {
if (argv == NULL)
return;
if (*argv != NULL)
free(*argv);
free(argv);
}
dll.c:
#include <stdlib.h>
#include <stdio.h>
#include "dll.h"
/* initialize "shortcut links" for empty list */
void
list_init(struct list_head *head)
{
head->prev = head;
head->next = head;
}
/* insert new entry after the specified head */
void
list_add(struct list_head *new, struct list_head *head)
{
new->prev = head;
new->next = head->next;
head->next = new;
new->next->prev = new;
}
/* insert new entry before the specified head */
void
list_add_tail(struct list_head *new, struct list_head *head)
{
//Insterting before head is equal to inserting after the previous of the head
list_add(new, head->prev);
}
/* deletes entry from list and reinitialize it, returns pointer to entry */
struct list_head*
list_del(struct list_head *entry)
{
struct list_head *previous = entry->prev;
struct list_head *following = entry->next;
previous->next = following;
following->prev = previous;
entry->prev = NULL;
entry->next = NULL;
return entry;
}
/* delete entry from one list and insert after the specified head */
void
list_move(struct list_head *entry, struct list_head *head)
{
list_add(list_del(entry), head);
}
/* delete entry from one list and insert before the specified head */
void
list_move_tail(struct list_head *entry, struct list_head *head)
{
list_add_tail(list_del(entry), head);
}
/* tests whether a list is empty */
int
list_empty(struct list_head *head)
{
return (head == head->prev && head == head->next);
}
dll.h:
#ifndef DLL_H
#define DLL_H
struct list_head {
struct list_head *next, *prev;
};
/* initialize "shortcut links" for empty list */
extern void
list_init(struct list_head *head);
/* insert new entry after the specified head */
extern void
list_add(struct list_head *new, struct list_head *head);
/* insert new entry before the specified head */
extern void
list_add_tail(struct list_head *new, struct list_head *head);
/* deletes entry from list and reinitialize it, returns pointer to entry */
extern struct list_head*
list_del(struct list_head *entry);
/* delete entry from one list and insert after the specified head */
extern void
list_move(struct list_head *entry, struct list_head *head);
/* delete entry from one list and insert before the specified head */
extern void
list_move_tail(struct list_head *entry, struct list_head *head);
/* tests whether a list is empty */
extern int
list_empty(struct list_head *head);
#endif
解决方案
错误是,您在孩子中设置了进程ID
if ((newProcess = fork()) == -1)
perror("Error when trying to fork");
else if (newProcess == 0) {
// This is executed in the CHILD PROCESS!!
new_proc->pid = getpid();
execvp(args[1], args+1);
perror("Cannot execute command");
printf("tsh>");
exit(1);
}
子进程不与父进程共享内存,因此信息不会自动传输到父进程。你必须在你的 if-block 之后添加这个:
new_proc->pid = newProcess;
这样子 pid 就保存在主进程中。
对于command
-issue:指针未初始化:
char *command;
strncpy(command, input+4, len-4);
您必须在复制到它之前分配内存并确保结果以空字节终止:
char *command = malloc(len-4+1);
strncpy(command, input+4, len-4);
command[len-4] = '\0';
推荐阅读
- angular - 错误 TS2345:“书籍”类型的参数不可分配给“书籍”类型的参数
- ruby - 结合`bundle exec`和`ruby -r`的正确方法?
- python - MySQL 服务器已经消失:一个 API 抛出它,而另一个没有
- html - 在 CSS ::after 之后放置一个 div
- video - 如何在不提高播放速度的情况下使用 ffmpeg 将 mjpeg 直播视频格式转换为 h.264 格式
- bash - 分配给 bash 脚本中变量的 ipv6 值行为错误
- c++ - QTableView 拉伸标题但保持交互
- c++ - C++ 中的对象和类有问题
- r - 如何在 r 的数据框中使用“for loop”
- python - Pygame:圆形物体有虚拟属性吗?