vlog: Add ability to log to an arbitrary file, and following related changes:
* New command-line options for configuring log files, hence: - Centralized vlog usage messages. * New vlogconf action for reopening log files. * New vlogconf support for specifying a target by pidfile.
This commit is contained in:
@@ -239,13 +239,13 @@ parse_options(int argc, char *argv[])
|
||||
{
|
||||
enum {
|
||||
OPT_MAX_IDLE = UCHAR_MAX + 1,
|
||||
OPT_PEER_CA_CERT
|
||||
OPT_PEER_CA_CERT,
|
||||
VLOG_OPTION_ENUMS
|
||||
};
|
||||
static struct option long_options[] = {
|
||||
{"hub", no_argument, 0, 'H'},
|
||||
{"noflow", no_argument, 0, 'n'},
|
||||
{"max-idle", required_argument, 0, OPT_MAX_IDLE},
|
||||
{"verbose", optional_argument, 0, 'v'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"version", no_argument, 0, 'V'},
|
||||
DAEMON_LONG_OPTIONS,
|
||||
@@ -294,10 +294,7 @@ parse_options(int argc, char *argv[])
|
||||
printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
case 'v':
|
||||
vlog_set_verbosity(optarg);
|
||||
break;
|
||||
|
||||
VLOG_OPTION_HANDLERS
|
||||
DAEMON_OPTION_HANDLERS
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
@@ -327,12 +324,11 @@ usage(void)
|
||||
program_name, program_name);
|
||||
vconn_usage(true, true, false);
|
||||
daemon_usage();
|
||||
vlog_usage();
|
||||
printf("\nOther options:\n"
|
||||
" -H, --hub act as hub instead of learning switch\n"
|
||||
" -n, --noflow pass traffic, but don't add flows\n"
|
||||
" --max-idle=SECS max idle time for new flows\n"
|
||||
" -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n"
|
||||
" -v, --verbose set maximum verbosity level\n"
|
||||
" -h, --help display this help message\n"
|
||||
" -V, --version display version information\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#define DAEMON_H 1
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define DAEMON_LONG_OPTIONS \
|
||||
{"detach", no_argument, 0, 'D'}, \
|
||||
@@ -62,5 +63,6 @@ void daemonize(void);
|
||||
void die_if_already_running(void);
|
||||
void ignore_existing_pidfile(void);
|
||||
void daemon_usage(void);
|
||||
pid_t read_pidfile(const char *name);
|
||||
|
||||
#endif /* daemon.h */
|
||||
|
||||
@@ -29,6 +29,7 @@ VLOG_MODULE(vconn_stream)
|
||||
VLOG_MODULE(vconn_unix)
|
||||
VLOG_MODULE(vconn)
|
||||
VLOG_MODULE(vlog)
|
||||
VLOG_MODULE(vlog_socket)
|
||||
|
||||
#ifdef HAVE_EXT
|
||||
#include "ext/vlogext-modules.def"
|
||||
|
||||
+23
-2
@@ -59,7 +59,8 @@ enum vlog_level vlog_get_level_val(const char *name);
|
||||
/* Facilities that we can log to. */
|
||||
#define VLOG_FACILITIES \
|
||||
VLOG_FACILITY(SYSLOG, "%05N|%c|%p|%m") \
|
||||
VLOG_FACILITY(CONSOLE, "%d{%b %d %H:%M:%S}|%05N|%c|%p|%m")
|
||||
VLOG_FACILITY(CONSOLE, "%d{%b %d %H:%M:%S}|%05N|%c|%p|%m") \
|
||||
VLOG_FACILITY(FILE, "%d{%b %d %H:%M:%S}|%05N|%c|%p|%m")
|
||||
enum vlog_facility {
|
||||
#define VLOG_FACILITY(NAME, PATTERN) VLF_##NAME,
|
||||
VLOG_FACILITIES
|
||||
@@ -115,12 +116,17 @@ struct vlog_rate_limit {
|
||||
/* Configuring how each module logs messages. */
|
||||
enum vlog_level vlog_get_level(enum vlog_module, enum vlog_facility);
|
||||
void vlog_set_levels(enum vlog_module, enum vlog_facility, enum vlog_level);
|
||||
void vlog_set_pattern(enum vlog_facility, const char *pattern);
|
||||
char *vlog_set_levels_from_string(const char *);
|
||||
char *vlog_get_levels(void);
|
||||
bool vlog_is_enabled(enum vlog_module, enum vlog_level);
|
||||
void vlog_set_verbosity(const char *arg);
|
||||
|
||||
/* Configuring log facilities. */
|
||||
void vlog_set_pattern(enum vlog_facility, const char *pattern);
|
||||
const char *vlog_get_log_file(void);
|
||||
int vlog_set_log_file(const char *file_name);
|
||||
int vlog_reopen_log_file(void);
|
||||
|
||||
/* Function for actual logging. */
|
||||
void vlog_init(void);
|
||||
void vlog_exit(void);
|
||||
@@ -164,6 +170,20 @@ void vlog_rate_limit(enum vlog_module, enum vlog_level,
|
||||
#define VLOG_DBG_RL(RL, ...) \
|
||||
vlog_rate_limit(THIS_MODULE, VLL_DBG, RL, __VA_ARGS__)
|
||||
|
||||
/* Command line processing. */
|
||||
#define VLOG_OPTION_ENUMS OPT_LOG_FILE
|
||||
#define VLOG_LONG_OPTIONS \
|
||||
{"verbose", optional_argument, 0, 'v'}, \
|
||||
{"log-file", optional_argument, 0, OPT_LOG_FILE}
|
||||
#define VLOG_OPTION_HANDLERS \
|
||||
case 'v': \
|
||||
vlog_set_verbosity(optarg); \
|
||||
break; \
|
||||
case OPT_LOG_FILE: \
|
||||
vlog_set_log_file(optarg); \
|
||||
break;
|
||||
void vlog_usage(void);
|
||||
|
||||
/* Implementation details. */
|
||||
#define VLOG(LEVEL, ...) \
|
||||
do { \
|
||||
@@ -173,4 +193,5 @@ void vlog_rate_limit(enum vlog_module, enum vlog_level,
|
||||
} while (0)
|
||||
extern enum vlog_level min_vlog_levels[VLM_N_MODULES];
|
||||
|
||||
|
||||
#endif /* vlog.h */
|
||||
|
||||
@@ -246,3 +246,51 @@ daemon_usage(void)
|
||||
" -f, --force with -P, start even if already running\n",
|
||||
ofp_rundir, program_name);
|
||||
}
|
||||
|
||||
/* Opens and reads a PID from 'pidfile'. Returns the nonnegative PID if
|
||||
* successful, otherwise a negative errno value. */
|
||||
pid_t
|
||||
read_pidfile(const char *pidfile)
|
||||
{
|
||||
char line[128];
|
||||
struct flock lck;
|
||||
FILE *file;
|
||||
int error;
|
||||
|
||||
file = fopen(pidfile, "r");
|
||||
if (!file) {
|
||||
error = errno;
|
||||
VLOG_WARN("%s: open: %s", pidfile, strerror(error));
|
||||
goto error;
|
||||
}
|
||||
|
||||
lck.l_type = F_WRLCK;
|
||||
lck.l_whence = SEEK_SET;
|
||||
lck.l_start = 0;
|
||||
lck.l_len = 0;
|
||||
if (fcntl(fileno(file), F_GETLK, &lck)) {
|
||||
error = errno;
|
||||
VLOG_WARN("%s: fcntl: %s", pidfile, strerror(error));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!fgets(line, sizeof line, file)) {
|
||||
error = errno;
|
||||
VLOG_WARN("%s: read: %s", pidfile, strerror(error));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (lck.l_pid != strtoul(line, NULL, 10)) {
|
||||
error = ESRCH;
|
||||
VLOG_WARN("l_pid (%ld) != %s pid (%s)",
|
||||
(long int) lck.l_pid, pidfile, line);
|
||||
goto error;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return lck.l_pid;
|
||||
|
||||
error:
|
||||
fclose(file);
|
||||
return -error;
|
||||
}
|
||||
|
||||
+63
-23
@@ -33,6 +33,7 @@
|
||||
|
||||
#include <config.h>
|
||||
#include "vlog-socket.h"
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <sys/un.h>
|
||||
#include <fcntl.h>
|
||||
@@ -43,16 +44,19 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include "daemon.h"
|
||||
#include "fatal-signal.h"
|
||||
#include "poll-loop.h"
|
||||
#include "socket-util.h"
|
||||
#include "timeval.h"
|
||||
#include "util.h"
|
||||
#include "vlog.h"
|
||||
|
||||
#ifndef SCM_CREDENTIALS
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#define THIS_MODULE VLM_vlog_socket
|
||||
#include "vlog.h"
|
||||
|
||||
/* Server for Vlog control connection. */
|
||||
struct vlog_server {
|
||||
@@ -256,6 +260,12 @@ poll_server(int fd UNUSED, short int events, void *server_)
|
||||
reply = msg ? msg : xstrdup("ack");
|
||||
} else if (!strcmp(cmd_buf, "list")) {
|
||||
reply = vlog_get_levels();
|
||||
} else if (!strcmp(cmd_buf, "reopen")) {
|
||||
int error = vlog_reopen_log_file();
|
||||
reply = (error
|
||||
? xasprintf("could not reopen log file \"%s\": %s",
|
||||
vlog_get_log_file(), strerror(error))
|
||||
: xstrdup("ack"));
|
||||
} else {
|
||||
reply = xstrdup("nak");
|
||||
}
|
||||
@@ -274,11 +284,18 @@ struct vlog_client {
|
||||
int fd;
|
||||
};
|
||||
|
||||
/* Connects to a Vlog server socket. If 'path' does not start with '/', then
|
||||
* it start with a PID as a string. If a non-null, non-absolute name was
|
||||
* passed to Vlog_server_socket::listen(), then it must follow the PID in
|
||||
* 'path'. If 'path' starts with '/', then it must be an absolute path that
|
||||
* gives the exact name of the Unix domain socket to connect to.
|
||||
/* Connects to a Vlog server socket. 'path' may be:
|
||||
*
|
||||
* - A string that starts with a PID. If a non-null, non-absolute name
|
||||
* was passed to Vlog_server_socket::listen(), then it must follow the
|
||||
* PID in 'path'.
|
||||
*
|
||||
* - An absolute path (starting with '/') to a Vlog server socket or a
|
||||
* pidfile. If it is a pidfile, the pidfile will be read and translated
|
||||
* into a Vlog server socket file name.
|
||||
*
|
||||
* - A relative path, which is translated into a pidfile name and then
|
||||
* treated as above.
|
||||
*
|
||||
* Returns 0 if successful, otherwise a positive errno value. If successful,
|
||||
* sets '*clientp' to the new vlog_client, otherwise to NULL. */
|
||||
@@ -287,29 +304,52 @@ vlog_client_connect(const char *path, struct vlog_client **clientp)
|
||||
{
|
||||
static int counter;
|
||||
struct vlog_client *client;
|
||||
int fd;
|
||||
struct stat s;
|
||||
int error;
|
||||
|
||||
client = xmalloc(sizeof *client);
|
||||
client->connect_path = (path[0] == '/'
|
||||
? xstrdup(path)
|
||||
: xasprintf("/tmp/vlogs.%s", path));
|
||||
if (path[0] == '/') {
|
||||
client->connect_path = xstrdup(path);
|
||||
} else if (isdigit((unsigned char) path[0])) {
|
||||
client->connect_path = xasprintf("/tmp/vlogs.%s", path);
|
||||
} else {
|
||||
client->connect_path = make_pidfile_name(path);
|
||||
}
|
||||
client->bind_path = NULL;
|
||||
|
||||
if (stat(client->connect_path, &s)) {
|
||||
error = errno;
|
||||
VLOG_WARN("could not stat \"%s\": %s",
|
||||
client->connect_path, strerror(error));
|
||||
goto error;
|
||||
} else if (S_ISREG(s.st_mode)) {
|
||||
pid_t pid = read_pidfile(client->connect_path);
|
||||
if (pid < 0) {
|
||||
error = -pid;
|
||||
VLOG_WARN("could not read pidfile \"%s\": %s",
|
||||
client->connect_path, strerror(error));
|
||||
goto error;
|
||||
}
|
||||
free(client->connect_path);
|
||||
client->connect_path = xasprintf("/tmp/vlogs.%ld", (long int) pid);
|
||||
}
|
||||
client->bind_path = xasprintf("/tmp/vlog.%ld.%d",
|
||||
(long int) getpid(), counter++);
|
||||
fd = make_unix_socket(SOCK_DGRAM, false, false,
|
||||
client->bind_path, client->connect_path);
|
||||
|
||||
if (fd >= 0) {
|
||||
client->fd = fd;
|
||||
*clientp = client;
|
||||
return 0;
|
||||
} else {
|
||||
free(client->connect_path);
|
||||
free(client->bind_path);
|
||||
free(client);
|
||||
*clientp = NULL;
|
||||
return errno;
|
||||
client->fd = make_unix_socket(SOCK_DGRAM, false, false,
|
||||
client->bind_path, client->connect_path);
|
||||
if (client->fd < 0) {
|
||||
error = -client->fd;
|
||||
goto error;
|
||||
}
|
||||
*clientp = client;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
free(client->connect_path);
|
||||
free(client->bind_path);
|
||||
free(client);
|
||||
*clientp = NULL;
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Destroys 'client'. */
|
||||
|
||||
+103
-10
@@ -43,6 +43,7 @@
|
||||
#include <syslog.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include "dirs.h"
|
||||
#include "dynamic-string.h"
|
||||
#include "sat-math.h"
|
||||
#include "timeval.h"
|
||||
@@ -93,6 +94,10 @@ enum vlog_level min_vlog_levels[VLM_N_MODULES];
|
||||
/* Time at which vlog was initialized, in milliseconds. */
|
||||
static long long int boot_time;
|
||||
|
||||
/* VLF_FILE configuration. */
|
||||
static char *log_file_name;
|
||||
static FILE *log_file;
|
||||
|
||||
/* Searches the 'n_names' in 'names'. Returns the index of a match for
|
||||
* 'target', or 'n_names' if no name matches. */
|
||||
static size_t
|
||||
@@ -179,7 +184,9 @@ update_min_level(enum vlog_module module)
|
||||
enum vlog_facility facility;
|
||||
|
||||
for (facility = 0; facility < VLF_N_FACILITIES; facility++) {
|
||||
min_level = MAX(min_level, levels[module][facility]);
|
||||
if (log_file || facility != VLF_FILE) {
|
||||
min_level = MAX(min_level, levels[module][facility]);
|
||||
}
|
||||
}
|
||||
min_vlog_levels[module] = min_level;
|
||||
}
|
||||
@@ -243,6 +250,71 @@ vlog_set_pattern(enum vlog_facility facility, const char *pattern)
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the name of the log file used by VLF_FILE, or a null pointer if no
|
||||
* log file has been set. (A non-null return value does not assert that the
|
||||
* named log file is in use: if vlog_set_log_file() or vlog_reopen_log_file()
|
||||
* fails, it still sets the log file name.) */
|
||||
const char *
|
||||
vlog_get_log_file(void)
|
||||
{
|
||||
return log_file_name;
|
||||
}
|
||||
|
||||
/* Sets the name of the log file used by VLF_FILE to 'file_name', or to the
|
||||
* default file name if 'file_name' is null. Returns 0 if successful,
|
||||
* otherwise a positive errno value. */
|
||||
int
|
||||
vlog_set_log_file(const char *file_name)
|
||||
{
|
||||
char *old_log_file_name;
|
||||
enum vlog_module module;
|
||||
int error;
|
||||
|
||||
/* Close old log file. */
|
||||
if (log_file) {
|
||||
VLOG_WARN("closing log file");
|
||||
fclose(log_file);
|
||||
log_file = NULL;
|
||||
}
|
||||
|
||||
/* Update log file name and free old name. The ordering is important
|
||||
* because 'file_name' might be 'log_file_name' or some suffix of it. */
|
||||
old_log_file_name = log_file_name;
|
||||
log_file_name = (file_name
|
||||
? xstrdup(file_name)
|
||||
: xasprintf("%s/%s.log", ofp_logdir, program_name));
|
||||
free(old_log_file_name);
|
||||
file_name = NULL; /* Might have been freed. */
|
||||
|
||||
/* Open new log file and update min_levels[] to reflect whether we actually
|
||||
* have a log_file. */
|
||||
log_file = fopen(log_file_name, "a");
|
||||
for (module = 0; module < VLM_N_MODULES; module++) {
|
||||
update_min_level(module);
|
||||
}
|
||||
|
||||
/* Log success or failure. */
|
||||
if (!log_file) {
|
||||
VLOG_WARN("failed to open %s for logging: %s",
|
||||
log_file_name, strerror(errno));
|
||||
error = errno;
|
||||
} else {
|
||||
VLOG_WARN("opened log file %s", log_file_name);
|
||||
error = 0;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Closes and then attempts to re-open the current log file. (This is useful
|
||||
* just after log rotation, to ensure that the new log file starts being used.)
|
||||
* Returns 0 if successful, otherwise a positive errno value. */
|
||||
int
|
||||
vlog_reopen_log_file(void)
|
||||
{
|
||||
return vlog_set_log_file(log_file_name);
|
||||
}
|
||||
|
||||
/* Set debugging levels:
|
||||
*
|
||||
* mod[:facility[:level]] mod2[:facility[:level]] ...
|
||||
@@ -358,14 +430,15 @@ vlog_get_levels(void)
|
||||
struct ds s = DS_EMPTY_INITIALIZER;
|
||||
enum vlog_module module;
|
||||
|
||||
ds_put_format(&s, " console syslog\n");
|
||||
ds_put_format(&s, " ------- ------\n");
|
||||
ds_put_format(&s, " console syslog file\n");
|
||||
ds_put_format(&s, " ------- ------ ------\n");
|
||||
|
||||
for (module = 0; module < VLM_N_MODULES; module++) {
|
||||
ds_put_format(&s, "%-16s %4s %4s\n",
|
||||
ds_put_format(&s, "%-16s %4s %4s %4s\n",
|
||||
vlog_get_module_name(module),
|
||||
vlog_get_level_name(vlog_get_level(module, VLF_CONSOLE)),
|
||||
vlog_get_level_name(vlog_get_level(module, VLF_SYSLOG)));
|
||||
vlog_get_level_name(vlog_get_level(module, VLF_SYSLOG)),
|
||||
vlog_get_level_name(vlog_get_level(module, VLF_FILE)));
|
||||
}
|
||||
|
||||
return ds_cstr(&s);
|
||||
@@ -489,9 +562,10 @@ void
|
||||
vlog_valist(enum vlog_module module, enum vlog_level level,
|
||||
const char *message, va_list args)
|
||||
{
|
||||
bool log_console = levels[module][VLF_CONSOLE] >= level;
|
||||
bool log_syslog = levels[module][VLF_SYSLOG] >= level;
|
||||
if (log_console || log_syslog) {
|
||||
bool log_to_console = levels[module][VLF_CONSOLE] >= level;
|
||||
bool log_to_syslog = levels[module][VLF_SYSLOG] >= level;
|
||||
bool log_to_file = levels[module][VLF_FILE] >= level && log_file;
|
||||
if (log_to_console || log_to_syslog || log_to_file) {
|
||||
int save_errno = errno;
|
||||
static unsigned int msg_num;
|
||||
struct ds s;
|
||||
@@ -500,14 +574,14 @@ vlog_valist(enum vlog_module module, enum vlog_level level,
|
||||
ds_reserve(&s, 1024);
|
||||
msg_num++;
|
||||
|
||||
if (log_console) {
|
||||
if (log_to_console) {
|
||||
format_log_message(module, level, VLF_CONSOLE, msg_num,
|
||||
message, args, &s);
|
||||
ds_put_char(&s, '\n');
|
||||
fputs(ds_cstr(&s), stderr);
|
||||
}
|
||||
|
||||
if (log_syslog) {
|
||||
if (log_to_syslog) {
|
||||
int syslog_level = syslog_levels[level];
|
||||
char *save_ptr = NULL;
|
||||
char *line;
|
||||
@@ -520,6 +594,14 @@ vlog_valist(enum vlog_module module, enum vlog_level level,
|
||||
}
|
||||
}
|
||||
|
||||
if (log_to_file) {
|
||||
format_log_message(module, level, VLF_FILE, msg_num,
|
||||
message, args, &s);
|
||||
ds_put_char(&s, '\n');
|
||||
fputs(ds_cstr(&s), log_file);
|
||||
fflush(log_file);
|
||||
}
|
||||
|
||||
ds_destroy(&s);
|
||||
errno = save_errno;
|
||||
}
|
||||
@@ -578,3 +660,14 @@ vlog_rate_limit(enum vlog_module module, enum vlog_level level,
|
||||
rl->n_dropped = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
vlog_usage(void)
|
||||
{
|
||||
printf("\nLogging options:\n"
|
||||
" -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n"
|
||||
" -v, --verbose set maximum verbosity level\n"
|
||||
" --log-file[=FILE] enable logging to specified FILE\n"
|
||||
" (default: %s/%s.log)\n",
|
||||
ofp_logdir, program_name);
|
||||
}
|
||||
|
||||
+6
-7
@@ -2514,7 +2514,8 @@ parse_options(int argc, char *argv[], struct settings *s)
|
||||
OPT_STP,
|
||||
OPT_NO_STP,
|
||||
OPT_OUT_OF_BAND,
|
||||
OPT_IN_BAND
|
||||
OPT_IN_BAND,
|
||||
VLOG_OPTION_ENUMS
|
||||
};
|
||||
static struct option long_options[] = {
|
||||
{"accept-vconn", required_argument, 0, OPT_ACCEPT_VCONN},
|
||||
@@ -2535,6 +2536,7 @@ parse_options(int argc, char *argv[], struct settings *s)
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"version", no_argument, 0, 'V'},
|
||||
DAEMON_LONG_OPTIONS,
|
||||
VLOG_LONG_OPTIONS,
|
||||
#ifdef HAVE_OPENSSL
|
||||
VCONN_SSL_LONG_OPTIONS
|
||||
{"bootstrap-ca-cert", required_argument, 0, OPT_BOOTSTRAP_CA_CERT},
|
||||
@@ -2670,12 +2672,10 @@ parse_options(int argc, char *argv[], struct settings *s)
|
||||
printf("%s "VERSION" compiled "__DATE__" "__TIME__"\n", argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
case 'v':
|
||||
vlog_set_verbosity(optarg);
|
||||
break;
|
||||
|
||||
DAEMON_OPTION_HANDLERS
|
||||
|
||||
VLOG_OPTION_HANDLERS
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
VCONN_SSL_OPTION_HANDLERS
|
||||
|
||||
@@ -2770,9 +2770,8 @@ usage(void)
|
||||
" --rate-limit[=PACKETS] max rate, in packets/s (default: 1000)\n"
|
||||
" --burst-limit=BURST limit on packet credit for idle time\n");
|
||||
daemon_usage();
|
||||
vlog_usage();
|
||||
printf("\nOther options:\n"
|
||||
" -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n"
|
||||
" -v, --verbose set maximum verbosity level\n"
|
||||
" -h, --help display this help message\n"
|
||||
" -V, --version display version information\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
+1
-2
@@ -299,9 +299,8 @@ usage(void)
|
||||
" -l, --listen=METHOD allow management connections on METHOD\n"
|
||||
" (a passive OpenFlow connection method)\n");
|
||||
daemon_usage();
|
||||
vlog_usage();
|
||||
printf("\nOther options:\n"
|
||||
" -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n"
|
||||
" -v, --verbose set maximum verbosity level\n"
|
||||
" -h, --help display this help message\n"
|
||||
" -V, --version display version information\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
@@ -194,13 +194,12 @@ usage(void)
|
||||
" do not request a specific IP)\n"
|
||||
" --vendor-class=STRING use STRING as vendor class (default:\n"
|
||||
" none); use OpenFlow to imitate secchan\n"
|
||||
" --no-resolv-conf do not update /etc/resolv.conf\n"
|
||||
"\nOther options:\n"
|
||||
" -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n"
|
||||
" -v, --verbose set maximum verbosity level\n"
|
||||
" -h, --help display this help message\n"
|
||||
" -V, --version display version information\n",
|
||||
" --no-resolv-conf do not update /etc/resolv.conf\n",
|
||||
program_name, program_name);
|
||||
vlog_usage();
|
||||
printf("\nOther options:\n"
|
||||
" -h, --help display this help message\n"
|
||||
" -V, --version display version information\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -238,11 +238,10 @@ usage(void)
|
||||
"where each SWITCH is an active OpenFlow connection method.\n",
|
||||
program_name, program_name);
|
||||
vconn_usage(true, false, false);
|
||||
printf("\nOptions:\n"
|
||||
vlog_usage();
|
||||
printf("\nOther options:\n"
|
||||
" --strict use strict match for flow commands\n"
|
||||
" -t, --timeout=SECS give up after SECS seconds\n"
|
||||
" -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n"
|
||||
" -v, --verbose set maximum verbosity level\n"
|
||||
" -h, --help display this help message\n"
|
||||
" -V, --version display version information\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
@@ -405,15 +405,15 @@ usage(void)
|
||||
" --accept-vconn=REGEX accept matching discovered controllers\n"
|
||||
" --exit-without-bind exit after discovery, without binding\n"
|
||||
" --exit-after-bind exit after discovery, after binding\n"
|
||||
" --no-detach do not detach after discovery\n"
|
||||
"\nOther options:\n"
|
||||
" --no-detach do not detach after discovery\n",
|
||||
program_name, program_name);
|
||||
vlog_usage();
|
||||
printf("\nOther options:\n"
|
||||
" -t, --timeout=SECS give up discovery after SECS seconds\n"
|
||||
" -P, --pidfile[=FILE] create pidfile (default: %s/%s.pid)\n"
|
||||
" -f, --force with -P, start even if already running\n"
|
||||
" -v, --verbose=MODULE[:FACILITY[:LEVEL]] set logging levels\n"
|
||||
" -v, --verbose set maximum verbosity level\n"
|
||||
" -h, --help display this help message\n"
|
||||
" -V, --version display version information\n",
|
||||
program_name, program_name, ofp_rundir, program_name);
|
||||
ofp_rundir, program_name);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
+9
-42
@@ -43,6 +43,7 @@
|
||||
#include "daemon.h"
|
||||
#include "timeval.h"
|
||||
#include "util.h"
|
||||
#include "vlog.h"
|
||||
|
||||
/* -s, --signal: signal to send. */
|
||||
static int sig_nr = SIGTERM;
|
||||
@@ -51,7 +52,6 @@ static int sig_nr = SIGTERM;
|
||||
static bool force;
|
||||
|
||||
static void cond_error(int err_no, const char *, ...) PRINTF_FORMAT(2, 3);
|
||||
static bool kill_pidfile(const char *pidfile, FILE *);
|
||||
|
||||
static void parse_options(int argc, char *argv[]);
|
||||
static void usage(void);
|
||||
@@ -64,6 +64,7 @@ main(int argc, char *argv[])
|
||||
|
||||
set_program_name(argv[0]);
|
||||
time_init();
|
||||
vlog_init();
|
||||
parse_options(argc, argv);
|
||||
|
||||
argc -= optind;
|
||||
@@ -77,16 +78,16 @@ main(int argc, char *argv[])
|
||||
|
||||
for (i = 0; i < argc; i++) {
|
||||
char *pidfile;
|
||||
FILE *file;
|
||||
pid_t pid;
|
||||
|
||||
pidfile = make_pidfile_name(argv[i]);
|
||||
file = fopen(pidfile, "r");
|
||||
if (!file) {
|
||||
ok = false;
|
||||
cond_error(errno, "%s: open", pidfile);
|
||||
pid = read_pidfile(pidfile);
|
||||
if (pid >= 0) {
|
||||
if (kill(pid, sig_nr) < 0) {
|
||||
cond_error(errno, "%s: kill(%ld)", pidfile, (long int) pid);
|
||||
}
|
||||
} else {
|
||||
ok = kill_pidfile(argv[i], file) && ok;
|
||||
fclose(file);
|
||||
cond_error(-pid, "could not read %s", pidfile);
|
||||
}
|
||||
free(pidfile);
|
||||
}
|
||||
@@ -94,40 +95,6 @@ main(int argc, char *argv[])
|
||||
return ok || force ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static bool
|
||||
kill_pidfile(const char *pidfile, FILE *file)
|
||||
{
|
||||
char line[128];
|
||||
struct flock lck;
|
||||
|
||||
lck.l_type = F_WRLCK;
|
||||
lck.l_whence = SEEK_SET;
|
||||
lck.l_start = 0;
|
||||
lck.l_len = 0;
|
||||
if (fcntl(fileno(file), F_GETLK, &lck)) {
|
||||
cond_error(errno, "%s: fcntl", pidfile);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fgets(line, sizeof line, file)) {
|
||||
cond_error(errno, "%s: read", pidfile);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lck.l_pid != strtoul(line, NULL, 10)) {
|
||||
cond_error(errno, "l_pid (%ld) != %s pid (%s)",
|
||||
(long int) lck.l_pid, pidfile, line);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (kill(lck.l_pid, sig_nr) < 0) {
|
||||
cond_error(errno, "%s: kill(%ld)", pidfile, (long int) lck.l_pid);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_options(int argc, char *argv[])
|
||||
{
|
||||
|
||||
+16
-4
@@ -53,15 +53,17 @@ usage(char *prog_name, int exit_code)
|
||||
printf("Usage: %s [TARGET] [ACTION...]\n"
|
||||
"Targets:\n"
|
||||
" -a, --all Apply to all targets (default)\n"
|
||||
" -t, --target=TARGET Specify target program, as a pid or an\n"
|
||||
" absolute path to a Unix domain socket\n"
|
||||
" -t, --target=TARGET Specify target program, as a pid, a\n"
|
||||
" pidfile, or an absolute path to a Unix\n"
|
||||
" domain socket\n"
|
||||
"Actions:\n"
|
||||
" -l, --list List current settings\n"
|
||||
" -s, --set=MODULE[:FACILITY[:LEVEL]]\n"
|
||||
" Set MODULE and FACILITY log level to LEVEL\n"
|
||||
" MODULE may be any valid module name or 'ANY'\n"
|
||||
" FACILITY may be 'syslog' or 'console' or 'ANY' (default)\n"
|
||||
" LEVEL may be 'emer', 'err', 'warn', or 'dbg (default)'\n"
|
||||
" FACILITY may be 'syslog', 'console', 'file', or 'ANY' (default)\n"
|
||||
" LEVEL may be 'emer', 'err', 'warn', or 'dbg' (default)\n"
|
||||
" -r, --reopen Make the program reopen its log file\n"
|
||||
" -h, --help Print this helpful information\n",
|
||||
prog_name);
|
||||
exit(exit_code);
|
||||
@@ -147,6 +149,7 @@ int main(int argc, char *argv[])
|
||||
/* Action options come afterward. */
|
||||
{"list", no_argument, NULL, 'l'},
|
||||
{"set", required_argument, NULL, 's'},
|
||||
{"reopen", no_argument, NULL, 'r'},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
char *short_options;
|
||||
@@ -204,6 +207,15 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
for (i = 0; i < n_clients; i++) {
|
||||
struct vlog_client *client = clients[i];
|
||||
char *request = xasprintf("reopen");
|
||||
transact_ack(client, request, &ok);
|
||||
free(request);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage(argv[0], EXIT_SUCCESS);
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user