1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
|
/*
* cpuplugd - Linux for System z Hotplug Daemon
*
* Daemon functions
*
* Copyright IBM Corp. 2007, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "cpuplugd.h"
const char *name = NAME;
static const char *pid_file = PIDFILE;
const char *const usage =
"Usage: %s [OPTIONS]\n"
"\n"
"Daemon to dynamically hotplug cpus and memory based on a set of rules\n"
"Use OPTIONS described below.\n"
"\n"
"\t-c, --config CONFIGFILE Path to the configuration file\n"
"\t-f, --foreground Run in foreground, do not detach\n"
"\t-h, --help Print this help, then exit\n"
"\t-v, --version Print version information, then exit\n"
"\t-V, --verbose Provide more verbose output\n";
/*
* Print command usage
*/
void print_usage(int is_error, char program_name[])
{
fprintf(is_error ? stderr : stdout, usage, program_name);
exit(is_error ? 1 : 0);
}
/*
* Print command version
*/
void print_version()
{
printf("%s: Linux on System z CPU hotplug daemon version %s\n",
name, RELEASE_STRING);
printf("Copyright IBM Corp. 2007, 2017\n");
exit(0);
}
/*
* Store daemon's pid so it can be stopped
*/
static int store_pid(void)
{
FILE *filp;
filp = fopen(pid_file, "w");
if (!filp) {
cpuplugd_error("cannot open pid file %s: %s\n", pid_file,
strerror(errno));
return -1;
}
fprintf(filp, "%d\n", getpid());
fclose(filp);
return 0;
}
/*
* Run daemon in background and write pid file
*/
int daemonize(void)
{
int fd, pipe_fds[2], startup_rc = 1;
pid_t pid;
if (pipe(pipe_fds) == -1) {
cpuplugd_error("cannot create pipe\n");
return -1;
}
pid = fork();
if (pid < 0)
goto close_pipe;
if (pid != 0) {
/* Wait for startup return code from daemon */
if (read(pipe_fds[0], &startup_rc, sizeof(startup_rc)) == -1)
cpuplugd_error("cannot read from pipe\n");
/* On success daemon has written pid file at this point */
exit(startup_rc);
}
/* Create new session */
if (setsid() < 0)
goto notify_parent;
/* Redirect stdin/out/err to /dev/null */
fd = open("/dev/null", O_RDWR, 0);
if (fd == -1)
goto notify_parent;
if (dup2(fd, STDIN_FILENO) < 0)
goto notify_parent;
if (dup2(fd, STDOUT_FILENO) < 0)
goto notify_parent;
if (dup2(fd, STDERR_FILENO) < 0)
goto notify_parent;
/* Create pid file */
if (store_pid() < 0)
goto notify_parent;
startup_rc = 0;
notify_parent:
/* Inform waiting parent about startup return code */
if (write(pipe_fds[1], &startup_rc, sizeof(startup_rc)) == -1) {
cpuplugd_error("cannot write to pipe\n");
startup_rc = 1;
}
close_pipe:
close(pipe_fds[0]);
close(pipe_fds[1]);
return startup_rc ? -1 : 0;
}
/*
* Check that we don't try to start this daemon twice
*/
void check_if_started_twice()
{
FILE *filp;
int pid, rc;
filp = fopen(pid_file, "r");
if (filp) {
rc = fscanf(filp, "%d", &pid);
if (rc != 1) {
cpuplugd_error("Reading pid file failed. Aborting!\n");
exit(1);
}
cpuplugd_error("pid file %s still exists.\nThis might indicate "
"that an instance of this daemon is already "
"running.\n", pid_file);
exit(1);
}
}
/*
* Clean up method
*/
void clean_up()
{
cpuplugd_info("terminated\n");
remove(pid_file);
remove(LOCKFILE);
/* suppress verbose messages on exit */
debug = 0;
reactivate_cpus();
if (memory)
cleanup_cmm();
exit(1);
}
/*
* End the deamon
*/
void kill_daemon(int UNUSED(a))
{
cpuplugd_info("shutting down\n");
remove(pid_file);
remove(LOCKFILE);
/* suppress verbose messages on exit */
debug = 0;
reactivate_cpus();
if (memory)
cleanup_cmm();
exit(0);
}
/*
* Reload the daemon (for lsb compliance)
*/
void reload_handler(int UNUSED(a))
{
reload_pending = 1;
}
void reload_daemon()
{
unsigned int temp_history;
long temp_mem;
int temp_cpu;
cpuplugd_info("cpuplugd restarted\n");
/*
* Before we parse the configuration file again we have to save
* the original values prior to startup. If we don't do this cpuplugd
* will no longer know how many cpus the system had before the daemon
* was started and therefor can't restore theres in case it is stopped
*/
temp_cpu = num_cpu_start;
temp_mem = cmm_pagesize_start;
temp_history = history_max;
/* clear varinfo before re-reading variables from config file */
memset(varinfo, 0, varinfo_size);
history_max = 1;
parse_configfile(configfile);
if (history_max > MAX_HISTORY)
cpuplugd_exit("History depth %i exceeded maximum (%i)\n",
history_max, MAX_HISTORY);
if (history_max != temp_history) {
free(meminfo);
free(vmstat);
free(cpustat);
free(timestamps);
setup_history();
}
check_config();
num_cpu_start = temp_cpu;
cmm_pagesize_start = temp_mem;
}
/*
* Set up for handling SIGTERM or SIGINT
*/
void handle_signals(void)
{
struct sigaction act;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
act.sa_handler = kill_daemon;
if (sigaction(SIGTERM, &act, NULL) < 0) {
cpuplugd_error("sigaction( SIGTERM, ... ) failed - reason %s\n",
strerror(errno));
exit(1);
}
if (sigaction(SIGINT, &act, NULL) < 0) {
cpuplugd_error("sigaction( SIGINT, ... ) failed - reason %s\n",
strerror(errno));
exit(1);
}
}
/*
* Signal handler for sighup. This is used to force the deamon to reload its
* configuration file.
* This feature is also required by a lsb compliant init script
*/
void handle_sighup(void)
{
struct sigaction act;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
act.sa_handler = reload_handler;
if (sigaction(SIGHUP, &act, NULL) < 0) {
cpuplugd_error("sigaction( SIGHUP, ... ) failed - reason %s\n",
strerror(errno));
exit(1);
}
}
/* Check if we are running in an LPAR environment.
* This functions return 1 if we run inside an lpar and 0 otherwise
*/
int check_lpar()
{
int rc;
FILE *filp;
size_t bytes_read;
char buffer[2048];
char *contains_vm;
rc = 0;
filp = fopen("/proc/cpuinfo", "r");
if (!filp)
cpuplugd_exit("cannot open /proc/cpuinfo: %s\n",
strerror(errno));
bytes_read = fread(buffer, 1, sizeof(buffer) - 1, filp);
if (bytes_read == 0)
cpuplugd_exit("Reading /proc/cpuinfo failed: %s\n",
strerror(errno));
/* NUL-terminate the text */
buffer[bytes_read] = '\0';
contains_vm = strstr(buffer, "version = FF");
if (contains_vm == NULL) {
rc = 1;
cpuplugd_debug("Detected System running in LPAR mode\n");
} else
cpuplugd_debug("Detected System running in z/VM mode\n");
fclose(filp);
return rc;
}
|