|  | /* | 
|  | *  Copyright (C) 2000-2006 SWsoft. All rights reserved. | 
|  | * | 
|  | *  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; either version 2 of the License, or | 
|  | *  (at your option) any later version. | 
|  | * | 
|  | *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
|  | */ | 
|  |  | 
|  | #include <stdlib.h> | 
|  | #include <stdio.h> | 
|  | #include <sys/types.h> | 
|  | #include <sys/stat.h> | 
|  | #include <fcntl.h> | 
|  | #include <unistd.h> | 
|  | #include <errno.h> | 
|  | #include <string.h> | 
|  | #include <sys/wait.h> | 
|  | #include <signal.h> | 
|  | #include <sys/stat.h> | 
|  |  | 
|  | #include "types.h" | 
|  | #include "util.h" | 
|  | #include "list.h" | 
|  | #include "logger.h" | 
|  | #include "vzerror.h" | 
|  | #include "util.h" | 
|  | #include "script.h" | 
|  | #include "fs.h" | 
|  |  | 
|  | volatile sig_atomic_t alarm_flag; | 
|  | static char *envp_bash[] = {"HOME=/", "TERM=linux", "PATH=/bin:/sbin:/usr/bin:/usr/sbin:", NULL}; | 
|  |  | 
|  | int read_script(const char *fname, char *include, char **buf) | 
|  | { | 
|  | struct stat st; | 
|  | char *tmp, *p = NULL; | 
|  | int  fd, len = 0; | 
|  | char *inc; | 
|  |  | 
|  | if (!fname) { | 
|  | logger(-1, 0, "read_script: file name not specified"); | 
|  | return -1; | 
|  | } | 
|  | /* Read include file first */ | 
|  | if (include != NULL) { | 
|  | inc = malloc(strlen(fname) + strlen(include) + 1); | 
|  | if ((p = strrchr(fname, '/')) != NULL) { | 
|  | snprintf(inc, p - fname + 2, "%s", fname); | 
|  | strcat(inc, include); | 
|  | } else { | 
|  | snprintf(inc, sizeof(inc), "%s", include); | 
|  | } | 
|  | if (stat_file(inc)) | 
|  | len = read_script(inc, NULL, buf); | 
|  | if (inc != NULL) free(inc); | 
|  | if (len < 0) | 
|  | return -1; | 
|  | } | 
|  | if (stat(fname, &st)) { | 
|  | logger(-1, 0, "file %s not found", fname); | 
|  | return -1; | 
|  | } | 
|  | if ((fd = open(fname, O_RDONLY)) < 0) { | 
|  | logger(-1, errno, "Unable to open %s", fname); | 
|  | goto err; | 
|  | } | 
|  | if (*buf != NULL) { | 
|  | tmp = realloc(*buf, st.st_size + len + 2); | 
|  | if (tmp ==  NULL) | 
|  | goto err; | 
|  | *buf = tmp; | 
|  | p = *buf + len; | 
|  | } else { | 
|  | *buf = malloc(st.st_size + 2); | 
|  | if (*buf == NULL) | 
|  | goto err; | 
|  | p = *buf; | 
|  | } | 
|  | if ((len =  read(fd, p, st.st_size)) < 0) { | 
|  | logger(-1, errno, "Error reading %s", fname); | 
|  | goto err; | 
|  | } | 
|  | p += len; | 
|  | p[0] = '\n'; | 
|  | p[1] = 0; | 
|  | close(fd); | 
|  |  | 
|  | return len; | 
|  | err: | 
|  | if (fd > 0) | 
|  | close(fd); | 
|  | if (*buf != NULL) | 
|  | free(*buf); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | #define ENV_SIZE	256 | 
|  | int run_script(const char *f, char *argv[], char *env[], int quiet) | 
|  | { | 
|  | int child, pid, fd; | 
|  | int status; | 
|  | int ret, i; | 
|  | char *cmd; | 
|  | struct sigaction act, actold; | 
|  | int out[2]; | 
|  | char *envp[ENV_SIZE]; | 
|  |  | 
|  | if (!stat_file(f)) { | 
|  | logger(-1, 0, "File %s not found", f); | 
|  | return VZ_NOSCRIPT; | 
|  | } | 
|  | sigaction(SIGCHLD, NULL, &actold); | 
|  | sigemptyset(&act.sa_mask); | 
|  | act.sa_handler = SIG_DFL; | 
|  | act.sa_flags = SA_NOCLDSTOP; | 
|  | sigaction(SIGCHLD, &act, NULL); | 
|  |  | 
|  | cmd = arg2str(argv); | 
|  | if (cmd != NULL) { | 
|  | logger(2, 0, "Running: %s", cmd); | 
|  | free(cmd); | 
|  | } | 
|  | if (quiet && pipe(out) < 0) { | 
|  | logger(-1, errno, "run_script: unable to create pipe"); | 
|  | return -1; | 
|  | } | 
|  | i = 0; | 
|  | if (env != NULL) { | 
|  | for (i = 0; i < ENV_SIZE - 1 && env[i] != NULL; i++) | 
|  | envp[i] = env[i]; | 
|  | } | 
|  | for (; i < ENV_SIZE - 1 && envp_bash[i] != NULL; i++) | 
|  | envp[i] = envp_bash[i]; | 
|  | envp[i] = NULL; | 
|  | if ((child = fork()) == 0) { | 
|  | fd = open("/dev/null", O_WRONLY); | 
|  | if (fd < 0) | 
|  | close(0); | 
|  | else | 
|  | dup2(fd, 0); | 
|  |  | 
|  | if (quiet) { | 
|  | dup2(fd, 1); | 
|  | dup2(fd, 2); | 
|  | } else { | 
|  | /* | 
|  | dup2(out[1], STDOUT_FILENO); | 
|  | dup2(out[1], STDERR_FILENO); | 
|  | close(out[0]); | 
|  | close(out[1]); | 
|  | */ | 
|  | } | 
|  | execve(f, argv, envp); | 
|  | logger(-1, errno, "Error exec %s", f); | 
|  | exit(1); | 
|  | } else if(child == -1) { | 
|  | logger(-1, errno, "Unable to fork"); | 
|  | ret = VZ_RESOURCE_ERROR; | 
|  | goto err; | 
|  | } | 
|  | while ((pid = waitpid(child, &status, 0)) == -1) | 
|  | if (errno != EINTR) | 
|  | break; | 
|  | ret = VZ_SYSTEM_ERROR; | 
|  | if (pid == child) { | 
|  | if (WIFEXITED(status)) | 
|  | ret = WEXITSTATUS(status); | 
|  | else if (WIFSIGNALED(status)) | 
|  | logger(-1, 0, "Received signal:" | 
|  | "  %d in %s", WTERMSIG(status), f); | 
|  | } else { | 
|  | logger(-1, errno, "Error in waitpid"); | 
|  | } | 
|  | err: | 
|  | sigaction(SIGCHLD, &actold, NULL); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | int run_pre_script(int veid, char *script) | 
|  | { | 
|  | char *arg[2]; | 
|  | char *env[4]; | 
|  | char buf[STR_SIZE]; | 
|  | int ret; | 
|  |  | 
|  | if (!stat_file(script)) | 
|  | return 0; | 
|  | /* cmd parameters */ | 
|  | arg[0] = script; | 
|  | arg[1] = NULL; | 
|  | /* enviroment parameters*/ | 
|  | snprintf(buf, sizeof(buf), "VEID=%d", veid); | 
|  | env[0] = strdup(buf); | 
|  | snprintf(buf, sizeof(buf), "VE_CONFFILE=%s%d.conf", VPS_CONF_DIR, veid); | 
|  | env[1] = strdup(buf); | 
|  | env[2] = strdup(ENV_PATH); | 
|  | env[3] = NULL; | 
|  | /* | 
|  | if ((dist = get_ostmpl(gparam)) != NULL) { | 
|  | snprintf(buf,  sizeof(buf), "DIST=%s", dist); | 
|  | env = ListAddElem(env, buf, NULL, NULL); | 
|  | } | 
|  | */ | 
|  | if ((ret = run_script(script, arg, env, 0))) | 
|  | ret = VZ_ACTIONSCRIPT_ERROR; | 
|  | free_arg(env); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | int mk_reboot_script() | 
|  | { | 
|  | char buf[STR_SIZE]; | 
|  | char *rc; | 
|  | int fd; | 
|  | #define REBOOT_MARK	"/reboot" | 
|  | #define VZREBOOT	"S00vzreboot" | 
|  | #define RC1		"/etc/rc.d/rc6.d" | 
|  | #define RC2		"/etc/rc6.d" | 
|  | #define REBOOT_SCRIPT	"#!/bin/bash\n>/" REBOOT_MARK | 
|  |  | 
|  | /* remove reboot flag  */ | 
|  | unlink(REBOOT_MARK); | 
|  | rc = NULL; | 
|  | if (stat_file(RC1)) | 
|  | rc = RC1; | 
|  | if (stat_file(RC2)) | 
|  | rc = RC2; | 
|  | if (rc == NULL) | 
|  | return 1; | 
|  | sprintf(buf, "%s/" VZREBOOT, rc); | 
|  | if ((fd = open(buf, O_CREAT|O_WRONLY|O_TRUNC, 0755)) < 0) { | 
|  | logger(-1, errno, "Unable to create %s", buf); | 
|  | return 1; | 
|  | } | 
|  | write(fd, REBOOT_SCRIPT, sizeof(REBOOT_SCRIPT)); | 
|  | close(fd); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #define PROC_QUOTA	"/proc/vz/vzaquota/" | 
|  | #define QUOTA_U		"/aquota.user" | 
|  | #define QUOTA_G		"/aquota.group" | 
|  | int mk_quota_link() | 
|  | { | 
|  | struct stat st; | 
|  | const char *fs; | 
|  | char buf[64]; | 
|  |  | 
|  | if (stat("/", &st)) { | 
|  | logger(-1, errno, "Unable to stat /"); | 
|  | return -1; | 
|  | } | 
|  | fs = vz_fs_get_name(); | 
|  | /* make dev */ | 
|  | snprintf(buf, sizeof(buf), "/dev/%s", fs); | 
|  | unlink(buf); | 
|  | logger(3, 0, "Setup quota dev %s", buf); | 
|  | if (mknod(buf, S_IFBLK | S_IXGRP, st.st_dev)) | 
|  | logger(-1, errno, "Unable to create %s", buf); | 
|  | snprintf(buf, sizeof(buf), PROC_QUOTA "%08lx" QUOTA_U, | 
|  | (unsigned long)st.st_dev); | 
|  | unlink(QUOTA_U); | 
|  | if (symlink(buf, QUOTA_U)) | 
|  | logger(-1, errno, "Unable to create symlink %s", buf); | 
|  | snprintf(buf, sizeof(buf), PROC_QUOTA "%08lx" QUOTA_G, | 
|  | (unsigned long)st.st_dev); | 
|  | unlink(QUOTA_G); | 
|  | if (symlink(buf, QUOTA_G)) | 
|  | logger(-1, errno, "Unable to create symlink %s", buf); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #define INITTAB_FILE		"/etc/inittab" | 
|  | #define INITTAB_VZID		"vz:" | 
|  | #define INITTAB_ACTION		INITTAB_VZID "35:once:touch " VZFIFO_FILE "\n" | 
|  | #define MAX_WAIT_TIMEOUT	60 * 60 | 
|  |  | 
|  | int add_reach_runlevel_mark() | 
|  | { | 
|  | int fd, found, len, ret; | 
|  | char buf[4096]; | 
|  |  | 
|  | unlink(VZFIFO_FILE); | 
|  | if (mkfifo(VZFIFO_FILE, 0644)) { | 
|  | fprintf(stderr, "Unable to create " VZFIFO_FILE " %s\n", | 
|  | strerror(errno)); | 
|  | return -1; | 
|  | } | 
|  | if ((fd = open(INITTAB_FILE, O_RDWR | O_APPEND)) == -1) { | 
|  | fprintf(stderr, "Unable to open " INITTAB_FILE " %s\n", | 
|  | strerror(errno)); | 
|  | return -1; | 
|  | } | 
|  | ret = 0; | 
|  | found = 0; | 
|  | while (1) { | 
|  | len = read(fd, buf, sizeof(buf)); | 
|  | if (len == 0) | 
|  | break; | 
|  | if (len < 0) { | 
|  | fprintf(stderr, "Unable to read from " INITTAB_FILE | 
|  | " %s\n", | 
|  | strerror(errno)); | 
|  | ret = -1; | 
|  | break; | 
|  | } | 
|  | buf[len] = 0; | 
|  | if (strstr(buf, "\n" INITTAB_VZID) != NULL) { | 
|  | found = 1; | 
|  | break; | 
|  | } | 
|  | } | 
|  | if (!found) { | 
|  | if (write(fd, INITTAB_ACTION, sizeof(INITTAB_ACTION) - 1) == -1) | 
|  | { | 
|  | fprintf(stderr, "Unable to write to " INITTAB_FILE | 
|  | " %s\n", | 
|  | strerror(errno)); | 
|  | ret = -1; | 
|  | } | 
|  | } | 
|  | close(fd); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static void alarm_handler(int sig) | 
|  | { | 
|  | alarm_flag = 1; | 
|  | } | 
|  |  | 
|  | int wait_on_fifo(void *data) | 
|  | { | 
|  | int fd, buf, ret; | 
|  | struct sigaction act, actold; | 
|  |  | 
|  | ret = 0; | 
|  | alarm_flag = 0; | 
|  | act.sa_flags = 0; | 
|  | act.sa_handler = alarm_handler; | 
|  | sigemptyset(&act.sa_mask); | 
|  | sigaction(SIGALRM, &act, &actold); | 
|  |  | 
|  | alarm(MAX_WAIT_TIMEOUT); | 
|  | fd = open(VZFIFO_FILE, O_RDONLY); | 
|  | if (fd == -1) { | 
|  | fprintf(stderr, "Unable to open " VZFIFO_FILE " %s\n", | 
|  | strerror(errno)); | 
|  | ret = -1; | 
|  | goto err; | 
|  | } | 
|  | if (read(fd, &buf, sizeof(buf)) == -1) | 
|  | ret = -1; | 
|  | err: | 
|  | if (alarm_flag) | 
|  | ret = VZ_EXEC_TIMEOUT; | 
|  | alarm(0); | 
|  | sigaction(SIGALRM, &actold, NULL); | 
|  | unlink(VZFIFO_FILE); | 
|  | return ret; | 
|  | } | 
|  |  |