From a14ee4ab9b6b622475c9520fb3d08e6f78b08881 Mon Sep 17 00:00:00 2001 From: Christian Heim Date: Fri, 2 Dec 2005 10:56:06 +0000 Subject: Import the latest baselayout changes. Merging revision 1658. svn path=/baselayout-vserver/trunk/; revision=127 --- src/core/src/Makefile.am | 17 +++ src/core/src/depscan.c | 298 +++++++++++++++++++++++++++++++++++++++++++++++ src/core/src/runscript.c | 237 +++++++++++++++++++++++++++++++++++++ 3 files changed, 552 insertions(+) create mode 100644 src/core/src/Makefile.am create mode 100644 src/core/src/depscan.c create mode 100644 src/core/src/runscript.c (limited to 'src/core/src') diff --git a/src/core/src/Makefile.am b/src/core/src/Makefile.am new file mode 100644 index 0000000..27d52d9 --- /dev/null +++ b/src/core/src/Makefile.am @@ -0,0 +1,17 @@ +sbin_PROGRAMS = \ + depscan \ + runscript + +INCLUDES = \ + -I$(top_srcdir) \ + $(RCSCRIPTS_DEFINES) + +LIBRCSCRIPTS = $(top_builddir)/librcscripts/librcscripts.la + +depscan_CFLAGS = -DLEGACY_DEPSCAN +depscan_LDADD = $(LIBRCSCRIPTS) +depscan_SOURCES = depscan.c + +runscript_LDADD = $(LIBRCSCRIPTS) -ldl +runscript_SOURCES = runscript.c + diff --git a/src/core/src/depscan.c b/src/core/src/depscan.c new file mode 100644 index 0000000..8cc9da8 --- /dev/null +++ b/src/core/src/depscan.c @@ -0,0 +1,298 @@ +/* + * depscan.c + * + * Basic frontend for updating the dependency cache. + * + * Copyright (C) 2004,2005 Martin Schlemmer + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Header$ + */ + +#include +#ifndef __KLIBC__ +# include +#endif +#include +#include +#include +#include +#include +#include +#include + +#include "librcscripts/rcscripts.h" +#include "librcscripts/debug.h" +#include "librcscripts/depend.h" +#include "librcscripts/misc.h" +#include "librcscripts/parse.h" + +char* svcdir_subdirs[] = { + "softscripts", + "snapshot", + "options", + "started", + "starting", + "inactive", + "stopping", + NULL +}; + +char *svcdir_volatile_subdirs[] = { + "snapshot", + "broken", + NULL +}; + +int create_directory(const char *name); +int create_var_dirs(const char *svcdir); +int delete_var_dirs(const char *svcdir); + +int create_directory(const char *name) { + if ((NULL == name) || (0 == strlen(name))) { + DBG_MSG("Invalid argument passed!\n"); + errno = EINVAL; + return -1; + } + + /* Check if directory exist, and is not a symlink */ + if (!is_dir(name, 0)) { + if (exists(name)) { + /* Remove it if not a directory */ + if (-1 == unlink(name)) { + DBG_MSG("Failed to remove '%s'!\n", name); + return -1; + } + } + /* Now try to create the directory */ + if (-1 == mktree(name, 0755)) { + DBG_MSG("Failed to create '%s'!\n", name); + return -1; + } + } + + return 0; +} + +int create_var_dirs(const char *svcdir) { + char *tmp_path = NULL; + int i = 0; + + if ((NULL == svcdir) || (0 == strlen(svcdir))) { + DBG_MSG("Invalid argument passed!\n"); + errno = EINVAL; + return -1; + } + + /* Check and create svcdir if needed */ + if (-1 == create_directory(svcdir)) { + DBG_MSG("Failed to create '%s'!\n", svcdir); + return -1; + } + + while (NULL != svcdir_subdirs[i]) { + tmp_path = strcatpaths(svcdir, svcdir_subdirs[i]); + if (NULL == tmp_path) { + DBG_MSG("Failed to allocate buffer!\n"); + return -1; + } + + /* Check and create all the subdirs if needed */ + if (-1 == create_directory(tmp_path)) { + DBG_MSG("Failed to create '%s'!\n", tmp_path); + free(tmp_path); + return -1; + } + + free(tmp_path); + i++; + } + + return 0; +} + +int delete_var_dirs(const char *svcdir) { + char *tmp_path = NULL; + int i = 0; + + if ((NULL == svcdir) || (0 == strlen(svcdir))) { + DBG_MSG("Invalid argument passed!\n"); + errno = EINVAL; + return -1; + } + + /* Just quit if svcdir do not exist */ + if (!exists(svcdir)) { + DBG_MSG("'%s' does not exist!\n", svcdir); + return 0; + } + + while (NULL != svcdir_volatile_subdirs[i]) { + tmp_path = strcatpaths(svcdir, svcdir_volatile_subdirs[i]); + if (NULL == tmp_path) { + DBG_MSG("Failed to allocate buffer!\n"); + return -1; + } + + /* Skip the directory if it does not exist */ + if (!exists(tmp_path)) + goto _continue; + + /* Check and delete all files and sub directories if needed */ + if (-1 == rmtree(tmp_path)) { + DBG_MSG("Failed to delete '%s'!\n", tmp_path); + free(tmp_path); + return -1; + } + +_continue: + free(tmp_path); + i++; + } + + return 0; +} + +#if defined(LEGACY_DEPSCAN) + +int main() { + FILE *cachefile_fd = NULL; + char *data = NULL; + char *svcdir = NULL; + char *cachefile = NULL; + char *tmp_cachefile = NULL; + int tmp_cachefile_fd = 0; + int datasize = 0; + + /* Make sure we do not run into locale issues */ +#ifndef __KLIBC__ + setlocale (LC_ALL, "C"); +#endif + + if (0 != getuid()) { + EERROR("Must be root!\n"); + exit(EXIT_FAILURE); + } + + svcdir = get_cnf_entry(RC_CONFD_FILE_NAME, SVCDIR_CONFIG_ENTRY); + if (NULL == svcdir) { + EERROR("Failed to get config entry '%s'!\n", + SVCDIR_CONFIG_ENTRY); + exit(EXIT_FAILURE); + } + + /* Delete (if needed) volatile directories in svcdir */ + if (-1 == delete_var_dirs(svcdir)) { + /* XXX: Not 100% accurate below message ... */ + EERROR("Failed to delete '%s', %s", svcdir, + "or one of its sub directories!\n"); + exit(EXIT_FAILURE); + } + + /* Create all needed directories in svcdir */ + if (-1 == create_var_dirs(svcdir)) { + EERROR("Failed to create '%s', %s", svcdir, + "or one of its sub directories!\n"); + exit(EXIT_FAILURE); + } + + cachefile = strcatpaths(svcdir, LEGACY_CACHE_FILE_NAME); + if (NULL == cachefile) { + DBG_MSG("Failed to allocate buffer!\n"); + exit(EXIT_FAILURE); + } + + tmp_cachefile = strcatpaths(cachefile, "XXXXXX"); + if (NULL == tmp_cachefile) { + DBG_MSG("Failed to allocate buffer!\n"); + exit(EXIT_FAILURE); + } + /* Replace the "/XXXXXX" with ".XXXXXX" + * Yes, I am lazy. */ + tmp_cachefile[strlen(tmp_cachefile) - strlen(".XXXXXX")] = '.'; + + if (-1 == get_rcscripts()) { + EERROR("Failed to get rc-scripts list!\n"); + exit(EXIT_FAILURE); + } + + if (-1 == check_rcscripts_mtime(cachefile)) { + EINFO("Caching service dependencies ...\n"); + DBG_MSG("Regenerating cache file '%s'.\n", cachefile); + + datasize = generate_stage2(&data); + if (-1 == datasize) { + EERROR("Failed to generate stage2!\n"); + exit(EXIT_FAILURE); + } + + if (-1 == parse_cache(data, datasize)) { + EERROR("Failed to parse stage2 output!\n"); + free(data); + exit(EXIT_FAILURE); + } + +#if 0 + tmp_cachefile_fd = open("foo", O_CREAT | O_TRUNC | O_RDWR, 0600); + write(tmp_cachefile_fd, data, datasize); + close(tmp_cachefile_fd); +#endif + + free(data); + + if (-1 == service_resolve_dependencies()) { + EERROR("Failed to resolve dependencies!\n"); + exit(EXIT_FAILURE); + } + +#ifndef __KLIBC__ + tmp_cachefile_fd = mkstemp(tmp_cachefile); +#else + /* FIXME: Need to add a mkstemp implementation for klibc */ + tmp_cachefile_fd = open(tmp_cachefile, O_CREAT | O_TRUNC | O_RDWR, 0600); +#endif + if (-1 == tmp_cachefile_fd) { + EERROR("Could not open temporary file for writing!\n"); + exit(EXIT_FAILURE); + } + cachefile_fd = fdopen(tmp_cachefile_fd, "w"); + if (NULL == cachefile_fd) { + EERROR("Could not open temporary file for writing!\n"); + exit(EXIT_FAILURE); + } + + write_legacy_stage3(cachefile_fd); + fclose(cachefile_fd); + + if ((-1 == unlink(cachefile)) && (exists(cachefile))) { + EERROR("Could not remove '%s'!\n", cachefile); + unlink(tmp_cachefile); + exit(EXIT_FAILURE); + } + + if (-1 == rename(tmp_cachefile, cachefile)) { + EERROR("Could not move temporary file to '%s'!\n", + cachefile); + unlink(tmp_cachefile); + exit(EXIT_FAILURE); + } + } + + exit(EXIT_SUCCESS); +} + +#endif + diff --git a/src/core/src/runscript.c b/src/core/src/runscript.c new file mode 100644 index 0000000..dc3ba51 --- /dev/null +++ b/src/core/src/runscript.c @@ -0,0 +1,237 @@ +/* + * runscript.c + * Handle launching of Gentoo init scripts. + * + * Copyright 1999-2004 Gentoo Foundation + * Distributed under the terms of the GNU General Public License v2 + * $Header$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "librcscripts/rcscripts.h" +#include "librcscripts/debug.h" +#include "librcscripts/misc.h" + +#define IS_SBIN_RC() ((caller) && (0 == strcmp(caller, SBIN_RC))) + +static void (*selinux_run_init_old) (void); +static void (*selinux_run_init_new) (int argc, char **argv); + +extern char **environ; + +void setup_selinux(int argc, char **argv) { + void *lib_handle = NULL; + + lib_handle = dlopen(SELINUX_LIB, RTLD_NOW | RTLD_GLOBAL); + if (NULL != lib_handle) { + selinux_run_init_old = dlsym(lib_handle, "selinux_runscript"); + selinux_run_init_new = dlsym(lib_handle, "selinux_runscript2"); + + /* Use new run_init if it exists, else fall back to old */ + if (NULL != selinux_run_init_new) + selinux_run_init_new(argc, argv); + else if (NULL != selinux_run_init_old) + selinux_run_init_old(); + else { + /* This shouldnt happen... probably corrupt lib */ + fprintf(stderr, "Run_init is missing from runscript_selinux.so!\n"); + exit(127); + } + } +} + +char **get_whitelist(char **whitelist, char *filename) { + char *buf = NULL; + char *tmp_buf = NULL; + char *tmp_p = NULL; + char *token = NULL; + size_t lenght = 0; + int count = 0; + int current = 0; + + if (-1 == file_map(filename, &buf, &lenght)) + return NULL; + + while (current < lenght) { + count = buf_get_line(buf, lenght, current); + + tmp_buf = strndup(&buf[current], count); + if (NULL == tmp_buf) { + DBG_MSG("Failed to allocate temporary buffer!\n"); + goto error; + } + tmp_p = tmp_buf; + + /* Strip leading spaces/tabs */ + while ((tmp_p[0] == ' ') || (tmp_p[0] == '\t')) + tmp_p++; + + /* Get entry - we do not want comments, and only the first word + * on a line is valid */ + token = strsep(&tmp_p, "# \t"); + if (NULL != token && '\0' != token[0]) { + tmp_p = strndup(token, strlen(token)); + STRING_LIST_ADD(whitelist, tmp_p, error); + } + + current += count + 1; + free(tmp_buf); + /* Set to NULL in case we error out above and have + * to free below */ + tmp_buf = NULL; + } + + + file_unmap(buf, lenght); + + return whitelist; + +error: + if (NULL != tmp_buf) + free(tmp_buf); + file_unmap(buf, lenght); + STRING_LIST_FREE(whitelist); + + return NULL; +} + +char **filter_environ(char *caller) { + char **myenv = NULL; + char **whitelist = NULL; + char *env_name = NULL; + int check_profile = 1; + int count = 0; + + if (NULL != getenv(SOFTLEVEL) && !IS_SBIN_RC()) + /* Called from /sbin/rc, but not /sbin/rc itself, so current + * environment should be fine */ + return environ; + + if (1 == is_file(SYS_WHITELIST, 1)) + whitelist = get_whitelist(whitelist, SYS_WHITELIST); + else + EWARN("System environment whitelist missing!\n"); + + if (1 == is_file(USR_WHITELIST, 1)) + whitelist = get_whitelist(whitelist, USR_WHITELIST); + + if (NULL == whitelist) + /* If no whitelist is present, revert to old behaviour */ + return environ; + + if (1 != is_file(PROFILE_ENV, 1)) + /* XXX: Maybe warn here? */ + check_profile = 0; + + STRING_LIST_FOR_EACH(whitelist, env_name, count) { + char *env_var = NULL; + char *tmp_p = NULL; + int env_len = 0; + + env_var = getenv(env_name); + if (NULL != env_var) + goto add_entry; + + if (1 == check_profile) { + char *tmp_env_name = NULL; + int tmp_len = 0; + + /* The entries in PROFILE_ENV is of the form: + * export VAR_NAME=value */ + tmp_len = strlen(env_name) + strlen("export ") + 1; + tmp_env_name = calloc(tmp_len, sizeof(char *)); + if (NULL == tmp_env_name) { + DBG_MSG("Failed to allocate temporary buffer!\n"); + goto error; + } + snprintf(tmp_env_name, tmp_len, "export %s", env_name); + + /* Clear errno so that subsequent calls do not trigger + * DBG_MSG */ + errno = 0; + env_var = get_cnf_entry(PROFILE_ENV, tmp_env_name); + free(tmp_env_name); + if (NULL == env_var && ENOMSG != errno) + goto error; + else if (NULL != env_var) + goto add_entry; + } + + continue; + +add_entry: + env_len = strlen(env_name) + strlen(env_var) + 2; + tmp_p = calloc(env_len, sizeof(char *)); + if (NULL == tmp_p) { + DBG_MSG("Failed to allocate temporary buffer!\n"); + goto error; + } + snprintf(tmp_p, env_len, "%s=%s", env_name, env_var); + STRING_LIST_ADD(myenv, tmp_p, error); + } + + STRING_LIST_FREE(whitelist); + + if (NULL == myenv) + /* If all else fails, just add a default PATH */ + STRING_LIST_ADD(myenv, strdup(DEFAULT_PATH), error); + + return myenv; + +error: + STRING_LIST_FREE(myenv); + STRING_LIST_FREE(whitelist); + + return NULL; +} + +int main(int argc, char *argv[]) { + char *myargs[32]; + char **myenv = NULL; + char *caller = argv[1]; + int new = 1; + + /* Need to be /bin/bash, else BASH is invalid */ + myargs[0] = "/bin/bash"; + while (argv[new] != 0) { + myargs[new] = argv[new]; + new++; + } + myargs[new] = NULL; + + /* Do not do help for /sbin/rc */ + if (argc < 3 && !IS_SBIN_RC()) { + execv(RCSCRIPT_HELP, myargs); + exit(1); + } + + /* Setup a filtered environment according to the whitelist */ + myenv = filter_environ(caller); + if (NULL == myenv) { + EWARN("%s: Failed to filter the environment!\n", caller); + /* XXX: Might think to bail here, but it could mean the system + * is rendered unbootable, so rather not */ + myenv = environ; + } + + /* Ok, we are ready to go, so setup selinux if applicable */ + setup_selinux(argc, argv); + + if (!IS_SBIN_RC()) { + if (execve("/sbin/runscript.sh", myargs, myenv) < 0) + exit(1); + } else { + if (execve("/bin/bash", myargs, myenv) < 0) + exit(1); + } + + return 0; +} -- cgit v1.2.3-65-gdbad