⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jobctrl.c

📁 Linux下写一个命令解释程序,实现了基本的功能.
💻 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 + -