Skip to content

Commit 4e4a3e0

Browse files
committed
rc-env: add new binary
1 parent d4b3e8f commit 4e4a3e0

File tree

3 files changed

+117
-0
lines changed

3 files changed

+117
-0
lines changed

src/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ subdir('pam_openrc')
2323
subdir('poweroff')
2424
subdir('rc-abort')
2525
subdir('rc-depend')
26+
subdir('rc-env')
2627
subdir('rc-service')
2728
subdir('rc-sstat')
2829
subdir('rc-status')

src/rc-env/meson.build

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
executable('rc-env', 'rc-env.c',
2+
include_directories: incdir,
3+
dependencies: [rc, einfo, shared],
4+
install: true,
5+
install_dir: sbindir)

src/rc-env/rc-env.c

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#include <rc.h>
2+
#include <einfo.h>
3+
4+
#include "helpers.h"
5+
#include "queue.h"
6+
#include "_usage.h"
7+
8+
const char *applet = NULL;
9+
const char *extraopts = NULL;
10+
const char *usagestring = "Usage: rc-env [options] [<NAME=VALUE>...]\n";
11+
const char getoptstring[] = "s:u" getoptstring_COMMON;
12+
const struct option longopts[] = {
13+
{ "service", required_argument, NULL, 's' },
14+
{ "unset", no_argument, NULL, 'u' },
15+
longopts_COMMON
16+
};
17+
const char * const longopts_help[] = {
18+
"Service whose variables to print",
19+
"Unset listed varibles",
20+
longopts_help_COMMON
21+
};
22+
23+
static void escape_variable(const char *value) {
24+
char ch;
25+
26+
printf("$'");
27+
for (const char *p = value; *p; p++) {
28+
switch ((ch = *p)) {
29+
case '\a': ch = 'a'; break;
30+
case '\b': ch = 'b'; break;
31+
case '\f': ch = 'f'; break;
32+
case '\n': ch = 'n'; break;
33+
case '\r': ch = 'r'; break;
34+
case '\t': ch = 't'; break;
35+
case '\v': ch = 'v'; break;
36+
/* \e is non-standard. */
37+
case 0x1b: ch = 'e'; break;
38+
case '"':
39+
case '\'':
40+
case '\\':
41+
break;
42+
default:
43+
putchar(ch);
44+
continue;
45+
}
46+
printf("\\%c", ch);
47+
}
48+
puts("\'\n");
49+
}
50+
51+
static void
52+
print_environment(const char *service)
53+
{
54+
/* from POSIX.2024 Shell Command Language 2.2 */
55+
static const char special_chars[] = "|&;<>()$`\\\"' \t\n*?[]^-!#~=%{},";
56+
struct rc_environ env;
57+
58+
if (!rc_environ_open(&env, service))
59+
return;
60+
61+
for (const char *name, *value; rc_environ_get(&env, &name, &value);) {
62+
if (strpbrk(value, special_chars))
63+
escape_variable(value);
64+
else
65+
puts(value);
66+
}
67+
68+
rc_environ_close(&env);
69+
}
70+
71+
int main(int argc, char **argv) {
72+
RC_STRINGLIST *services = NULL;
73+
RC_STRING *service;
74+
bool unset = false;
75+
int opt;
76+
77+
applet = basename_c(argv[0]);
78+
while ((opt = getopt_long(argc, argv, getoptstring, longopts, NULL)) != -1) {
79+
switch (opt) {
80+
case 'u': unset = true; break;
81+
case 's':
82+
if (!services)
83+
services = rc_stringlist_new();
84+
rc_stringlist_addu(services, optarg);
85+
break;
86+
case_RC_COMMON_GETOPT
87+
}
88+
}
89+
90+
argc -= optind;
91+
argv += optind;
92+
93+
if (!argc) {
94+
if (!services) {
95+
services = rc_services_in_state(RC_SERVICE_STARTED);
96+
print_environment("rc");
97+
}
98+
TAILQ_FOREACH(service, services, entries)
99+
print_environment(service->value);
100+
rc_stringlist_free(services);
101+
} else for (int i = 0; i < argc; i++) {
102+
char *value = argv[i], *name = strsep(&value, "=");
103+
104+
if (unset && value)
105+
eerror("invalid variable name '%s=%s'", name, value);
106+
else if (!unset && !value && !(value = getenv(name)))
107+
ewarn("no value found for variable '%s'", name);
108+
else
109+
rc_service_setenv(NULL, name, value);
110+
}
111+
}

0 commit comments

Comments
 (0)