openrc/src/env-update.c
Roy Marples f1bba12892 API change! rc_strlist_add and friends now take char *** instead of
char ** and return a pointer to the item added instead of the new
list head. This is so we can easily tell if the item was successfully
added or not instead of iterating through the list looking for it.

list = rc_strlist_add (list, item);
becomes
rc_strlist_add (&list, item);
2007-09-18 11:36:55 +00:00

348 lines
7.6 KiB
C

/*
env-update
Create /etc/profile.env (sh), /etc/csh.env from /etc/env.d
Run ldconfig as required
Copyright 2007 Gentoo Foundation
Released under the GPLv2
*/
#define APPLET "env-update"
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "builtins.h"
#include "einfo.h"
#include "rc.h"
#include "rc-misc.h"
#include "strlist.h"
#define ENVDIR "/etc/env.d"
#define PROFILE_ENV "/etc/profile.env"
#define CSH_ENV "/etc/csh.env"
#define LDSOCONF "/etc/ld.so.conf"
#define NOTICE "# THIS FILE IS AUTOMATICALLY GENERATED BY env-update.\n" \
"# DO NOT EDIT THIS FILE. CHANGES TO STARTUP PROFILES\n" \
"# GO INTO %s NOT %s\n\n"
#define LDNOTICE "# ld.so.conf autogenerated by env-update; make all\n" \
"# changes to contents of /etc/env.d directory\n"
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#define LD_MESSAGE "Regenerating /var/run/ld-elf.so.hints"
#define LD_SYSTEM "/sbin/ldconfig -elf -i '" LDSOCONF "'"
#else
#define LD_MESSAGE "Regenerating /etc/ld.so.cache"
#define LD_SYSTEM "/sbin/ldconfig"
#endif
static const char *colon_separated[] = {
"ADA_INCLUDE_PATH",
"ADA_OBJECTS_PATH",
"CLASSPATH",
"INFOPATH",
"KDEDIRS",
"LDPATH",
"MANPATH",
"PATH",
"PKG_CONFIG_PATH",
"PRELINK_PATH",
"PRELINK_PATH_MASK",
"PYTHONPATH",
"ROOTPATH",
NULL
};
static const char *space_separated[] = {
"CONFIG_PROTECT",
"CONFIG_PROTECT_MASK",
NULL,
};
static char *applet = NULL;
#include "_usage.h"
#define getoptstring "lL" getoptstring_COMMON
static struct option longopts[] = {
{ "fork-ldconfig", 0, NULL, 'l'},
{ "no-ldconfig", 0, NULL, 'L'},
longopts_COMMON
{ NULL, 0, NULL, 0}
};
#include "_usage.c"
int env_update (int argc, char **argv)
{
char **files = rc_ls_dir (NULL, ENVDIR, 0);
char *file;
char **envs = NULL;
char *env;
int i = 0;
int j;
FILE *fp;
bool ld = true;
char *ldent;
char **ldents = NULL;
char **config = NULL;
char *entry;
char **mycolons = NULL;
char **myspaces = NULL;
int opt;
bool ldconfig = true;
bool fork_ldconfig = false;
int nents = 0;
applet = argv[0];
while ((opt = getopt_long (argc, argv, getoptstring,
longopts, (int *) 0)) != -1)
{
switch (opt) {
case 'l':
fork_ldconfig = true;
break;
case 'L':
ldconfig = false;
break;
case_RC_COMMON_GETOPT
}
}
if (! files)
eerrorx ("%s: no files in " ENVDIR " to process", applet);
STRLIST_FOREACH (files, file, i) {
char *path = rc_strcatpaths (ENVDIR, file, (char *) NULL);
char **entries = NULL;
j = strlen (file);
if (! rc_is_dir (path) &&
j > 2 &&
*file >= '0' &&
*file <= '9' &&
*(file + 1) >= '0' &&
*(file + 1) <= '9' &&
*(file + j - 1) != '~' &&
(j < 4 || strcmp (file + j - 4, ".bak") != 0) &&
(j < 5 || strcmp (file + j - 5, ".core") != 0))
entries = rc_get_config (NULL, path);
free (path);
STRLIST_FOREACH (entries, entry, j) {
char *tmpent = rc_xstrdup (entry);
char *value = tmpent;
char *var = strsep (&value, "=");
if (strcmp (var, "COLON_SEPARATED") == 0)
while ((var = strsep (&value, " ")))
rc_strlist_addu (&mycolons, var);
else if (strcmp (var, "SPACE_SEPARATED") == 0)
while ((var = strsep (&value, " ")))
rc_strlist_addu (&myspaces, var);
else
rc_strlist_add (&config, entry);
free (tmpent);
}
rc_strlist_free (entries);
}
STRLIST_FOREACH (config, entry, i) {
char *tmpent = rc_xstrdup (entry);
char *value = tmpent;
char *var = strsep (&value, "=");
char *match;
bool colon = false;
bool space = false;
bool replaced = false;
for (j = 0; colon_separated[j]; j++)
if (strcmp (colon_separated[j], var) == 0) {
colon = true;
break;
}
if (! colon)
STRLIST_FOREACH (mycolons, match, j) {
if (strcmp (match, var) == 0) {
colon = true;
break;
} }
if (! colon)
for (j = 0; space_separated[j]; j++)
if (strcmp (space_separated[j], var) == 0) {
space = true;
break;
}
if (! colon && ! space)
STRLIST_FOREACH (myspaces, match, j)
if (strcmp (match, var) == 0) {
space = true;
break;
}
/* Skip blank vars */
if ((colon || space) &&
(! value || strlen (value)) == 0)
{
free (tmpent);
continue;
}
STRLIST_FOREACH (envs, env, j) {
char *tmpenv = rc_xstrdup (env);
char *tmpvalue = tmpenv;
char *tmpentry = strsep (&tmpvalue, "=");
if (strcmp (tmpentry, var) == 0) {
if (colon || space) {
int len = strlen (envs[j - 1]) + strlen (entry) + 1;
envs[j - 1] = rc_xrealloc (envs[j - 1], len);
snprintf (envs[j - 1] + strlen (envs[j - 1]), len,
"%s%s", colon ? ":" : " ", value);
} else {
free (envs[j - 1]);
envs[j - 1] = rc_xstrdup (entry);
}
replaced = true;
}
free (tmpenv);
if (replaced)
break;
}
if (! replaced)
rc_strlist_addsort (&envs, entry);
free (tmpent);
}
rc_strlist_free (mycolons);
rc_strlist_free (myspaces);
rc_strlist_free (config);
rc_strlist_free (files);
if ((fp = fopen (PROFILE_ENV, "w")) == NULL)
eerrorx ("%s: fopen `%s': %s", applet, PROFILE_ENV, strerror (errno));
fprintf (fp, NOTICE, "/etc/profile", PROFILE_ENV);
STRLIST_FOREACH (envs, env, i) {
char *tmpent = rc_xstrdup (env);
char *value = tmpent;
char *var = strsep (&value, "=");
if (strcmp (var, "LDPATH") != 0) {
if (*value == '$')
fprintf (fp, "export %s=%s\n", var, value);
else
fprintf (fp, "export %s='%s'\n", var, value);
}
free (tmpent);
}
fclose (fp);
if ((fp = fopen (CSH_ENV, "w")) == NULL)
eerrorx ("%s: fopen `%s': %s", applet, PROFILE_ENV, strerror (errno));
fprintf (fp, NOTICE, "/etc/csh.cshrc", PROFILE_ENV);
STRLIST_FOREACH (envs, env, i) {
char *tmpent = rc_xstrdup (env);
char *value = tmpent;
char *var = strsep (&value, "=");
if (strcmp (var, "LDPATH") != 0) {
if (*value == '$')
fprintf (fp, "setenv %s %s\n", var, value);
else
fprintf (fp, "setenv %s '%s'\n", var, value);
}
free (tmpent);
}
fclose (fp);
ldent = rc_get_config_entry (envs, "LDPATH");
if (! ldent ||
(argc > 1 && argv[1] && strcmp (argv[1], "--no-ldconfig") == 0))
{
rc_strlist_free (envs);
return (EXIT_SUCCESS);
}
while ((file = strsep (&ldent, ":"))) {
if (strlen (file) == 0)
continue;
if (rc_strlist_addu (&ldents, file))
nents++;
}
if (ldconfig) {
/* Update ld.so.conf only if different */
if (rc_exists (LDSOCONF)) {
char **lines = rc_get_list (NULL, LDSOCONF);
char *line;
ld = false;
STRLIST_FOREACH (lines, line, i)
if (i > nents || strcmp (line, ldents[i - 1]) != 0)
{
ld = true;
break;
}
rc_strlist_free (lines);
if (i - 1 != nents)
ld = true;
}
if (ld) {
int retval = 0;
pid_t pid = 0;
if ((fp = fopen (LDSOCONF, "w")) == NULL)
eerrorx ("%s: fopen `%s': %s", applet, LDSOCONF,
strerror (errno));
fprintf (fp, LDNOTICE);
STRLIST_FOREACH (ldents, ldent, i)
fprintf (fp, "%s\n", ldent);
fclose (fp);
ebegin (LD_MESSAGE);
if (fork_ldconfig) {
if ((pid = fork ()) == -1)
eerror ("%s: failed to fork: %s", applet,
strerror (errno));
else if (pid == 0) {
/* Become a proper daemon for a little bit */
int fd = open ("/dev/null", O_RDWR);
setsid ();
dup2 (fd, fileno (stdin));
dup2 (fd, fileno (stdout));
dup2 (fd, fileno (stderr));
}
}
if (pid == 0)
retval = system (LD_SYSTEM);
eend (retval, NULL);
}
}
rc_strlist_free (ldents);
rc_strlist_free (envs);
return(EXIT_SUCCESS);
}