Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions man/openrc-run.8
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,20 @@ for later retrieval. Saved values are lost when the service stops.
.It Ic service_get_value Ar name
Returns the saved value called
.Ar name .
.It Xo
.Ic service_export Ar NAME Ns Op = Ns Ar VALUE
.Ar ...
.Xc
Exports
.Ar NAME
for dependee services. Exported variables are lost when the service stops.

If
.Ar VALUE
is not provided, it's taken from the environment.

Exported variables only take effect when dependees start, so it makes
little sense to export anywhere but on start_pre, start, or start_post.
.It Ic service_started Op Ar service
If the service is started, return 0 otherwise 1.
.It Ic service_starting Op Ar service
Expand Down
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ if not cc.has_function('pipe2', prefix: '#include <unistd.h>')
endif
endif

add_project_arguments(feature_macros.keys(), language: 'c')
add_project_arguments([feature_macros.keys(), '-Drc_private='], language: 'c')

incdir = include_directories('src/shared')
einfo_incdir = include_directories('src/libeinfo')
Expand Down
38 changes: 20 additions & 18 deletions src/librc/librc-misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,35 +55,25 @@ rc_yesno(const char *value)
return false;
}


/**
* Read the entire @file into the buffer and set @len to the
* size of the buffer when finished. For C strings, this will
* be strlen(buffer) + 1.
* Don't forget to free the buffer afterwards!
*/
bool
rc_getfile(const char *file, char **buffer, size_t *len)
rc_getfileat(int dirfd, const char *file, char **buffer, size_t *size)
{
bool ret = false;
FILE *fp;
int fd;
struct stat st;
size_t done, left;

fp = fopen(file, "re");
fp = do_fopenat(dirfd, file, O_RDONLY);
if (!fp)
return false;

/* assume fileno() never fails */
fd = fileno(fp);

if (fstat(fd, &st))
if (fstat(fileno(fp), &st))
goto finished;

left = st.st_size;
*len = left + 1; /* NUL terminator */
*buffer = xrealloc(*buffer, *len);
*size = left + 1; /* NUL terminator */
*buffer = xrealloc(*buffer, *size);
while (left) {
done = fread(*buffer, sizeof(*buffer[0]), left, fp);
if (done == 0 && ferror(fp))
Expand All @@ -92,16 +82,28 @@ rc_getfile(const char *file, char **buffer, size_t *len)
}
ret = true;

finished:
finished:
if (!ret) {
free(*buffer);
*len = 0;
*size = 0;
} else
(*buffer)[*len - 1] = '\0';
(*buffer)[*size - 1] = '\0';
fclose(fp);
return ret;
}

/**
* Read the entire @file into the buffer and set @len to the
* size of the buffer when finished. For C strings, this will
* be strlen(buffer) + 1.
* Don't forget to free the buffer afterwards!
*/
bool
rc_getfile(const char *file, char **buffer, size_t *len)
{
return rc_getfileat(AT_FDCWD, file, buffer, len);
}

char *
rc_proc_getent(const char *ent RC_UNUSED)
{
Expand Down
66 changes: 66 additions & 0 deletions src/librc/librc.c
Original file line number Diff line number Diff line change
Expand Up @@ -964,6 +964,7 @@ rc_service_mark(const char *service, const RC_SERVICE state)
if (state == RC_SERVICE_STOPPED) {
rm_dir(rc_dirfd(RC_DIR_OPTIONS), base, true);
rm_dir(rc_dirfd(RC_DIR_DAEMONS), base, true);
rm_dir(rc_dirfd(RC_DIR_ENVIRONMENT), base, true);
rc_service_schedule_clear(service);
}

Expand Down Expand Up @@ -1268,3 +1269,68 @@ rc_services_scheduled(const char *service)
{
return ls_dir(rc_dirfd(RC_DIR_SCHEDULED), basename_c(service), LS_INITD);
}

bool
rc_service_setenv(const char *service, const char *name, const char *value)
{
FILE *envfile;
int dirfd;

if (!service)
service = "rc";

if (mkdirat(rc_dirfd(RC_DIR_ENVIRONMENT), service, 0644) == -1 && errno != EEXIST)
return false;
if ((dirfd = openat(rc_dirfd(RC_DIR_ENVIRONMENT), service, O_RDONLY | O_DIRECTORY)) == -1)
return false;

if (!value) {
bool ret = unlinkat(dirfd, name, 0) == 0;
close(dirfd);
return ret;
}

envfile = do_fopenat(dirfd, name, O_WRONLY | O_TRUNC | O_CREAT);
close(dirfd);

if (!envfile)
return false;

fputs(value, envfile);
return fclose(envfile) == 0;
}

bool
rc_environ_open(struct rc_environ *env, const char *service)
{
DIR *envdir = do_opendirat(rc_dirfd(RC_DIR_ENVIRONMENT), service ? basename_c(service) : "rc");
if (!envdir)
return false;
*env = (struct rc_environ) { .envdir = envdir };
return true;
}

bool
rc_environ_get(struct rc_environ *env, const char **name, const char **value)
{
for (struct dirent *entry; (entry = readdir(env->envdir));) {
if (entry->d_name[0] == '.')
continue;

if (!rc_getfileat(dirfd(env->envdir), entry->d_name, &env->bytes, &env->size))
continue;

*name = entry->d_name;
*value = env->bytes;
return true;
}

return false;
}

void
rc_environ_close(struct rc_environ *env)
{
closedir(env->envdir);
free(env->bytes);
}
2 changes: 2 additions & 0 deletions src/librc/librc.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,12 @@ static const char *const dirnames[RC_DIR_SYS_MAX] =
[RC_DIR_OPTIONS] = "options",
[RC_DIR_EXCLUSIVE] = "exclusive",
[RC_DIR_SCHEDULED] = "scheduled",
[RC_DIR_ENVIRONMENT] = "environment",
[RC_DIR_INITD] = "init.d",
[RC_DIR_TMP] = "tmp",
};

bool do_getfileat(int dirfd, const char *file, char **buffer, size_t *size);
RC_STRINGLIST *config_list(int dirfd, const char *pathname);
void clear_dirfds(void);

Expand Down
39 changes: 39 additions & 0 deletions src/librc/rc.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define __RC_H__

#include <sys/types.h>
#include <dirent.h>
#include <stdbool.h>
#include <stdio.h>

Expand Down Expand Up @@ -62,6 +63,10 @@ extern "C" {
# define RC_LOCAL_CONFDIR RC_LOCAL_PREFIX "/etc/conf.d"
#endif

#ifndef rc_private
#define rc_private __attribute__((deprecated("private field")))
#endif

#ifndef _SYS_QUEUE_H_

/*
Expand Down Expand Up @@ -209,6 +214,7 @@ enum rc_dir {
RC_DIR_OPTIONS,
RC_DIR_EXCLUSIVE,
RC_DIR_SCHEDULED,
RC_DIR_ENVIRONMENT,
RC_DIR_INITD,
RC_DIR_TMP,
RC_DIR_SYS_MAX,
Expand Down Expand Up @@ -373,6 +379,38 @@ RC_STRINGLIST *rc_services_scheduled(const char *);
* @return true if all daemons started are still running, otherwise false */
bool rc_service_daemons_crashed(const char *);

/*! Sets a variable into the enviroment for a given service.
* @param service name, if null, sets the variable to the global environment.
* @param variable name.
* @param variable value.
* @return true on success, false on IO error. */
bool rc_service_setenv(const char *, const char *, const char *);

struct rc_environ {
rc_private DIR *envdir;
rc_private char *bytes;
rc_private size_t size;
};

/*! Opens the environment of a given service.
* @param environ to initialize.
* @param serivce name.
* @return true on success, false on IO error. */
bool rc_environ_open(struct rc_environ *, const char *);

/*! Gets the environment of a given service. the name and value are only
* valid until the next rc_environ_get or rc_environ_close call with the
* same environment object.
* @param environment to iterate.
* @param out variable name.
* @param out variable value.
* @return true on success, false when there's no more variables. */
bool rc_environ_get(struct rc_environ *, const char **, const char **);

/*! Closes the environment and frees the resources.
* @param environ to cleanup. */
void rc_environ_close(struct rc_environ *);

/*! @name System types
* OpenRC can support some special sub system types, normally virtualization.
* Some services cannot work in these systems, or we do something else. */
Expand Down Expand Up @@ -661,6 +699,7 @@ typedef LIST_HEAD(rc_pidlist, rc_pid) RC_PIDLIST;
RC_PIDLIST *rc_find_pids(const char *, const char *const *, uid_t, pid_t);

/* Basically the same as getline(), it just returns multiple lines */
bool rc_getfileat(int, const char *, char **, size_t *);
bool rc_getfile(const char *, char **, size_t *);

/* __END_DECLS */
Expand Down
1 change: 1 addition & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ subdir('pam_openrc')
subdir('poweroff')
subdir('rc-abort')
subdir('rc-depend')
subdir('rc-env')
subdir('rc-service')
subdir('rc-sstat')
subdir('rc-status')
Expand Down
32 changes: 27 additions & 5 deletions src/openrc-run/openrc-run.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,20 @@ unhotplug(void)
eerror("%s: unlink '%s/hotplugged/%s': %s", applet, rc_svcdir(), applet, strerror(errno));
}

static void
add_environment(const char *svcname)
{
struct rc_environ svc_env;

if (!rc_environ_open(&svc_env, svcname))
return;

for (const char *name, *value; rc_environ_get(&svc_env, &name, &value);)
setenv(name, value, true);

rc_environ_close(&svc_env);
}

static void
start_services(RC_STRINGLIST *list)
{
Expand Down Expand Up @@ -676,8 +690,10 @@ svc_start_deps(void)
tmplist = rc_stringlist_new();
TAILQ_FOREACH(svc, services, entries) {
state = rc_service_state(svc->value);
if (state & RC_SERVICE_STARTED)
if (state & RC_SERVICE_STARTED) {
add_environment(svc->value);
continue;
}

/* Don't wait for services which went inactive but are
* now in starting state which we are after */
Expand All @@ -694,8 +710,10 @@ svc_start_deps(void)
eerror("%s: timed out waiting for %s",
applet, svc->value);
state = rc_service_state(svc->value);
if (state & RC_SERVICE_STARTED)
if (state & RC_SERVICE_STARTED) {
add_environment(svc->value);
continue;
}
if (rc_stringlist_find(need_services, svc->value)) {
if (state & RC_SERVICE_INACTIVE ||
state & RC_SERVICE_WASINACTIVE)
Expand Down Expand Up @@ -800,6 +818,8 @@ static void svc_start_real(void)
static int
svc_start(void)
{
add_environment(NULL);

if (dry_run)
einfon("start:");
else
Expand Down Expand Up @@ -912,8 +932,9 @@ svc_stop_deps(RC_SERVICE state)
return;

TAILQ_FOREACH(svc, tmplist, entries) {
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED) {
continue;
}
svc_wait(svc->value);
if (rc_service_state(svc->value) & RC_SERVICE_STOPPED)
continue;
Expand Down Expand Up @@ -984,9 +1005,10 @@ svc_stop_real(void)
static int
svc_stop(void)
{
RC_SERVICE state;
RC_SERVICE state = 0;

add_environment(NULL);

state = 0;
if (dry_run)
einfon("stop:");
else
Expand Down
5 changes: 5 additions & 0 deletions src/rc-env/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
executable('rc-env', 'rc-env.c',
include_directories: incdir,
dependencies: [rc, einfo, shared],
install: true,
install_dir: sbindir)
Loading