Specifies the command to stop the service. Applicable only to \fBscripted\fR
services.
.TP
+\fBworking-dir\fR = \fIdirectory\fR
+Specifies the working directory for this service. For a scripted service, this
+affects both the start command and the stop command.
+.TP
\fBrun-as\fR = \fIuser-id\fR
Specifies which user to run the process(es) for this service as. The group id
for the process will also be set to the primary group of the specified user.
}
if (forkpid == 0) {
- run_child_proc(cmd.data(), logfile, on_console, pipefd[1], control_socket[1], socket_fd,
- run_as_uid, run_as_gid);
+ const char * working_dir_c = nullptr;
+ if (! working_dir.empty()) working_dir_c = working_dir.c_str();
+ run_child_proc(cmd.data(), working_dir_c, logfile, on_console, pipefd[1], control_socket[1],
+ socket_fd, run_as_uid, run_as_gid);
}
else {
// Parent process
string stop_command; // storage for stop program/script and arguments
std::vector<const char *> stop_arg_parts; // pointer to each argument/part of the stop_command, and nullptr
+ string working_dir; // working directory (or empty)
+
service_child_watcher child_listener;
exec_status_pipe_watcher child_status_listener;
process_restart_timer restart_timer;
run_as_gid = gid;
}
+ // Set the working directory
+ void set_workding_dir(string working_dir_p)
+ {
+ working_dir = working_dir_p;
+ }
+
// The restart/stop timer expired.
void timer_expired() noexcept;
};
// Run a child process (call after forking).
// - args specifies the program arguments including the executable (argv[0])
+ // - working_dir specifies the working directory; may be null
// - logfile specifies the logfile
// - on_console: if true, process is run with access to console
// - wpipefd: if the exec is unsuccessful, or another error occurs beforehand, the
// - csfd: the control socket fd; may be -1 to inhibit passing of control socket
// - socket_fd: the pre-opened socket file descriptor (may be -1)
// - uid/gid: the identity to run the process as (may be both -1, otherwise both must be valid)
- void run_child_proc(const char * const *args, const char *logfile, bool on_console, int wpipefd,
- int csfd, int socket_fd, uid_t uid, gid_t gid) noexcept;
+ void run_child_proc(const char * const *args, const char *working_dir, const char *logfile,
+ bool on_console, int wpipefd, int csfd, int socket_fd, uid_t uid, gid_t gid) noexcept;
// A dependency has reached STARTED state
void dependency_started() noexcept;
list<pair<unsigned,unsigned>> command_offsets;
string stop_command;
list<pair<unsigned,unsigned>> stop_command_offsets;
+ string working_dir;
string pid_file;
service_type_t service_type = service_type_t::PROCESS;
if (setting == "command") {
command = read_setting_value(i, end, &command_offsets);
}
+ else if (setting == "working-dir") {
+ working_dir = read_setting_value(i, end, nullptr);
+ }
else if (setting == "socket-listen") {
socket_path = read_setting_value(i, end, nullptr);
}
if (service_type == service_type_t::PROCESS) {
auto rvalps = new process_service(this, string(name), std::move(command),
command_offsets, depends);
+ rvalps->set_workding_dir(working_dir);
rvalps->set_restart_interval(restart_interval, max_restarts);
rvalps->set_restart_delay(restart_delay);
rvalps->set_stop_timeout(stop_timeout);
rvalps->set_start_interruptible(start_is_interruptible);
rvalps->set_extra_termination_signal(term_signal);
rvalps->set_run_as_uid_gid(run_as_uid, run_as_gid);
+ rvalps->set_workding_dir(working_dir);
// process service start / run on console must be the same:
onstart_flags.starts_on_console = onstart_flags.runs_on_console;
rval = rvalps;
else if (service_type == service_type_t::BGPROCESS) {
auto rvalps = new bgproc_service(this, string(name), std::move(command),
command_offsets, depends);
+ rvalps->set_workding_dir(working_dir);
rvalps->set_pid_file(std::move(pid_file));
rvalps->set_restart_interval(restart_interval, max_restarts);
rvalps->set_restart_delay(restart_delay);
auto rvalps = new scripted_service(this, string(name), std::move(command),
command_offsets, depends);
rvalps->set_stop_command(stop_command, stop_command_offsets);
+ rvalps->set_workding_dir(working_dir);
rvalps->set_stop_timeout(stop_timeout);
rvalps->set_start_timeout(start_timeout);
rvalps->set_start_interruptible(start_is_interruptible);
#include "service.h"
-void service_record::run_child_proc(const char * const *args, const char *logfile, bool on_console,
- int wpipefd, int csfd, int socket_fd, uid_t uid, gid_t gid) noexcept
+void service_record::run_child_proc(const char * const *args, const char *working_dir,
+ const char *logfile, bool on_console, int wpipefd, int csfd, int socket_fd,
+ uid_t uid, gid_t gid) noexcept
{
// Child process. Must not allocate memory (or otherwise risk throwing any exception)
// from here until exit().
if (putenv(csenvbuf)) goto failure_out;
}
+ if (working_dir != nullptr && *working_dir != 0) {
+ if (chdir(working_dir) == -1) {
+ goto failure_out;
+ }
+ }
+
if (! on_console) {
// Re-set stdin, stdout, stderr
close(0); close(1); close(2);
// Stub out run_child_proc function, for testing purposes.
-void service_record::run_child_proc(const char * const *args, const char *logfile, bool on_console,
- int wpipefd, int csfd, int socket_fd, uid_t uid, gid_t gid) noexcept
+void service_record::run_child_proc(const char * const *args, const char *working_dir,
+ const char *logfile, bool on_console, int wpipefd, int csfd, int socket_fd,
+ uid_t uid, gid_t gid) noexcept
{
}