5af58b4514
query runlevels, services and state without using bash. We also provide libeinfo so other programs can easily use our informational functions. As such, we have dropped the requirement of using bash as the init script shell. We now use /bin/sh and have strived to make the scripts as portable as possible. Shells that work are bash and dash. busybox works provided you disable s-s-d. If you have WIPE_TMP set to yes in conf.d/bootmisc you should disable find too. zsh and ksh do not work at this time. Networking support is currently being re-vamped also as it was heavily bash array based. As such, a new config format is available like so config_eth0="1.2.3.4/24 5.6.7.8/16" or like so config_eth0="'1.2.3.4 netmask 255.255.255.0' '5.6.7.8 netmask 255.255.0.0'" We will still support the old bash array format provided that /bin/sh IS a link it bash. ChangeLog for baselayout-1 can be found in our SVN repo.
751 lines
15 KiB
C
751 lines
15 KiB
C
/*
|
|
rc-misc.c
|
|
rc misc functions
|
|
Copyright 2007 Gentoo Foundation
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/utsname.h>
|
|
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include <limits.h>
|
|
#include <regex.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "einfo.h"
|
|
#include "rc-misc.h"
|
|
#include "rc.h"
|
|
#include "strlist.h"
|
|
|
|
#define ERRX eerrorx("out of memory");
|
|
|
|
#define PROFILE_ENV "/etc/profile.env"
|
|
#define SYS_WHITELIST RC_LIBDIR "conf.d/env_whitelist"
|
|
#define USR_WHITELIST "/etc/conf.d/env_whitelist"
|
|
#define RC_CONFIG "/etc/conf.d/rc"
|
|
|
|
#define PATH_PREFIX RC_LIBDIR "bin:/bin:/sbin:/usr/bin:/usr/sbin"
|
|
|
|
#ifndef S_IXUGO
|
|
# define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH)
|
|
#endif
|
|
|
|
void *rc_xcalloc (size_t n, size_t size)
|
|
{
|
|
void *value = calloc (n, size);
|
|
|
|
if (value)
|
|
return value;
|
|
|
|
ERRX
|
|
}
|
|
|
|
void *rc_xmalloc (size_t size)
|
|
{
|
|
void *value = malloc (size);
|
|
|
|
if (value)
|
|
return (value);
|
|
|
|
ERRX
|
|
}
|
|
|
|
void *rc_xrealloc (void *ptr, size_t size)
|
|
{
|
|
void *value = realloc (ptr, size);
|
|
|
|
if (value)
|
|
return (value);
|
|
|
|
ERRX
|
|
}
|
|
|
|
|
|
char *rc_xstrdup (const char *str)
|
|
{
|
|
char *value;
|
|
|
|
if (! str)
|
|
return (NULL);
|
|
|
|
value = strdup (str);
|
|
|
|
if (value)
|
|
return (value);
|
|
|
|
ERRX
|
|
}
|
|
|
|
bool rc_is_env (const char *var, const char *val)
|
|
{
|
|
char *v;
|
|
|
|
if (! var)
|
|
return (false);
|
|
|
|
v = getenv (var);
|
|
if (! v)
|
|
return (val == NULL ? true : false);
|
|
|
|
return (strcasecmp (v, val) == 0 ? true : false);
|
|
}
|
|
|
|
char *rc_strcatpaths (const char *path1, const char *paths, ...)
|
|
{
|
|
va_list ap;
|
|
int length;
|
|
int i;
|
|
char *p;
|
|
char *path;
|
|
char *pathp;
|
|
|
|
if (! path1 || ! paths)
|
|
return (NULL);
|
|
|
|
length = strlen (path1) + strlen (paths) + 3;
|
|
i = 0;
|
|
va_start (ap, paths);
|
|
while ((p = va_arg (ap, char *)) != NULL)
|
|
length += strlen (p) + 1;
|
|
va_end (ap);
|
|
|
|
path = rc_xmalloc (length);
|
|
memset (path, 0, length);
|
|
memcpy (path, path1, strlen (path1));
|
|
pathp = path + strlen (path1) - 1;
|
|
if (*pathp != '/')
|
|
{
|
|
pathp++;
|
|
*pathp++ = '/';
|
|
}
|
|
else
|
|
pathp++;
|
|
memcpy (pathp, paths, strlen (paths));
|
|
pathp += strlen (paths);
|
|
|
|
va_start (ap, paths);
|
|
while ((p = va_arg (ap, char *)) != NULL)
|
|
{
|
|
if (*pathp != '/')
|
|
*pathp++ = '/';
|
|
i = strlen (p);
|
|
memcpy (pathp, p, i);
|
|
pathp += i;
|
|
}
|
|
va_end (ap);
|
|
|
|
*pathp++ = 0;
|
|
|
|
return (path);
|
|
}
|
|
|
|
bool rc_exists (const char *pathname)
|
|
{
|
|
struct stat buf;
|
|
|
|
if (! pathname)
|
|
return (false);
|
|
|
|
if (stat (pathname, &buf) == 0)
|
|
return (true);
|
|
|
|
errno = 0;
|
|
return (false);
|
|
}
|
|
|
|
bool rc_is_file (const char *pathname)
|
|
{
|
|
struct stat buf;
|
|
|
|
if (! pathname)
|
|
return (false);
|
|
|
|
if (stat (pathname, &buf) == 0)
|
|
return (S_ISREG (buf.st_mode));
|
|
|
|
errno = 0;
|
|
return (false);
|
|
}
|
|
|
|
bool rc_is_dir (const char *pathname)
|
|
{
|
|
struct stat buf;
|
|
|
|
if (! pathname)
|
|
return (false);
|
|
|
|
if (stat (pathname, &buf) == 0)
|
|
return (S_ISDIR (buf.st_mode));
|
|
|
|
errno = 0;
|
|
return (false);
|
|
}
|
|
|
|
bool rc_is_link (const char *pathname)
|
|
{
|
|
struct stat buf;
|
|
|
|
if (! pathname)
|
|
return (false);
|
|
|
|
if (lstat (pathname, &buf) == 0)
|
|
return (S_ISLNK (buf.st_mode));
|
|
|
|
errno = 0;
|
|
return (false);
|
|
}
|
|
|
|
bool rc_is_exec (const char *pathname)
|
|
{
|
|
struct stat buf;
|
|
|
|
if (! pathname)
|
|
return (false);
|
|
|
|
if (lstat (pathname, &buf) == 0)
|
|
return (buf.st_mode & S_IXUGO);
|
|
|
|
errno = 0;
|
|
return (false);
|
|
}
|
|
|
|
char **rc_ls_dir (char **list, const char *dir, int options)
|
|
{
|
|
DIR *dp;
|
|
struct dirent *d;
|
|
|
|
if (! dir)
|
|
return (list);
|
|
|
|
if ((dp = opendir (dir)) == NULL)
|
|
{
|
|
eerror ("failed to opendir `%s': %s", dir, strerror (errno));
|
|
return (list);
|
|
}
|
|
|
|
errno = 0;
|
|
while (((d = readdir (dp)) != NULL) && errno == 0)
|
|
{
|
|
if (d->d_name[0] != '.')
|
|
{
|
|
if (options & RC_LS_INITD)
|
|
{
|
|
int l = strlen (d->d_name);
|
|
char *init = rc_strcatpaths (RC_INITDIR, d->d_name, NULL);
|
|
bool ok = rc_exists (init);
|
|
free (init);
|
|
if (! ok)
|
|
continue;
|
|
|
|
/* .sh files are not init scripts */
|
|
if (l > 2 && d->d_name[l - 3] == '.' &&
|
|
d->d_name[l - 2] == 's' &&
|
|
d->d_name[l - 1] == 'h')
|
|
continue;
|
|
}
|
|
list = rc_strlist_addsort (list, d->d_name);
|
|
}
|
|
}
|
|
closedir (dp);
|
|
|
|
if (errno != 0)
|
|
{
|
|
eerror ("failed to readdir `%s': %s", dir, strerror (errno));
|
|
rc_strlist_free (list);
|
|
return (NULL);
|
|
}
|
|
|
|
return (list);
|
|
}
|
|
|
|
bool rc_rm_dir (const char *pathname, bool top)
|
|
{
|
|
DIR *dp;
|
|
struct dirent *d;
|
|
|
|
if (! pathname)
|
|
return (false);
|
|
|
|
if ((dp = opendir (pathname)) == NULL)
|
|
{
|
|
eerror ("failed to opendir `%s': %s", pathname, strerror (errno));
|
|
return (false);
|
|
}
|
|
|
|
errno = 0;
|
|
while (((d = readdir (dp)) != NULL) && errno == 0)
|
|
{
|
|
if (strcmp (d->d_name, ".") != 0 && strcmp (d->d_name, "..") != 0)
|
|
{
|
|
char *tmp = rc_strcatpaths (pathname, d->d_name, NULL);
|
|
if (d->d_type == DT_DIR)
|
|
{
|
|
if (! rc_rm_dir (tmp, true))
|
|
{
|
|
free (tmp);
|
|
closedir (dp);
|
|
return (false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (unlink (tmp))
|
|
{
|
|
eerror ("failed to unlink `%s': %s", tmp, strerror (errno));
|
|
free (tmp);
|
|
closedir (dp);
|
|
return (false);
|
|
}
|
|
}
|
|
free (tmp);
|
|
}
|
|
}
|
|
if (errno != 0)
|
|
eerror ("failed to readdir `%s': %s", pathname, strerror (errno));
|
|
closedir (dp);
|
|
|
|
if (top && rmdir (pathname) != 0)
|
|
{
|
|
eerror ("failed to rmdir `%s': %s", pathname, strerror (errno));
|
|
return false;
|
|
}
|
|
|
|
return (true);
|
|
}
|
|
|
|
char **rc_get_config (char **list, const char *file)
|
|
{
|
|
FILE *fp;
|
|
char buffer[RC_LINEBUFFER];
|
|
char *p;
|
|
char *token;
|
|
char *line;
|
|
char *linep;
|
|
char *linetok;
|
|
int i = 0;
|
|
bool replaced;
|
|
char *entry;
|
|
char *newline;
|
|
|
|
if (! (fp = fopen (file, "r")))
|
|
{
|
|
ewarn ("load_config_file `%s': %s", file, strerror (errno));
|
|
return (list);
|
|
}
|
|
|
|
while (fgets (buffer, RC_LINEBUFFER, fp))
|
|
{
|
|
p = buffer;
|
|
|
|
/* Strip leading spaces/tabs */
|
|
while ((*p == ' ') || (*p == '\t'))
|
|
p++;
|
|
|
|
if (! p || strlen (p) < 3 || p[0] == '#')
|
|
continue;
|
|
|
|
/* Get entry */
|
|
token = strsep (&p, "=");
|
|
if (! token)
|
|
continue;
|
|
|
|
entry = rc_xstrdup (token);
|
|
|
|
do
|
|
{
|
|
/* Bash variables are usually quoted */
|
|
token = strsep (&p, "\"\'");
|
|
}
|
|
while ((token) && (strlen (token) == 0));
|
|
|
|
/* Drop a newline if that's all we have */
|
|
i = strlen (token) - 1;
|
|
if (token[i] == 10)
|
|
token[i] = 0;
|
|
|
|
i = strlen (entry) + strlen (token) + 2;
|
|
newline = rc_xmalloc (i);
|
|
snprintf (newline, i, "%s=%s", entry, token);
|
|
|
|
replaced = false;
|
|
/* In shells the last item takes precedence, so we need to remove
|
|
any prior values we may already have */
|
|
STRLIST_FOREACH (list, line, i)
|
|
{
|
|
char *tmp = rc_xstrdup (line);
|
|
linep = tmp;
|
|
linetok = strsep (&linep, "=");
|
|
if (strcmp (linetok, entry) == 0)
|
|
{
|
|
/* We have a match now - to save time we directly replace it */
|
|
free (list[i - 1]);
|
|
list[i - 1] = newline;
|
|
replaced = true;
|
|
free (tmp);
|
|
break;
|
|
}
|
|
free (tmp);
|
|
}
|
|
|
|
if (! replaced)
|
|
{
|
|
list = rc_strlist_addsort (list, newline);
|
|
free (newline);
|
|
}
|
|
free (entry);
|
|
}
|
|
fclose (fp);
|
|
|
|
return (list);
|
|
}
|
|
|
|
char *rc_get_config_entry (char **list, const char *entry)
|
|
{
|
|
char *line;
|
|
int i;
|
|
char *p;
|
|
|
|
STRLIST_FOREACH (list, line, i)
|
|
{
|
|
p = strchr (line, '=');
|
|
if (p && strncmp (entry, line, p - line) == 0)
|
|
return (p += 1);
|
|
}
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
char **rc_get_list (char **list, const char *file)
|
|
{
|
|
FILE *fp;
|
|
char buffer[RC_LINEBUFFER];
|
|
char *p;
|
|
char *token;
|
|
|
|
if (! (fp = fopen (file, "r")))
|
|
{
|
|
ewarn ("rc_get_list `%s': %s", file, strerror (errno));
|
|
return (list);
|
|
}
|
|
|
|
while (fgets (buffer, RC_LINEBUFFER, fp))
|
|
{
|
|
p = buffer;
|
|
|
|
/* Strip leading spaces/tabs */
|
|
while ((*p == ' ') || (*p == '\t'))
|
|
p++;
|
|
|
|
/* Get entry - we do not want comments */
|
|
token = strsep (&p, "#");
|
|
if (token && (strlen (token) > 1))
|
|
{
|
|
token[strlen (token) - 1] = 0;
|
|
list = rc_strlist_add (list, token);
|
|
}
|
|
}
|
|
fclose (fp);
|
|
|
|
return (list);
|
|
}
|
|
|
|
char **rc_filter_env (void)
|
|
{
|
|
char **env = NULL;
|
|
char **whitelist = NULL;
|
|
char *env_name = NULL;
|
|
char **profile = NULL;
|
|
int count = 0;
|
|
bool got_path = false;
|
|
char *env_var;
|
|
int env_len;
|
|
char *p;
|
|
char *token;
|
|
char *sep;
|
|
char *e;
|
|
int pplen = strlen (PATH_PREFIX);
|
|
|
|
whitelist = rc_get_list (whitelist, SYS_WHITELIST);
|
|
if (! whitelist)
|
|
ewarn ("system environment whitelist (" SYS_WHITELIST ") missing");
|
|
|
|
whitelist = rc_get_list (whitelist, USR_WHITELIST);
|
|
|
|
if (! whitelist)
|
|
return (NULL);
|
|
|
|
if (rc_is_file (PROFILE_ENV))
|
|
profile = rc_get_config (profile, PROFILE_ENV);
|
|
|
|
STRLIST_FOREACH (whitelist, env_name, count)
|
|
{
|
|
char *space = strchr (env_name, ' ');
|
|
if (space)
|
|
*space = 0;
|
|
|
|
env_var = getenv (env_name);
|
|
|
|
if (! env_var && profile)
|
|
{
|
|
env_len = strlen (env_name) + strlen ("export ") + 1;
|
|
p = rc_xmalloc (sizeof (char *) * env_len);
|
|
snprintf (p, env_len, "export %s", env_name);
|
|
env_var = rc_get_config_entry (profile, p);
|
|
free (p);
|
|
}
|
|
|
|
if (! env_var)
|
|
continue;
|
|
|
|
/* Ensure our PATH is prefixed with the system locations first
|
|
for a little extra security */
|
|
if (strcmp (env_name, "PATH") == 0 &&
|
|
strncmp (PATH_PREFIX, env_var, pplen) != 0)
|
|
{
|
|
got_path = true;
|
|
env_len = strlen (env_name) + strlen (env_var) + pplen + 2;
|
|
e = p = rc_xmalloc (sizeof (char *) * env_len);
|
|
p += sprintf (e, "%s=%s", env_name, PATH_PREFIX);
|
|
|
|
/* Now go through the env var and only add bits not in our PREFIX */
|
|
sep = env_var;
|
|
while ((token = strsep (&sep, ":")))
|
|
{
|
|
char *np = strdup (PATH_PREFIX);
|
|
char *npp = np;
|
|
char *tok = NULL;
|
|
while ((tok = strsep (&npp, ":")))
|
|
if (strcmp (tok, token) == 0)
|
|
break;
|
|
if (! tok)
|
|
p += sprintf (p, ":%s", token);
|
|
free (np);
|
|
}
|
|
*p++ = 0;
|
|
}
|
|
else
|
|
{
|
|
env_len = strlen (env_name) + strlen (env_var) + 2;
|
|
e = rc_xmalloc (sizeof (char *) * env_len);
|
|
snprintf (e, env_len, "%s=%s", env_name, env_var);
|
|
}
|
|
|
|
env = rc_strlist_add (env, e);
|
|
free (e);
|
|
}
|
|
|
|
/* We filtered the env but didn't get a PATH? Very odd.
|
|
However, we do need a path, so use a default. */
|
|
if (! got_path)
|
|
{
|
|
env_len = strlen ("PATH=") + strlen (PATH_PREFIX) + 2;
|
|
p = rc_xmalloc (sizeof (char *) * env_len);
|
|
snprintf (p, env_len, "PATH=%s", PATH_PREFIX);
|
|
env = rc_strlist_add (env, p);
|
|
free (p);
|
|
}
|
|
|
|
rc_strlist_free (whitelist);
|
|
rc_strlist_free (profile);
|
|
|
|
return (env);
|
|
}
|
|
|
|
/* Other systems may need this at some point, but for now it's Linux only */
|
|
#ifdef __linux__
|
|
static bool file_regex (const char *file, const char *regex)
|
|
{
|
|
FILE *fp;
|
|
char buffer[RC_LINEBUFFER];
|
|
regex_t re;
|
|
bool retval = false;
|
|
int result;
|
|
|
|
if (! rc_exists (file))
|
|
return (false);
|
|
|
|
if (! (fp = fopen (file, "r")))
|
|
{
|
|
ewarn ("file_regex `%s': %s", file, strerror (errno));
|
|
return (false);
|
|
}
|
|
|
|
if ((result = regcomp (&re, regex, REG_EXTENDED | REG_NOSUB)) != 0)
|
|
{
|
|
fclose (fp);
|
|
regerror (result, &re, buffer, sizeof (buffer));
|
|
eerror ("file_regex: %s", buffer);
|
|
return (false);
|
|
}
|
|
|
|
while (fgets (buffer, RC_LINEBUFFER, fp))
|
|
{
|
|
if (regexec (&re, buffer, 0, NULL, 0) == 0)
|
|
{
|
|
retval = true;
|
|
break;
|
|
}
|
|
}
|
|
fclose (fp);
|
|
regfree (&re);
|
|
|
|
return (retval);
|
|
}
|
|
#endif
|
|
|
|
char **rc_config_env (char **env)
|
|
{
|
|
char *line;
|
|
int i;
|
|
char *p;
|
|
char **config = rc_get_config (NULL, RC_CONFIG);
|
|
char *e;
|
|
char sys[6];
|
|
struct utsname uts;
|
|
bool has_net_fs_list = false;
|
|
FILE *fp;
|
|
char buffer[PATH_MAX];
|
|
|
|
STRLIST_FOREACH (config, line, i)
|
|
{
|
|
p = strchr (line, '=');
|
|
if (! p)
|
|
continue;
|
|
|
|
*p = 0;
|
|
e = getenv (line);
|
|
if (! e)
|
|
{
|
|
*p = '=';
|
|
env = rc_strlist_add (env, line);
|
|
}
|
|
else
|
|
{
|
|
int len = strlen (line) + strlen (e) + 2;
|
|
char *new = rc_xmalloc (sizeof (char *) * len);
|
|
snprintf (new, len, "%s=%s", line, e);
|
|
env = rc_strlist_add (env, new);
|
|
free (new);
|
|
}
|
|
}
|
|
rc_strlist_free (config);
|
|
|
|
i = strlen ("RC_LIBDIR=//rcscripts") + strlen (LIBDIR) + 2;
|
|
line = rc_xmalloc (sizeof (char *) * i);
|
|
snprintf (line, i, "RC_LIBDIR=/" LIBDIR "/rcscripts");
|
|
env = rc_strlist_add (env, line);
|
|
free (line);
|
|
|
|
i += strlen ("/init.d");
|
|
line = rc_xmalloc (sizeof (char *) * i);
|
|
snprintf (line, i, "RC_SVCDIR=/" LIBDIR "/rcscripts/init.d");
|
|
env = rc_strlist_add (env, line);
|
|
free (line);
|
|
|
|
env = rc_strlist_add (env, "RC_BOOTLEVEL=" RC_LEVEL_BOOT);
|
|
|
|
p = rc_get_runlevel ();
|
|
i = strlen ("RC_SOFTLEVEL=") + strlen (p) + 1;
|
|
line = rc_xmalloc (sizeof (char *) * i);
|
|
snprintf (line, i, "RC_SOFTLEVEL=%s", p);
|
|
env = rc_strlist_add (env, line);
|
|
free (line);
|
|
|
|
if (rc_exists (RC_SVCDIR "ksoftlevel"))
|
|
{
|
|
if (! (fp = fopen (RC_SVCDIR "ksoftlevel", "r")))
|
|
eerror ("fopen `%s': %s", RC_SVCDIR "ksoftlevel",
|
|
strerror (errno));
|
|
else
|
|
{
|
|
memset (buffer, 0, sizeof (buffer));
|
|
if (fgets (buffer, sizeof (buffer), fp))
|
|
{
|
|
i = strlen (buffer) - 1;
|
|
if (buffer[i] == '\n')
|
|
buffer[i] = 0;
|
|
i += strlen ("RC_DEFAULTLEVEL=") + 2;
|
|
line = rc_xmalloc (sizeof (char *) * i);
|
|
snprintf (line, i, "RC_DEFAULTLEVEL=%s", buffer);
|
|
env = rc_strlist_add (env, line);
|
|
free (line);
|
|
}
|
|
fclose (fp);
|
|
}
|
|
}
|
|
else
|
|
env = rc_strlist_add (env, "RC_DEFAULTLEVEL=" RC_LEVEL_DEFAULT);
|
|
|
|
memset (sys, 0, sizeof (sys));
|
|
|
|
/* Linux can run some funky stuff like Xen, VServer, UML, etc
|
|
We store this special system in RC_SYS so our scripts run fast */
|
|
#ifdef __linux__
|
|
if (rc_is_dir ("/proc/xen"))
|
|
{
|
|
fp = fopen ("/proc/xen/capabilities", "r");
|
|
if (fp)
|
|
{
|
|
fclose (fp);
|
|
if (file_regex ("/proc/xen/capabilities", "control_d"))
|
|
sprintf (sys, "XENU");
|
|
}
|
|
if (! sys)
|
|
sprintf (sys, "XEN0");
|
|
}
|
|
else if (file_regex ("/proc/cpuinfo", "UML"))
|
|
sprintf (sys, "UML");
|
|
else if (file_regex ("/proc/self/status",
|
|
"(s_context|VxID|envID):[[:space:]]*[1-9]"))
|
|
sprintf(sys, "VPS");
|
|
#endif
|
|
|
|
/* Only add a NET_FS list if not defined */
|
|
STRLIST_FOREACH (env, line, i)
|
|
if (strncmp (line, "RC_NET_FS_LIST=", strlen ("RC_NET_FS_LIST=")) == 0)
|
|
{
|
|
has_net_fs_list = true;
|
|
break;
|
|
}
|
|
if (! has_net_fs_list)
|
|
{
|
|
i = strlen ("RC_NET_FS_LIST=") + strlen (RC_NET_FS_LIST_DEFAULT) + 1;
|
|
line = rc_xmalloc (sizeof (char *) * i);
|
|
snprintf (line, i, "RC_NET_FS_LIST=%s", RC_NET_FS_LIST_DEFAULT);
|
|
env = rc_strlist_add (env, line);
|
|
free (line);
|
|
}
|
|
|
|
if (sys[0])
|
|
{
|
|
i = strlen ("RC_SYS=") + strlen (sys) + 2;
|
|
line = rc_xmalloc (sizeof (char *) * i);
|
|
snprintf (line, i, "RC_SYS=%s", sys);
|
|
env = rc_strlist_add (env, line);
|
|
free (line);
|
|
}
|
|
|
|
/* Some scripts may need to take a different code path if Linux/FreeBSD, etc
|
|
To save on calling uname, we store it in an environment variable */
|
|
if (uname (&uts) == 0)
|
|
{
|
|
i = strlen ("RC_UNAME=") + strlen (uts.sysname) + 2;
|
|
line = rc_xmalloc (sizeof (char *) * i);
|
|
snprintf (line, i, "RC_UNAME=%s", uts.sysname);
|
|
env = rc_strlist_add (env, line);
|
|
free (line);
|
|
}
|
|
|
|
/* Set this var to ensure that things are POSIX, which makes scripts work
|
|
on non GNU systems with less effort. */
|
|
env = rc_strlist_add (env, "POSIXLY_CORRECT=1");
|
|
|
|
return (env);
|
|
}
|