📄 jobctrl.c
字号:
#include "jobctrl.h"
#include "cmd.h"
#include <pwd.h>
#if !defined (savestring)
# define savestring(x) (char *)strcpy (malloc (1 + strlen (x)), (x))
#endif
/* The current host's name. */
static char *current_host_name = NULL;
/* Information about the current user. */
static struct {
uid_t uid, euid;
gid_t gid, egid;
char *user_name;
char *curr_dir;
char prompt[3];
} current_user;
static void get_current_user_info()
{
struct passwd *entry;
if (current_host_name == 0) {
char hostname[BUFF_SIZE];
/* Initialize current_host_name. */
if (gethostname (hostname, BUFF_SIZE) < 0)
current_host_name = "??host??";
else
current_host_name = savestring(hostname);
/* Don't fetch this more than once. */
current_user.uid = getuid();
current_user.gid = getgid();
current_user.euid = geteuid();
current_user.egid = getegid();
entry = getpwuid (current_user.uid);
if (entry)
current_user.user_name = savestring(entry->pw_name);
current_user.prompt[0] = '@';
current_user.prompt[1] = ' ';
endpwent();
}
}
static void prompt()
{
char path[BUFF_SIZE];
get_current_user_info();
getcwd(path, BUFF_SIZE);
if (strlen(path) > 1) {
current_user.curr_dir = strrchr(path, '/');
current_user.curr_dir++;
}
else {
current_user.curr_dir = path;
}
fprintf(stdout, "[%s@%s %s]%s",
current_user.user_name,
current_host_name,
current_user.curr_dir,
current_user.prompt);
}
static int setup_redirections(PROCESS *prog)
{
int i;
int openfd;
int mode;
struct redirection_specifier *redir = prog->redirections;
for (i = 0; i < prog->num_redirections; i++, redir++) {
switch (redir->type) {
case REDIRECT_READ:
mode = O_RDONLY;
break;
case REDIRECT_OVERWRITE:
mode = O_RDWR | O_CREAT | O_TRUNC;
break;
case REDIRECT_APPEND:
mode = O_RDWR | O_CREAT | O_APPEND;
break;
case REDIRECT_READWRITE:
mode = O_RDWR;
break;
}
openfd = open(redir->filename, mode, 0666);
if (openfd < 0) {
fprintf(stderr, "error opening %s: %s\n",
redir->filename, strerror(errno));
return 1;
}
if (openfd != redir->fd) {
dup2(openfd, redir->fd);
close(openfd);
}
}
return 0;
}
int get_cmd(FILE *source, char *command)
{
if (source == stdin) {
prompt();
fflush(stdout);
}
if (!fgets(command, MAX_COMMAND_LEN, source)) {
if (source == stdin)
printf("\n");
return 1;
}
command[strlen(command) - 1] = '\0'; /* erase character '/n' */
return 0;
}
void free_job(JOB *cmd)
{
int i;
for (i = 0; i < cmd->num_progs; i++) {
free(cmd->progs[i].argv);
if (cmd->progs[i].redirections)
free(cmd->progs[i].redirections);
if (cmd->progs[i].free_glob)
globfree(&cmd->progs[i].glob_result);
}
free(cmd->progs);
if (cmd->text)
free(cmd->text);
free(cmd->cmd_buf);
}
int run_command(JOB new_job, CHAIN *job_list, int inbg)
{
JOB *job;
int i;
int nextin, nextout;
int pipefds[2];
nextin = STDIN_FILENO, nextout = STDOUT_FILENO;
for (i = 0; i < new_job.num_progs; i++) {
if ((i + 1) < new_job.num_progs) {
pipe(pipefds);
nextout = pipefds[1];
}
else {
nextout = STDOUT_FILENO;
}
new_job.progs[i].pid = getpid();
/* Some commands affect main process and don't support pipeline. */
if (!strcmp(new_job.progs[i].argv[0], "exit")) {
m_exit(job_list);
}
else if (!strcmp(new_job.progs[i].argv[0], "cd")) {
m_cd(new_job.progs[i].argv);
}
else if (!strcmp(new_job.progs[0].argv[0], "more")) {
m_more(new_job.progs[0].argv);
}
else if (!strcmp(new_job.progs[i].argv[0], "fg") ||
!strcmp(new_job.progs[i].argv[0], "bg")) {
m_fgbg(new_job.progs[i].argv);
}
/* handle fork command here */
else if (!(new_job.progs[i].pid = fork())) {
signal(SIGTTOU, SIG_DFL);
signal(SIGINT, SIG_DFL);
signal(SIGTSTP, SIG_DFL);
if (nextin != STDIN_FILENO) {
dup2(nextin, STDIN_FILENO);
close(nextin);
}
if (nextout != STDOUT_FILENO) {
dup2(nextout, STDOUT_FILENO);
close(nextout);
}
/* override pipeline */
setup_redirections(new_job.progs + i);
if (!strcmp(new_job.progs[i].argv[0], "copy")) {
m_copy(new_job.progs[i].argv);
}
else if (!strcmp(new_job.progs[i].argv[0], "date")) {
m_date(new_job.progs[i].argv);
}
else if (!strcmp(new_job.progs[i].argv[0], "del")) {
m_del(new_job.progs[i].argv);
}
else if (!strcmp(new_job.progs[i].argv[0], "dir")) {
m_dir(new_job.progs[i].argv);
}
else if (!strcmp(new_job.progs[i].argv[0], "find")) {
m_find(new_job.progs[i].argv);
}
else if (!strcmp(new_job.progs[i].argv[0], "jobs")) {
m_jobs(new_job.progs[i].argv);
}
else if (!strcmp(new_job.progs[i].argv[0], "md")) {
m_md(new_job.progs[i].argv);
}
else if (!strcmp(new_job.progs[i].argv[0], "pwd")) {
m_pwd(NULL);
}
else if (!strcmp(new_job.progs[i].argv[0], "time")) {
m_time(new_job.progs[i].argv);
}
else if (!strcmp(new_job.progs[i].argv[0], "ren")) {
m_ren(new_job.progs[i].argv);
}
else {
execvp(new_job.progs[i].argv[0], new_job.progs[i].argv);
/* fprintf(stderr, "exec() of %s failed: %s\n",
new_job.progs[i].argv[0], strerror(errno));
*/
fprintf(stderr, " %s: command not found\n",
new_job.progs[i].argv[0]);
}
exit(1);
}
if (nextin != STDIN_FILENO)
close(nextin);
if (nextout != STDOUT_FILENO)
close(nextout);
nextin = pipefds[0];
}
new_job.pgrp = new_job.progs[0].pid;
new_job.id = 1;
for (job = job_list->head; job; job = job->next)
if (job->id >= new_job.id)
new_job.id = job->id + 1;
if (!job_list->head) {
job = job_list->head = malloc(sizeof(*job));
}
else {
for (job = job_list->head; job->next; job = job->next);
job->next = malloc(sizeof(*job));
job = job->next;
}
*job = new_job;
job->next = NULL;
job->running_progs = job->num_progs;
job->stopped_progs = 0;
if (inbg) {
printf("[%d] %d\n", job->id,
new_job.progs[new_job.num_progs - 1].pid);
}
else {
job_list->fg = job;
}
return 0;
}
void remove_job(CHAIN *job_list, JOB *job)
{
struct job *prev_job;
free_job(job);
if (job == job_list->head) {
job_list->head = job->next;
}
else {
prev_job = job_list->head;
while (prev_job->next != job)
prev_job = prev_job->next;
prev_job->next = job->next;
}
free(job);
}
void check_jobs(CHAIN *job_list)
{
struct job *job;
pid_t childpid;
int status;
int prog_num;
while ((childpid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) {
for (job = job_list->head; job; job = job->next) {
prog_num = 0;
while (prog_num < job->num_progs &&
job->progs[prog_num].pid != childpid)
prog_num++;
if (prog_num < job->num_progs)
break;
}
if (WIFEXITED(status) || WIFSIGNALED(status)) {
job->running_progs--;
job->progs[prog_num].pid = 0;
if (!job->running_progs) {
printf(JOB_STATUS_FORMAT, job->id, "Done", job->text);
remove_job(job_list, job);
}
}
else {
job->stopped_progs++;
job->progs[prog_num].is_stopped = 1;
if (job->stopped_progs == job->num_progs) {
printf(JOB_STATUS_FORMAT, job->id, "Stopped", job->text);
}
}
}
if (childpid == -1 && errno != ECHILD)
perror("waitpid");
}
/* find match patten, see glob() */
static void glob_argument(PROCESS *prog, int *argc_ptr,
int *argc_alloced_ptr)
{
int argc = *argc_ptr;
int argc_alloced = *argc_alloced_ptr;
int rc;
int flags;
int i;
char *src, *dst;
if (argc > 1) {
flags = GLOB_APPEND;
i = prog->glob_result.gl_pathc;
}
else {
prog->free_glob = 1;
flags = 0;
i = 0;
}
rc = glob(prog->argv[argc-1], flags, NULL, &prog->glob_result);
if (rc == GLOB_NOSPACE) {
fprintf(stderr, "out of space during glob operation\n");
return ;
}
else if(rc == GLOB_NOMATCH ||
(!rc && (prog->glob_result.gl_pathc - i) == 1 &&
!strcmp(prog->argv[argc - 1],
prog->glob_result.gl_pathv[i]))) {
src = dst = prog->argv[argc-1];
while (*src) {
if (*src != '\\')
*dst++ = *src;
src++;
}
*dst = '\0';
}
else if (!rc) {
argc_alloced += (prog->glob_result.gl_pathc - i);
prog->argv = realloc(prog->argv, argc_alloced*sizeof(*prog->argv));
memcpy(prog->argv + (argc - 1), prog->glob_result.gl_pathv + i,
sizeof(*(prog->argv)) * (prog->glob_result.gl_pathc - i));
argc += (prog->glob_result.gl_pathc - i - 1);
}
*argc_alloced_ptr = argc_alloced;
*argc_ptr = argc;
}
int parse_cmd(char **cmd_ptr, JOB *job, int *bg)
{
char *command;
char *return_cmd = NULL;
char *src, *buf, *chptr;
int argc = 0;
int done = 0;
int argv_alloced;
int i;
char quote = '\0';
int count;
PROCESS *prog;
while (**cmd_ptr && isspace(**cmd_ptr))
(*cmd_ptr)++;
if (!**cmd_ptr) {
job->num_progs = 0;
*cmd_ptr = NULL;
return 0;
}
*bg = 0;
job->num_progs = 1;
job->progs = malloc(sizeof(*job->progs));
job->cmd_buf = command = calloc(1, strlen(*cmd_ptr) + 1);
job->text = NULL;
prog = job->progs;
prog->num_redirections = 0;
prog->redirections = NULL;
prog->free_glob = 0;
prog->is_stopped = 0;
argv_alloced = INCREMENT_LEN;
prog->argv = malloc(sizeof(*prog->argv) * argv_alloced);
prog->argv[0] = job->cmd_buf;
buf = command;
src = *cmd_ptr;
while (*src && !done) {
if (quote == *src) {
quote = '\0';
}
else if (quote) {
if (*src == '\\') {
src++;
if (!src) {
fprintf(stderr, "character expected after \\\n");
free_job(job);
return 1;
}
if (*src != quote)
*buf++ = '\\';
}
else if (*src == '*' || *src == '?' || *src == '[' ||
*src == ']')
*buf++ = '\\';
*buf++ = *src;
}
else if (isspace(*src)) {
if (*prog->argv[argc]) {
buf++, argc++;
if ((argc + 1) == argv_alloced) {
argv_alloced += INCREMENT_LEN;
prog->argv = realloc(prog->argv,
sizeof(*prog->argv) * argv_alloced);
}
prog->argv[argc] = buf;
glob_argument(prog, &argc, &argv_alloced);
}
}
else
switch (*src) {
case '"':
case '\'':
quote = *src;
break;
case '#':
done = 1;
break;
case '>':
case '<':
i = prog->num_redirections++;
prog->redirections =
realloc(prog->redirections,sizeof(*prog->redirections)*(i+1));
prog->redirections[i].fd = -1;
if (buf != prog->argv[argc]) {
prog->redirections[i].fd =
strtol(prog->argv[argc], &chptr, 10);
if (*chptr && *prog->argv[argc]) {
buf++, argc++;
glob_argument(prog, &argc, &argv_alloced);
}
}
if (prog->redirections[i].fd == -1) {
if (*src == '>')
prog->redirections[i].fd = STDOUT_FILENO;
else
prog->redirections[i].fd = STDIN_FILENO;
}
if (*src++ == '>') {
if (*src == '>')
prog->redirections[i].type = REDIRECT_APPEND, src++;
else
prog->redirections[i].type = REDIRECT_OVERWRITE;
}
else {
if (*src == '>')
prog->redirections[i].type = REDIRECT_READWRITE, src++;
else
prog->redirections[i].type = REDIRECT_READ;
}
chptr = src;
while (isspace(*chptr))
chptr++;
if (!*chptr) {
fprintf(stderr, "file name expected after %c \n", *src);
free_job(job);
return 1;
}
prog->redirections[i].filename = buf;
while (*chptr && !isspace(*chptr))
*buf++ = *chptr++;
src = chptr -1;
prog->argv[argc] = ++buf;
break;
case '|':
if (*prog->argv[argc])
argc++;
if (!argc) {
fprintf(stderr, "empty command in pipe\n");
free_job(job);
return 1;
}
prog->argv[argc] = NULL;
job->num_progs++;
job->progs = realloc(job->progs,
sizeof(*job->progs) * job->num_progs);
prog = job->progs + (job->num_progs - 1);
prog->num_redirections = 0;
prog->redirections = NULL;
prog->free_glob = 0;
argc = 0;
argv_alloced = INCREMENT_LEN;
prog->argv = malloc(sizeof(*prog->argv) * argv_alloced);
prog->argv[0] = ++buf;
src++;
while (*src && isspace(*src))
src++;
if (!*src) {
fprintf(stderr, "empty command in pipe\n");
*cmd_ptr = src;
return 1;
}
src--;
break;
case '&':
*bg = 1;
case ';':
done = 1;
return_cmd = *cmd_ptr + (src - *cmd_ptr) + 1;
break;
case '\\':
src++;
if (!*src) {
free_job(job);
fprintf(stderr, "character expected after \\\n");
*cmd_ptr = src;
return 1;
}
if (*src == '*' || *src == '[' || *src == ']' || *src == '?')
*buf++ = '\\';
default:
*buf++ = *src;
}
src++;
}
if (*prog->argv[argc]) {
argc++;
glob_argument(prog, &argc, &argv_alloced);
}
if (!argc) {
free_job(job);
return 0;
}
prog->argv[argc] = NULL;
if (!return_cmd) {
job->text = malloc(strlen(*cmd_ptr) + 1);
strcpy(job->text, *cmd_ptr);
}
else {
count = return_cmd - *cmd_ptr;
job->text = malloc(count + 1);
strncpy(job->text, *cmd_ptr, count);
job->text[count] = '\0';
}
*cmd_ptr = return_cmd;
return 0;
}
int m_exit(CHAIN *job_list)
{
JOB *job, *prevjob;
job = job_list->head;
while (job) {
prevjob = job;
job = job->next;
remove_job(job_list, prevjob);
}
if (current_host_name) free(current_host_name);
if (current_user.user_name) free(current_user.user_name);
exit(0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -