mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-02-16 03:42:45 +08:00
![ridiculousfish](/assets/img/avatar_default.png)
This changes how fish attempts to protect itself from calling tcsetpgrp() too aggressively. Recall that tcsetpgrp() will "force" itself, if SIGTTOU is ignored (which it is in fish when job control is enabled). Prior to this fix, we avoided SIGTTINs by only transferring the tty ownership if fish was already the owner. This dated from a time before we had really nailed down how pgroups should be assigned. Now we more deliberately assign a job's pgroup so we don't need this conservative check. However we still need logic to avoid transferring the tty if fish is not the owner. The bad case is when job control is enabled while fish is running in the background - here fish would transfer the tty and "steal" from the foreground process. So retain the checks of the current tty owner but migrate them to the point of calling tcsetpgrp() itself.
92 lines
3.5 KiB
C++
92 lines
3.5 KiB
C++
// Functions that we may safely call after fork(), of which there are very few. In particular we
|
|
// cannot allocate memory, since we're insane enough to call fork from a multithreaded process.
|
|
#ifndef FISH_POSTFORK_H
|
|
#define FISH_POSTFORK_H
|
|
|
|
#include "config.h"
|
|
|
|
#include <stddef.h>
|
|
#include <unistd.h>
|
|
|
|
#include "maybe.h"
|
|
#if HAVE_SPAWN_H
|
|
#include <spawn.h>
|
|
#endif
|
|
#ifndef FISH_USE_POSIX_SPAWN
|
|
#define FISH_USE_POSIX_SPAWN HAVE_SPAWN_H
|
|
#endif
|
|
|
|
class dup2_list_t;
|
|
class job_t;
|
|
class process_t;
|
|
|
|
/// Tell the proc \p pid to join process group \p pgroup.
|
|
/// If \p is_child is true, we are the child process; otherwise we are fish.
|
|
/// Called by both parent and child; this is an unavoidable race inherent to Unix.
|
|
/// If is_parent is set, then we are the parent process and should swallow EACCESS.
|
|
/// \return 0 on success, an errno error code on failure.
|
|
int execute_setpgid(pid_t pid, pid_t pgroup, bool is_parent);
|
|
|
|
/// Report the error code \p err for a failed setpgid call.
|
|
/// Note not all errors should be reported; in particular EACCESS is expected and benign in the
|
|
/// parent only.
|
|
void report_setpgid_error(int err, pid_t desired_pgid, const job_t *j, const process_t *p);
|
|
|
|
/// Initialize a new child process. This should be called right away after forking in the child
|
|
/// process. If job control is enabled for this job, the process is put in the process group of the
|
|
/// job, all signal handlers are reset, signals are unblocked (this function may only be called
|
|
/// inside the exec function, which blocks all signals), and all IO redirections and other file
|
|
/// descriptor actions are performed.
|
|
///
|
|
/// Assign the terminal to new_termowner unless it is INVALID_PID.
|
|
///
|
|
/// \return 0 on success, -1 on failure. When this function returns, signals are always unblocked.
|
|
/// On failure, signal handlers, io redirections and process group of the process is undefined.
|
|
int child_setup_process(pid_t new_termowner, pid_t fish_pgrp, const job_t &job, bool is_forked,
|
|
const dup2_list_t &dup2s);
|
|
|
|
/// Call fork(), retrying on failure a few times.
|
|
pid_t execute_fork();
|
|
|
|
/// Report an error from failing to exec or posix_spawn a command.
|
|
void safe_report_exec_error(int err, const char *actual_cmd, const char *const *argv,
|
|
const char *const *envv);
|
|
|
|
#ifdef FISH_USE_POSIX_SPAWN
|
|
/// A RAII type which wraps up posix_spawn's data structures.
|
|
class posix_spawner_t {
|
|
public:
|
|
/// Attempt to construct from a job and dup2 list.
|
|
/// The caller must check the error function, as this may fail.
|
|
posix_spawner_t(const job_t *j, const dup2_list_t &dup2s);
|
|
|
|
/// \return the last error code, or 0 if there is no error.
|
|
int get_error() const { return error_; }
|
|
|
|
/// If this spawner does not have an error, invoke posix_spawn. Parameters are the same as
|
|
/// posix_spawn.
|
|
/// \return the pid, or none() on failure, in which case our error will be set.
|
|
maybe_t<pid_t> spawn(const char *cmd, char *const argv[], char *const envp[]);
|
|
|
|
~posix_spawner_t();
|
|
|
|
posix_spawner_t(const posix_spawner_t &) = delete;
|
|
void operator=(const posix_spawner_t &) = delete;
|
|
void operator=(posix_spawner_t &&) = delete;
|
|
posix_spawner_t(posix_spawner_t &&) = delete;
|
|
|
|
private:
|
|
bool check_fail(int err);
|
|
posix_spawnattr_t *attr() { return &*attr_; }
|
|
posix_spawn_file_actions_t *actions() { return &*actions_; }
|
|
|
|
posix_spawner_t();
|
|
int error_{0};
|
|
maybe_t<posix_spawnattr_t> attr_{};
|
|
maybe_t<posix_spawn_file_actions_t> actions_{};
|
|
};
|
|
|
|
#endif
|
|
|
|
#endif
|