Пример #1
0
/* 
	* eval - Evaluate the command line that the user has just typed in
	* 
	* If the user has requested a built-in command (quit, jobs, bg or fg)
	* then execute it immediately. Otherwise, fork a child process and
	* run the job in the context of the child. If the job is running in
	* the foreground, wait for it to terminate and then return.  Note:
	* each child process must have a unique process group ID so that our
	* background children don't receive SIGINT (SIGTSTP) from the kernel
	* when we type ctrl-c (ctrl-z) at the keyboard.  
	*/
void eval(char *cmdline) 
{
	char *argv[MAXARGS];
	/* int ground = parseline(cmdline, (char **)&argv); */
	char buf[MAXLINE];      // Holds modified command line
	strcpy(buf, cmdline);
	int ground = parseline(buf, argv);

	if (argv[0] == NULL) return;

	if (!builtin_cmd((char **)&argv)) {
		sigset_t mask;
		sigemptyset(&mask);
		sigaddset(&mask, SIGCHLD);
		sigprocmask(SIG_BLOCK, &mask, NULL);
		pid_t pid = __fork();

		if (pid != 0) {
			addjob(jobs, pid, ground ? BG : FG, cmdline);
			sigprocmask(SIG_UNBLOCK, &mask, NULL);
			if (!ground) waitfg(pid);
			else printf("[%d] (%d) %s", pid2jid(pid), pid, cmdline);
		} else {
			__setpgid(0, 0);
			sigprocmask(SIG_UNBLOCK, &mask, NULL);
			if (execve(argv[0], argv, environ) < 0) {
				printf("%s: Command not found\n", argv[0]);
				exit(0);
			}
		}
	}

	return;
}
Пример #2
0
/*
 * fork stub
 */
pid_t
fork(void)
{
	int ret;
	
	_libSystem_atfork_prepare();
	// Reader beware: this __fork() call is yet another wrapper around the actual syscall
	// and lives inside libsyscall. The fork syscall needs some cuddling by asm before it's
	// allowed to see the big wide C world.
	ret = __fork();
	if (-1 == ret)
	{
		// __fork already set errno for us
		_libSystem_atfork_parent();
		return ret;
	}
	
	if (0 == ret)
	{
		// We're the child in this part.
		_libSystem_atfork_child();
		return 0;
	}
	
	_libSystem_atfork_parent();
	return ret;
}
Пример #3
0
extern "C" NS_EXPORT pid_t
WRAP(fork)(void)
{
  pid_t pid;
  for (std::vector<AtForkFuncs>::reverse_iterator it = atfork.rbegin();
       it < atfork.rend(); ++it)
    if (it->prepare)
      it->prepare();

  switch ((pid = __fork())) {
  case 0:
    cpuacct_add(getuid());
    for (std::vector<AtForkFuncs>::iterator it = atfork.begin();
         it < atfork.end(); ++it)
      if (it->child)
        it->child();
    break;
  default:
    for (std::vector<AtForkFuncs>::iterator it = atfork.begin();
         it < atfork.end(); ++it)
      if (it->parent)
        it->parent();
  }
  return pid;
}
Пример #4
0
int  fork(void)
{
    int  ret;

    /* Posix mandates that the timers of a fork child process be
     * disarmed, but not destroyed. To avoid a race condition, we're
     * going to stop all timers now, and only re-start them in case
     * of error, or in the parent process
     */
    __timer_table_start_stop(1);
    __bionic_atfork_run_prepare();

    ret = __fork();
    if (ret != 0) {  /* not a child process */
        __timer_table_start_stop(0);
        __bionic_atfork_run_parent();
    } else {
        /*
         * Newly created process must update cpu accounting.
         * Call cpuacct_add passing in our uid, which will take
         * the current task id and add it to the uid group passed
         * as a parameter.
         */
        cpuacct_add(getuid());
        __bionic_atfork_run_child();
    }
    return ret;
}
Пример #5
0
/*
 * returns pid, or -1 for failure
 */
int
_openchild (const char *command, FILE ** fto, FILE ** ffrom)
{
  int i;
  int pid;
  int pdto[2];
  int pdfrom[2];

  if (__pipe (pdto) < 0)
    goto error1;
  if (__pipe (pdfrom) < 0)
    goto error2;
  switch (pid = __fork ())
    {
    case -1:
      goto error3;

    case 0:
      /*
       * child: read from pdto[0], write into pdfrom[1]
       */
      __close (0);
      __dup (pdto[0]);
      __close (1);
      __dup (pdfrom[1]);
      fflush (stderr);
      for (i = _rpc_dtablesize () - 1; i >= 3; i--)
	__close (i);
      fflush (stderr);
      execlp (command, command, NULL);
      perror ("exec");
      _exit (~0);

    default:
      /*
       * parent: write into pdto[1], read from pdfrom[0]
       */
      *fto = __fdopen (pdto[1], "w");
      __close (pdto[0]);
      *ffrom = __fdopen (pdfrom[0], "r");
      __close (pdfrom[1]);
      break;
    }
  return pid;

  /*
   * error cleanup and return
   */
error3:
  __close (pdfrom[0]);
  __close (pdfrom[1]);
error2:
  __close (pdto[0]);
  __close (pdto[1]);
error1:
  return -1;
}
Пример #6
0
int fork(void)
{
  int pid;
  struct handler_list * prepare, * child, * parent;

  pthread_mutex_lock(&pthread_atfork_lock);
  prepare = pthread_atfork_prepare;
  child = pthread_atfork_child;
  parent = pthread_atfork_parent;
  pthread_mutex_unlock(&pthread_atfork_lock);
  pthread_call_handlers(prepare);
  pid = __fork();
  if (pid == 0) {
    __pthread_reset_main_thread();
    __fresetlockfiles();
    pthread_call_handlers(child);
  } else {
    pthread_call_handlers(parent);
  }
  return pid;
}
Пример #7
0
int
grantpt (int fd)
{
#if defined __OpenBSD__
  /* On OpenBSD, master and slave of a pseudo-terminal are allocated together,
     through an ioctl on /dev/ptm.  There is no need for grantpt().  */
  return 0;
#else
  /* This function is most often called from a process without 'root'
     credentials.  Use the helper program.  */
  int retval = -1;
  pid_t pid = __fork ();
  if (pid == -1)
    goto cleanup;
  else if (pid == 0)
    {
      /* This is executed in the child process.  */

# if HAVE_SETRLIMIT && defined RLIMIT_CORE
      /* Disable core dumps.  */
      struct rlimit rl = { 0, 0 };
      __setrlimit (RLIMIT_CORE, &rl);
# endif

      /* We pass the master pseudo terminal as file descriptor PTY_FILENO.  */
      if (fd != PTY_FILENO)
        if (__dup2 (fd, PTY_FILENO) < 0)
          _exit (FAIL_EBADF);

# ifdef CLOSE_ALL_FDS
      CLOSE_ALL_FDS ();
# endif

      execle (_PATH_PT_CHOWN, strrchr (_PATH_PT_CHOWN, '/') + 1, NULL, NULL);
      _exit (FAIL_EXEC);
    }
  else
    {
      int w;

      if (__waitpid (pid, &w, 0) == -1)
        goto cleanup;
      if (!WIFEXITED (w))
        __set_errno (ENOEXEC);
      else
        switch (WEXITSTATUS (w))
          {
          case 0:
            retval = 0;
            break;
          case FAIL_EBADF:
            __set_errno (EBADF);
            break;
          case FAIL_EINVAL:
            __set_errno (EINVAL);
            break;
          case FAIL_EACCES:
            __set_errno (EACCES);
            break;
          case FAIL_EXEC:
            __set_errno (ENOEXEC);
            break;
          case FAIL_ENOMEM:
            __set_errno (ENOMEM);
            break;

          default:
            assert(! "getpt: internal error: invalid exit code from pt_chown");
          }
    }

 cleanup:
  return retval;
#endif
}
Пример #8
0
/* Execute LINE as a shell command, returning its status.  */
static int
do_system (const char *line)
{
  int status, save;
  pid_t pid;
  struct sigaction sa;
#ifndef _LIBC_REENTRANT
  struct sigaction intr, quit;
#endif
  sigset_t omask;

  sa.sa_handler = SIG_IGN;
  sa.sa_flags = 0;
  __sigemptyset (&sa.sa_mask);

  DO_LOCK ();
  if (ADD_REF () == 0)
    {
      if (__sigaction (SIGINT, &sa, &intr) < 0)
	{
	  (void) SUB_REF ();
	  goto out;
	}
      if (__sigaction (SIGQUIT, &sa, &quit) < 0)
	{
	  save = errno;
	  (void) SUB_REF ();
	  goto out_restore_sigint;
	}
    }
  DO_UNLOCK ();

  /* We reuse the bitmap in the 'sa' structure.  */
  __sigaddset (&sa.sa_mask, SIGCHLD);
  save = errno;
  if (__sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0)
    {
#ifndef _LIBC
      if (errno == ENOSYS)
	__set_errno (save);
      else
#endif
	{
	  DO_LOCK ();
	  if (SUB_REF () == 0)
	    {
	      save = errno;
	      (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
	    out_restore_sigint:
	      (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
	      __set_errno (save);
	    }
	out:
	  DO_UNLOCK ();
	  return -1;
	}
    }

#ifdef CLEANUP_HANDLER
  CLEANUP_HANDLER;
#endif

#ifdef FORK
  pid = FORK ();
#else
  pid = __fork ();
#endif
  if (pid == (pid_t) 0)
    {
      /* Child side.  */
      const char *new_argv[4];
      new_argv[0] = SHELL_NAME;
      new_argv[1] = "-c";
      new_argv[2] = line;
      new_argv[3] = NULL;

      /* Restore the signals.  */
      (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
      (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
      (void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
      INIT_LOCK ();

      /* Exec the shell.  */
      (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ);
      _exit (127);
    }
  else if (pid < (pid_t) 0)
    /* The fork failed.  */
    status = -1;
  else
    /* Parent side.  */
    {
      /* Note the system() is a cancellation point.  But since we call
	 waitpid() which itself is a cancellation point we do not
	 have to do anything here.  */
      if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) != pid)
	status = -1;
    }

#ifdef CLEANUP_HANDLER
  CLEANUP_RESET;
#endif

  save = errno;
  DO_LOCK ();
  if ((SUB_REF () == 0
       && (__sigaction (SIGINT, &intr, (struct sigaction *) NULL)
	   | __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0)
      || __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0)
    {
#ifndef _LIBC
      /* glibc cannot be used on systems without waitpid.  */
      if (errno == ENOSYS)
	__set_errno (save);
      else
#endif
	status = -1;
    }
  DO_UNLOCK ();

  return status;
}
Пример #9
0
/* Spawn a new process executing PATH with the attributes describes in *ATTRP.
   Before running the process perform the actions described in FILE-ACTIONS. */
int
__spawni (pid_t *pid, const char *file,
	  const posix_spawn_file_actions_t *file_actions,
	  const posix_spawnattr_t *attrp, char *const argv[],
	  char *const envp[], int xflags)
{
  pid_t new_pid;
  char *path, *p, *name;
  size_t len;
  size_t pathlen;

  /* Do this once.  */
  short int flags = attrp == NULL ? 0 : attrp->__flags;

  /* Generate the new process.  */
  if ((flags & POSIX_SPAWN_USEVFORK) != 0
      /* If no major work is done, allow using vfork.  Note that we
	 might perform the path searching.  But this would be done by
	 a call to execvp(), too, and such a call must be OK according
	 to POSIX.  */
      || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF
		    | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER
		    | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0
	  && file_actions == NULL))
    new_pid = __vfork ();
  else
    new_pid = __fork ();

  if (new_pid != 0)
    {
      if (new_pid < 0)
	return errno;

      /* The call was successful.  Store the PID if necessary.  */
      if (pid != NULL)
	*pid = new_pid;

      return 0;
    }

  /* Set signal mask.  */
  if ((flags & POSIX_SPAWN_SETSIGMASK) != 0
      && __sigprocmask (SIG_SETMASK, &attrp->__ss, NULL) != 0)
    _exit (SPAWN_ERROR);

  /* Set signal default action.  */
  if ((flags & POSIX_SPAWN_SETSIGDEF) != 0)
    {
      /* We have to iterate over all signals.  This could possibly be
	 done better but it requires system specific solutions since
	 the sigset_t data type can be very different on different
	 architectures.  */
      int sig;
      struct sigaction sa;

      memset (&sa, '\0', sizeof (sa));
      sa.sa_handler = SIG_DFL;

      for (sig = 1; sig <= _NSIG; ++sig)
	if (__sigismember (&attrp->__sd, sig) != 0
	    && __sigaction (sig, &sa, NULL) != 0)
	  _exit (SPAWN_ERROR);

    }

#ifdef _POSIX_PRIORITY_SCHEDULING
  /* Set the scheduling algorithm and parameters.  */
  if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER))
      == POSIX_SPAWN_SETSCHEDPARAM)
    {
      if (__sched_setparam (0, &attrp->__sp) == -1)
	_exit (SPAWN_ERROR);
    }
  else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0)
    {
      if (__sched_setscheduler (0, attrp->__policy, &attrp->__sp) == -1)
	_exit (SPAWN_ERROR);
    }
#endif

  /* Set the process group ID.  */
  if ((flags & POSIX_SPAWN_SETPGROUP) != 0
      && __setpgid (0, attrp->__pgrp) != 0)
    _exit (SPAWN_ERROR);

  /* Set the effective user and group IDs.  */
  if ((flags & POSIX_SPAWN_RESETIDS) != 0
      && (local_seteuid (__getuid ()) != 0
	  || local_setegid (__getgid ()) != 0))
    _exit (SPAWN_ERROR);

  /* Execute the file actions.  */
  if (file_actions != NULL)
    {
      int cnt;
      struct rlimit64 fdlimit;
      bool have_fdlimit = false;

      for (cnt = 0; cnt < file_actions->__used; ++cnt)
	{
	  struct __spawn_action *action = &file_actions->__actions[cnt];

	  switch (action->tag)
	    {
	    case spawn_do_close:
	      if (close_not_cancel (action->action.close_action.fd) != 0)
		{
		  if (! have_fdlimit)
		    {
		      getrlimit64 (RLIMIT_NOFILE, &fdlimit);
		      have_fdlimit = true;
		    }

		  /* Only signal errors for file descriptors out of range.  */
		  if (action->action.close_action.fd < 0
		      || action->action.close_action.fd >= fdlimit.rlim_cur)
		    /* Signal the error.  */
		    _exit (SPAWN_ERROR);
		}
	      break;

	    case spawn_do_open:
	      {
		int new_fd = open_not_cancel (action->action.open_action.path,
					      action->action.open_action.oflag
					      | O_LARGEFILE,
					      action->action.open_action.mode);

		if (new_fd == -1)
		  /* The `open' call failed.  */
		  _exit (SPAWN_ERROR);

		/* Make sure the desired file descriptor is used.  */
		if (new_fd != action->action.open_action.fd)
		  {
		    if (__dup2 (new_fd, action->action.open_action.fd)
			!= action->action.open_action.fd)
		      /* The `dup2' call failed.  */
		      _exit (SPAWN_ERROR);

		    if (close_not_cancel (new_fd) != 0)
		      /* The `close' call failed.  */
		      _exit (SPAWN_ERROR);
		  }
	      }
	      break;

	    case spawn_do_dup2:
	      if (__dup2 (action->action.dup2_action.fd,
			  action->action.dup2_action.newfd)
		  != action->action.dup2_action.newfd)
		/* The `dup2' call failed.  */
		_exit (SPAWN_ERROR);
	      break;
	    }
	}
    }

  if ((xflags & SPAWN_XFLAGS_USE_PATH) == 0 || strchr (file, '/') != NULL)
    {
      /* The FILE parameter is actually a path.  */
      __execve (file, argv, envp);

      maybe_script_execute (file, argv, envp, xflags);

      /* Oh, oh.  `execve' returns.  This is bad.  */
      _exit (SPAWN_ERROR);
    }

  /* We have to search for FILE on the path.  */
  path = getenv ("PATH");
  if (path == NULL)
    {
      /* There is no `PATH' in the environment.
	 The default search path is the current directory
	 followed by the path `confstr' returns for `_CS_PATH'.  */
      len = confstr (_CS_PATH, (char *) NULL, 0);
      path = (char *) __alloca (1 + len);
      path[0] = ':';
      (void) confstr (_CS_PATH, path + 1, len);
    }

  len = strlen (file) + 1;
  pathlen = strlen (path);
  name = __alloca (pathlen + len + 1);
  /* Copy the file name at the top.  */
  name = (char *) memcpy (name + pathlen + 1, file, len);
  /* And add the slash.  */
  *--name = '/';

  p = path;
  do
    {
      char *startp;

      path = p;
      p = __strchrnul (path, ':');

      if (p == path)
	/* Two adjacent colons, or a colon at the beginning or the end
	   of `PATH' means to search the current directory.  */
	startp = name + 1;
      else
	startp = (char *) memcpy (name - (p - path), path, p - path);

      /* Try to execute this name.  If it works, execv will not return.  */
      __execve (startp, argv, envp);

      maybe_script_execute (startp, argv, envp, xflags);

      switch (errno)
	{
	case EACCES:
	case ENOENT:
	case ESTALE:
	case ENOTDIR:
	  /* Those errors indicate the file is missing or not executable
	     by us, in which case we want to just try the next path
	     directory.  */
	  break;

	default:
	  /* Some other error means we found an executable file, but
	     something went wrong executing it; return the error to our
	     caller.  */
	  _exit (SPAWN_ERROR);
	    }
    }
  while (*p++ != '\0');

  /* Return with an error.  */
  _exit (SPAWN_ERROR);
}
Пример #10
0
/* Change the ownership and access permission of the slave pseudo
   terminal associated with the master pseudo terminal specified
   by FD.  */
int
grantpt (int fd)
{
  int retval = -1;
#ifdef PATH_MAX
  char _buf[PATH_MAX];
#else
  char _buf[512];
#endif
  char *buf = _buf;
  struct stat64 st;

  if (__glibc_unlikely (pts_name (fd, &buf, sizeof (_buf), &st)))
    {
      int save_errno = errno;

      /* Check, if the file descriptor is valid.  pts_name returns the
	 wrong errno number, so we cannot use that.  */
      if (__libc_fcntl (fd, F_GETFD) == -1 && errno == EBADF)
	return -1;

       /* If the filedescriptor is no TTY, grantpt has to set errno
	  to EINVAL.  */
       if (save_errno == ENOTTY)
	 __set_errno (EINVAL);
       else
	 __set_errno (save_errno);

       return -1;
    }

  /* Make sure that we own the device.  */
  uid_t uid = __getuid ();
  if (st.st_uid != uid)
    {
      if (__chown (buf, uid, st.st_gid) < 0)
	goto helper;
    }

  static int tty_gid = -1;
  if (__glibc_unlikely (tty_gid == -1))
    {
      char *grtmpbuf;
      struct group grbuf;
      size_t grbuflen = __sysconf (_SC_GETGR_R_SIZE_MAX);
      struct group *p;

      /* Get the group ID of the special `tty' group.  */
      if (grbuflen == (size_t) -1L)
	/* `sysconf' does not support _SC_GETGR_R_SIZE_MAX.
	   Try a moderate value.  */
	grbuflen = 1024;
      grtmpbuf = (char *) __alloca (grbuflen);
      __getgrnam_r (TTY_GROUP, &grbuf, grtmpbuf, grbuflen, &p);
      if (p != NULL)
	tty_gid = p->gr_gid;
    }
  gid_t gid = tty_gid == -1 ? __getgid () : tty_gid;

  /* Make sure the group of the device is that special group.  */
  if (st.st_gid != gid)
    {
      if (__chown (buf, uid, gid) < 0)
	goto helper;
    }

  /* Make sure the permission mode is set to readable and writable by
     the owner, and writable by the group.  */
  if ((st.st_mode & ACCESSPERMS) != (S_IRUSR|S_IWUSR|S_IWGRP))
    {
      if (__chmod (buf, S_IRUSR|S_IWUSR|S_IWGRP) < 0)
	goto helper;
    }

  retval = 0;
  goto cleanup;

  /* We have to use the helper program if it is available.  */
 helper:;

#ifdef HAVE_PT_CHOWN
  pid_t pid = __fork ();
  if (pid == -1)
    goto cleanup;
  else if (pid == 0)
    {
      /* Disable core dumps.  */
      struct rlimit rl = { 0, 0 };
      __setrlimit (RLIMIT_CORE, &rl);

      /* We pass the master pseudo terminal as file descriptor PTY_FILENO.  */
      if (fd != PTY_FILENO)
	if (__dup2 (fd, PTY_FILENO) < 0)
	  _exit (FAIL_EBADF);

# ifdef CLOSE_ALL_FDS
      CLOSE_ALL_FDS ();
# endif

      execle (_PATH_PT_CHOWN, basename (_PATH_PT_CHOWN), NULL, NULL);
      _exit (FAIL_EXEC);
    }
  else
    {
      int w;

      if (__waitpid (pid, &w, 0) == -1)
	goto cleanup;
      if (!WIFEXITED (w))
	__set_errno (ENOEXEC);
      else
	switch (WEXITSTATUS (w))
	  {
	  case 0:
	    retval = 0;
	    break;
	  case FAIL_EBADF:
	    __set_errno (EBADF);
	    break;
	  case FAIL_EINVAL:
	    __set_errno (EINVAL);
	    break;
	  case FAIL_EACCES:
	    __set_errno (EACCES);
	    break;
	  case FAIL_EXEC:
	    __set_errno (ENOEXEC);
	    break;
	  case FAIL_ENOMEM:
	    __set_errno (ENOMEM);
	    break;

	  default:
	    assert(! "getpt: internal error: invalid exit code from pt_chown");
	  }
    }
#endif

 cleanup:
  if (buf != _buf)
    free (buf);

  return retval;
}
Пример #11
0
pid_t __vfork(void)
{
  return __fork();
}