2
* Copyright Red Hat Inc. 2008
4
* Author: Steve Olivieri <sjo@redhat.com>
5
* Author: Vivek Goyal <vgoyal@redhat.com>
7
* Some part of the programs have been derived from Dhaval Giani's posting
8
* for daemon to place the task in right container. Original copyright notice
11
* Copyright IBM Corporation, 2007
12
* Author: Dhaval Giani <dhaval <at> linux.vnet.ibm.com>
13
* Derived from test_cn_proc.c by Matt Helsley
14
* Original copyright notice follows
16
* Copyright (C) Matt Helsley, IBM Corp. 2005
17
* Derived from fcctl.c by Guillaume Thouvenin
18
* Original copyright notice follows:
20
* Copyright (C) 2005 BULL SA.
21
* Written by Guillaume Thouvenin <guillaume.thouvenin <at> bull.net>
23
* This program is free software; you can redistribute it and/or modify it
24
* under the terms of version 2.1 of the GNU Lesser General Public License
25
* as published by the Free Software Foundation.
27
* This program is distributed in the hope that it would be useful, but
28
* WITHOUT ANY WARRANTY; without even the implied warranty of
29
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
31
* TODO Stop using netlink for communication (or at least rewrite that part).
34
#include "libcgroup.h"
35
#include "cgrulesengd.h"
36
#include "../libcgroup-internal.h"
42
#include <sys/socket.h>
43
#include <sys/syslog.h>
45
#include <linux/netlink.h>
52
#include <sys/types.h>
54
#include <linux/connector.h>
55
#include <linux/cn_proc.h>
58
#define NUM_PER_REALLOCATIOM (100)
60
/* Log file, NULL if logging to file is disabled */
63
/* Log facility, 0 if logging to syslog is disabled */
66
/* Current log level */
70
* Prints the usage information for this program and, optionally, an error
71
* message. This function uses vfprintf.
72
* @param fd The file stream to print to
73
* @param msg The error message to print (printf style)
74
* @param ... Any args to msg (printf style)
76
void usage(FILE* fd, const char* msg, ...)
78
/* List of args to msg */
81
/* Put all args after msg into the list. */
85
vfprintf(fd, msg, ap);
87
fprintf(fd, "cgrulesengd -- a daemon for the cgroups rules engine\n\n");
88
fprintf(fd, "Usage : cgrulesengd [options]\n\n");
89
fprintf(fd, " options :\n");
90
fprintf(fd, " -q | --quiet quiet mode\n"
91
" -v | --verbose verbose mode\n"
92
" -f <path> | --logfile=<path> write log to file\n"
93
" -s[facility] | --syslog=[facility] write log to syslog\n"
94
" -n | --nodaemom don't fork daemon\n"
95
" -d | --debug same as -v -v -n -f -\n"
96
" -Q | --nolog disable logging\n"
97
" -h | --help show this help\n\n"
103
* Prints a formatted message (like printf()) to all log destinations.
104
* Flushes the file stream's buffer so that the message is immediately
106
* @param level The log level (LOG_EMERG ... LOG_DEBUG)
107
* @param format The format for the message (printf style)
108
* @param ... Any args to format (printf style)
110
void flog(int level, const char *format, ...)
112
/* List of args to format */
115
/* Check the log level */
116
if (level > loglevel)
120
/* Print the message to the given stream. */
121
va_start(ap, format);
122
vfprintf(logfile, format, ap);
124
fprintf(logfile, "\n");
127
* Flush the stream's buffer, so the data is readable
136
sigemptyset(&sigset);
137
sigaddset(&sigset, SIGUSR2);
138
sigprocmask(SIG_BLOCK, &sigset, NULL);
140
va_start(ap, format);
141
vsyslog(LOG_MAKEPRI(logfacility, level), format, ap);
144
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
152
struct array_parent_info {
155
struct parent_info **parent_info;
157
struct array_parent_info array_pi;
159
static int cgre_store_parent_info(pid_t pid)
163
struct parent_info *info;
165
if (clock_gettime(CLOCK_MONOTONIC, &tp) < 0) {
166
flog(LOG_WARNING, "Failed to get time");
169
uptime_ns = ((__u64)tp.tv_sec * 1000 * 1000 * 1000 ) + tp.tv_nsec;
171
if (array_pi.index >= array_pi.num_allocation) {
172
array_pi.num_allocation += NUM_PER_REALLOCATIOM;
173
array_pi.parent_info = realloc(array_pi.parent_info,
174
sizeof(info) * array_pi.num_allocation);
175
if (!array_pi.parent_info) {
176
flog(LOG_WARNING, "Failed to allocate memory");
180
info = calloc(1, sizeof(struct parent_info));
182
flog(LOG_WARNING, "Failed to allocate memory");
185
info->timestamp = uptime_ns;
188
array_pi.parent_info[array_pi.index] = info;
194
static void cgre_remove_old_parent_info(__u64 key_timestamp)
198
for (i = 0; i < array_pi.index; i++) {
199
if (key_timestamp < array_pi.parent_info[i]->timestamp)
201
free(array_pi.parent_info[i]);
202
for (j = i; j < array_pi.index - 1; j++)
203
array_pi.parent_info[j] = array_pi.parent_info[j + 1];
210
static int cgre_was_parent_changed_when_forking(const struct proc_event *ev)
214
__u64 timestamp_child;
215
__u64 timestamp_parent;
217
parent_pid = ev->event_data.fork.parent_pid;
218
timestamp_child = ev->timestamp_ns;
220
cgre_remove_old_parent_info(timestamp_child);
222
for (i = 0; i < array_pi.index; i++) {
223
if (parent_pid != array_pi.parent_info[i]->pid)
225
timestamp_parent = array_pi.parent_info[i]->timestamp;
226
if (timestamp_child > timestamp_parent)
233
struct unchanged_pid {
238
struct array_unchanged {
241
struct unchanged_pid *proc;
244
struct array_unchanged array_unch;
246
static int cgre_store_unchanged_process(pid_t pid, int flags)
250
for (i = 0; i < array_unch.index; i++) {
251
if (array_unch.proc[i].pid != pid)
253
/* pid is stored already. */
256
if (array_unch.index >= array_unch.num_allocation) {
257
array_unch.num_allocation += NUM_PER_REALLOCATIOM;
258
array_unch.proc = realloc(array_unch.proc,
259
sizeof(unchanged_pid_t) * array_unch.num_allocation);
260
if (!array_unch.proc) {
261
flog(LOG_WARNING, "Failed to allocate memory");
265
array_unch.proc[array_unch.index].pid = pid;
266
array_unch.proc[array_unch.index].flags = flags;
268
flog(LOG_DEBUG, "Store the unchanged process (PID: %d, FLAGS: %d)",
273
static void cgre_remove_unchanged_process(pid_t pid)
277
for (i = 0; i < array_unch.index; i++) {
278
if (array_unch.proc[i].pid != pid)
280
for (j = i; j < array_unch.index - 1; j++)
281
memcpy(&array_unch.proc[j],
282
&array_unch.proc[j + 1],
283
sizeof(struct unchanged_pid));
285
flog(LOG_DEBUG, "Remove the unchanged process (PID: %d)", pid);
291
static int cgre_is_unchanged_process(pid_t pid)
295
for (i = 0; i < array_unch.index; i++) {
296
if (array_unch.proc[i].pid != pid)
303
static int cgre_is_unchanged_child(pid_t pid)
307
for (i = 0; i < array_unch.index; i++) {
308
if (array_unch.proc[i].pid != pid)
310
if (array_unch.proc[i].flags & CGROUP_DAEMON_UNCHANGE_CHILDREN)
317
static int cgre_change_cgroup(const uid_t uid, const gid_t gid, char *procname,
324
* For avoiding the deadlock, protect cdgroup_change_cgroup_
325
* ~uid_gid_flags() by blocking SIGUSR2 signal.
327
sigemptyset(&sigset);
328
sigaddset(&sigset, SIGUSR2);
329
sigprocmask(SIG_BLOCK, &sigset, NULL);
331
ret = cgroup_change_cgroup_flags(uid, gid, procname, pid,
333
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
339
* Process an event from the kernel, and determine the correct UID/GID/PID to
340
* pass to libcgroup. Then, libcgroup will decide the cgroup to move the PID
342
* @param ev The event to process
343
* @param type The type of event to process (part of ev)
344
* @return 0 on success, > 0 on failure
346
int cgre_process_event(const struct proc_event *ev, const int type)
350
pid_t pid = 0, log_pid = 0;
351
uid_t euid, log_uid = 0;
352
gid_t egid, log_gid = 0;
359
pid = ev->event_data.id.process_pid;
361
case PROC_EVENT_FORK:
362
ppid = ev->event_data.fork.parent_pid;
363
cpid = ev->event_data.fork.child_pid;
364
if (cgre_is_unchanged_child(ppid)) {
365
if (cgre_store_unchanged_process(cpid,
366
CGROUP_DAEMON_UNCHANGE_CHILDREN))
371
* If this process was forked while changing parent's cgroup,
372
* this process's cgroup also should be changed.
374
if (!cgre_was_parent_changed_when_forking(ev))
376
pid = ev->event_data.fork.child_pid;
378
case PROC_EVENT_EXIT:
379
cgre_remove_unchanged_process(ev->event_data.exit.process_pid);
381
case PROC_EVENT_EXEC:
383
* If the unchanged process, the daemon should not change the
384
* cgroup of the process.
386
if (cgre_is_unchanged_process(ev->event_data.exec.process_pid))
388
pid = ev->event_data.exec.process_pid;
393
ret = cgroup_get_uid_gid_from_procfs(pid, &euid, &egid);
394
if (ret == ECGROUPNOTEXIST)
395
/* cgroup_get_uid_gid_from_procfs() returns ECGROUPNOTEXIST
396
* if a process finished and that is not a problem. */
401
ret = cgroup_get_procname_from_procfs(pid, &procname);
402
if (ret == ECGROUPNOTEXIST)
408
* Now that we have the UID, the GID, and the PID, we can make a call
409
* to libcgroup to change the cgroup for this PID.
414
log_uid = ev->event_data.id.e.euid;
416
euid = ev->event_data.id.e.euid;
420
log_gid = ev->event_data.id.e.egid;
421
egid = ev->event_data.id.e.egid;
423
case PROC_EVENT_FORK:
427
case PROC_EVENT_EXEC:
434
ret = cgre_change_cgroup(euid, egid, procname, pid);
437
* TODO: add some supression, do not spam log when every group
440
flog(LOG_WARNING, "Cgroup change for PID: %d, UID: %d, GID: %d"
441
" FAILED! (Error Code: %d)", log_pid, log_uid, log_gid,
444
ret = cgre_store_parent_info(pid);
445
flog(LOG_INFO, "Cgroup change for PID: %d, UID: %d, GID: %d OK",
446
log_pid, log_uid, log_gid);
453
* Handle a netlink message. In the event of PROC_EVENT_UID or PROC_EVENT_GID,
454
* we pass the event along to cgre_process_event for further processing. All
455
* other events are ignored.
456
* @param cn_hdr The netlink message
457
* @return 0 on success, > 0 on error
459
int cgre_handle_msg(struct cn_msg *cn_hdr)
461
/* The event to consider */
462
struct proc_event *ev;
467
/* Get the event data. We only care about two event types. */
468
ev = (struct proc_event*)cn_hdr->data;
471
flog(LOG_DEBUG, "UID Event: PID = %d, tGID = %d, rUID = %d,"
472
" eUID = %d", ev->event_data.id.process_pid,
473
ev->event_data.id.process_tgid,
474
ev->event_data.id.r.ruid,
475
ev->event_data.id.e.euid);
476
ret = cgre_process_event(ev, PROC_EVENT_UID);
479
flog(LOG_DEBUG, "GID Event: PID = %d, tGID = %d, rGID = %d,"
480
" eGID = %d", ev->event_data.id.process_pid,
481
ev->event_data.id.process_tgid,
482
ev->event_data.id.r.rgid,
483
ev->event_data.id.e.egid);
484
ret = cgre_process_event(ev, PROC_EVENT_GID);
486
case PROC_EVENT_FORK:
487
ret = cgre_process_event(ev, PROC_EVENT_FORK);
489
case PROC_EVENT_EXIT:
490
ret = cgre_process_event(ev, PROC_EVENT_EXIT);
492
case PROC_EVENT_EXEC:
493
flog(LOG_DEBUG, "EXEC Event: PID = %d, tGID = %d",
494
ev->event_data.exec.process_pid,
495
ev->event_data.exec.process_tgid);
496
ret = cgre_process_event(ev, PROC_EVENT_EXEC);
505
int cgre_receive_netlink_msg(int sk_nl)
507
char buff[BUFF_SIZE];
509
struct sockaddr_nl from_nla;
510
socklen_t from_nla_len;
511
struct nlmsghdr *nlh;
512
struct sockaddr_nl kern_nla;
513
struct cn_msg *cn_hdr;
515
kern_nla.nl_family = AF_NETLINK;
516
kern_nla.nl_groups = CN_IDX_PROC;
520
memset(buff, 0, sizeof(buff));
521
from_nla_len = sizeof(from_nla);
522
memcpy(&from_nla, &kern_nla, sizeof(from_nla));
523
recv_len = recvfrom(sk_nl, buff, sizeof(buff), 0,
524
(struct sockaddr *)&from_nla, &from_nla_len);
525
if (recv_len == ENOBUFS) {
526
flog(LOG_ERR, "ERROR: NETLINK BUFFER FULL, MESSAGE DROPPED!");
532
nlh = (struct nlmsghdr *)buff;
533
while (NLMSG_OK(nlh, recv_len)) {
534
cn_hdr = NLMSG_DATA(nlh);
535
if (nlh->nlmsg_type == NLMSG_NOOP) {
536
nlh = NLMSG_NEXT(nlh, recv_len);
539
if ((nlh->nlmsg_type == NLMSG_ERROR) ||
540
(nlh->nlmsg_type == NLMSG_OVERRUN))
542
if (cgre_handle_msg(cn_hdr) < 0)
544
if (nlh->nlmsg_type == NLMSG_DONE)
546
nlh = NLMSG_NEXT(nlh, recv_len);
551
void cgre_receive_unix_domain_msg(int sk_unix)
556
struct sockaddr_un caddr;
558
struct stat buff_stat;
559
char path[FILENAME_MAX];
561
caddr_len = sizeof(caddr);
562
fd_client = accept(sk_unix, (struct sockaddr *)&caddr, &caddr_len);
564
cgroup_dbg("accept error");
567
if (read(fd_client, &pid, sizeof(pid)) < 0) {
568
cgroup_dbg("read error");
571
sprintf(path, "/proc/%d", pid);
572
if (stat(path, &buff_stat)) {
573
cgroup_dbg("There is not such process (PID: %d)", pid);
576
if (read(fd_client, &flags, sizeof(flags)) < 0) {
577
cgroup_dbg("read error");
580
if (cgre_store_unchanged_process(pid, flags))
583
if (write(fd_client, CGRULE_SUCCESS_STORE_PID,
584
sizeof(CGRULE_SUCCESS_STORE_PID)) < 0) {
585
cgroup_dbg("write error");
593
int cgre_create_netlink_socket_process_msg()
595
int sk_nl = 0, sk_unix = 0, sk_max;
596
struct sockaddr_nl my_nla;
597
char buff[BUFF_SIZE];
599
struct nlmsghdr *nl_hdr;
600
struct cn_msg *cn_hdr;
601
enum proc_cn_mcast_op *mcop_msg;
602
struct sockaddr_un saddr;
606
* Create an endpoint for communication. Use the kernel user
607
* interface device (PF_NETLINK) which is a datagram oriented
608
* service (SOCK_DGRAM). The protocol used is the connector
609
* protocol (NETLINK_CONNECTOR)
611
sk_nl = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
613
cgroup_dbg("socket sk_nl error");
617
my_nla.nl_family = AF_NETLINK;
618
my_nla.nl_groups = CN_IDX_PROC;
619
my_nla.nl_pid = getpid();
622
if (bind(sk_nl, (struct sockaddr *)&my_nla, sizeof(my_nla)) < 0) {
623
cgroup_dbg("binding sk_nl error");
627
nl_hdr = (struct nlmsghdr *)buff;
628
cn_hdr = (struct cn_msg *)NLMSG_DATA(nl_hdr);
629
mcop_msg = (enum proc_cn_mcast_op*)&cn_hdr->data[0];
630
cgroup_dbg("sending proc connector: PROC_CN_MCAST_LISTEN... ");
631
memset(buff, 0, sizeof(buff));
632
*mcop_msg = PROC_CN_MCAST_LISTEN;
634
/* fill the netlink header */
635
nl_hdr->nlmsg_len = SEND_MESSAGE_LEN;
636
nl_hdr->nlmsg_type = NLMSG_DONE;
637
nl_hdr->nlmsg_flags = 0;
638
nl_hdr->nlmsg_seq = 0;
639
nl_hdr->nlmsg_pid = getpid();
641
/* fill the connector header */
642
cn_hdr->id.idx = CN_IDX_PROC;
643
cn_hdr->id.val = CN_VAL_PROC;
646
cn_hdr->len = sizeof(enum proc_cn_mcast_op);
647
cgroup_dbg("sending netlink message len=%d, cn_msg len=%d\n",
648
nl_hdr->nlmsg_len, (int) sizeof(struct cn_msg));
649
if (send(sk_nl, nl_hdr, nl_hdr->nlmsg_len, 0) != nl_hdr->nlmsg_len) {
650
cgroup_dbg("failed to send proc connector mcast ctl op!\n");
653
cgroup_dbg("sent\n");
656
* Setup Unix domain socket.
658
sk_unix = socket(PF_UNIX, SOCK_STREAM, 0);
660
cgroup_dbg("socket sk_unix error");
663
memset(&saddr, 0, sizeof(saddr));
664
saddr.sun_family = AF_UNIX;
665
strcpy(saddr.sun_path, CGRULE_CGRED_SOCKET_PATH);
666
unlink(CGRULE_CGRED_SOCKET_PATH);
667
if (bind(sk_unix, (struct sockaddr *)&saddr,
668
sizeof(saddr.sun_family) + strlen(CGRULE_CGRED_SOCKET_PATH)) < 0) {
669
cgroup_dbg("binding sk_unix error");
672
if (listen(sk_unix, 1) < 0) {
673
cgroup_dbg("listening sk_unix error");
677
FD_SET(sk_nl, &readfds);
678
FD_SET(sk_unix, &readfds);
684
memcpy(&fds, &readfds, sizeof(fd_set));
685
if (select(sk_max + 1, &fds, NULL, NULL, NULL) < 0) {
686
cgroup_dbg("selecting error");
689
if (FD_ISSET(sk_nl, &fds)) {
690
if (cgre_receive_netlink_msg(sk_nl))
693
if (FD_ISSET(sk_unix, &fds))
694
cgre_receive_unix_domain_msg(sk_unix);
706
* Start logging. Opens syslog and/or log file and sets log level.
707
* @param logp Path of the log file, NULL if no log file was specified
708
* @param logf Syslog facility, NULL if no facility was specified
709
* @param logv Log verbosity, 2 is the default, 0 = no logging, 4 = everything
711
static void cgre_start_log(const char *logp, int logf, int logv)
713
/* Current system time */
720
LOG_NOTICE, /* default */
725
/* Set default logging destination if nothing was specified */
731
if (strcmp("-", logp) == 0) {
734
logfile = fopen(logp, "a");
736
fprintf(stderr, "Failed to open log file %s,"
737
" error: %s. Continuing anyway.\n",
738
logp, strerror(errno));
747
openlog("CGRE", LOG_CONS | LOG_PID, logf);
752
/* Set the log level */
755
if (logv >= sizeof(loglevels)/sizeof(int))
756
logv = sizeof(loglevels)/sizeof(int)-1;
758
loglevel = loglevels[logv];
760
flog(LOG_DEBUG, "CGroup Rules Engine Daemon log started");
762
flog(LOG_DEBUG, "Current time: %s", ctime(&tm));
763
flog(LOG_DEBUG, "Opened log file: %s, log facility: %d, log level: %d",
764
logp, logfacility, loglevel);
769
* Turns this program into a daemon. In doing so, we fork() and kill the
770
* parent process. Note too that stdout, stdin, and stderr are closed in
771
* daemon mode, and a file descriptor for a log file is opened.
772
* @param logp Path of the log file, NULL if no log file was specified
773
* @param logf Syslog facility, 0 if no facility was specified
774
* @param daemon False to turn off daemon mode (no fork, leave FDs open)
775
* @param logv Log verbosity, 2 is the default, 0 = no logging, 5 = everything
776
* @return 0 on success, > 0 on error
778
int cgre_start_daemon(const char *logp, const int logf,
779
const unsigned char daemon, const int logv)
781
/* PID returned from the fork() */
788
openlog("CGRE", LOG_CONS, LOG_DAEMON|LOG_WARNING);
789
syslog(LOG_DAEMON|LOG_WARNING, "Failed to fork,"
790
" error: %s", strerror(errno));
792
fprintf(stderr, "Failed to fork(), %s\n",
795
} else if (pid > 0) {
799
/* Change the file mode mask. */
802
cgroup_dbg("Not using daemon mode.\n");
806
cgre_start_log(logp, logf, logv);
809
/* We can skip the rest, since we're not becoming a daemon. */
810
flog(LOG_INFO, "Proceeding with PID %d", getpid());
813
/* Get a new SID for the child. */
815
flog(LOG_ERR, "Failed to get a new SID, error: %s",
820
/* Change to the root directory. */
821
if (chdir("/") < 0) {
822
flog(LOG_ERR, "Failed to chdir to /, error: %s",
827
/* Close standard file descriptors. */
829
if (logfile != stdout)
830
close(STDOUT_FILENO);
831
close(STDERR_FILENO);
834
/* If we make it this far, we're a real daemon! Or we chose not to. */
835
flog(LOG_INFO, "Proceeding with PID %d", getpid());
840
* Catch the SIGUSR2 signal and reload the rules configuration. This function
841
* makes use of the logfile and flog() to print the new rules.
842
* @param signum The signal that we caught (always SIGUSR2)
844
void cgre_flash_rules(int signum)
849
flog(LOG_NOTICE, "Reloading rules configuration.");
850
flog(LOG_DEBUG, "Current time: %s", ctime(&tm));
852
/* Ask libcgroup to reload the rules table. */
853
cgroup_reload_cached_rules();
855
/* Print the results of the new table to our log file. */
856
if (logfile && loglevel >= LOG_INFO) {
857
cgroup_print_rules_config(logfile);
858
fprintf(logfile, "\n");
863
* Catch the SIGTERM and SIGINT signals so that we can exit gracefully. Before
864
* exiting, this function makes use of the logfile and flog().
865
* @param signum The signal that we caught (SIGTERM, SIGINT)
867
void cgre_catch_term(int signum)
872
flog(LOG_NOTICE, "Stopped CGroup Rules Engine Daemon at %s",
875
/* Close the log file, if we opened one */
876
if (logfile && logfile != stdout)
887
* Parse the syslog facility as received on command line.
888
* @param arg Command line argument with the syslog facility
889
* @return the syslog facility (e.g. LOG_DAEMON) or 0 on error
891
static int cgre_parse_syslog_facility(const char *arg)
923
int main(int argc, char *argv[])
925
/* Patch to the log file */
926
const char *logp = NULL;
928
/* Syslog facility */
934
/* For catching signals */
937
/* Should we daemonize? */
938
unsigned char daemon = 1;
943
/* Command line arguments */
944
const char *short_options = "hvqf:s::ndQ";
945
struct option long_options[] = {
946
{"help", no_argument, NULL, 'h'},
947
{"verbose", no_argument, NULL, 'v'},
948
{"quiet", no_argument, NULL, 'q'},
949
{"logfile", required_argument, NULL, 'f'},
950
{"syslog", optional_argument, NULL, 's'},
951
{"nodaemon", no_argument, NULL, 'n'},
952
{"debug", no_argument, NULL, 'd'},
953
{"nolog", no_argument, NULL, 'Q'},
957
/* Make sure the user is root. */
959
fprintf(stderr, "Error: Only root can start/stop the control"
960
" group rules engine daemon\n");
968
c = getopt_long(argc, argv, short_options, long_options, NULL);
973
case 'h': /* --help */
974
usage(stdout, "Help:\n");
978
case 'v': /* --verbose */
982
case 'q': /* --quiet */
986
case 'Q': /* --nolog */
990
case 'f': /* --logfile=<filename> */
994
case 's': /* --syslog=[facility] */
996
facility = cgre_parse_syslog_facility(optarg);
999
"Unknown syslog facility: %s\n",
1005
facility = LOG_DAEMON;
1009
case 'n': /* --no-fork */
1013
case 'd': /* --debug */
1027
/* Initialize libcgroup. */
1028
if ((ret = cgroup_init()) != 0) {
1029
fprintf(stderr, "Error: libcgroup initialization failed, %d\n",
1034
/* Ask libcgroup to load the configuration rules. */
1035
if ((ret = cgroup_init_rules_cache()) != 0) {
1036
fprintf(stderr, "Error: libcgroup failed to initialize rules"
1037
"cache, %d\n", ret);
1041
/* Now, start the daemon. */
1042
ret = cgre_start_daemon(logp, facility, daemon, verbosity);
1044
fprintf(stderr, "Error: Failed to launch the daemon, %d\n",
1050
* Set up the signal handler to reload the cached rules upon reception
1051
* of a SIGUSR2 signal.
1053
sa.sa_handler = &cgre_flash_rules;
1055
sa.sa_restorer = NULL;
1056
sigemptyset(&sa.sa_mask);
1057
if ((ret = sigaction(SIGUSR2, &sa, NULL))) {
1058
flog(LOG_ERR, "Failed to set up signal handler for SIGUSR2."
1059
" Error: %s", strerror(errno));
1064
* Set up the signal handler to catch SIGINT and SIGTERM so that we
1065
* can exit gracefully.
1067
sa.sa_handler = &cgre_catch_term;
1068
ret = sigaction(SIGINT, &sa, NULL);
1069
ret |= sigaction(SIGTERM, &sa, NULL);
1071
flog(LOG_ERR, "Failed to set up the signal handler. Error:"
1072
" %s", strerror(errno));
1076
/* Print the configuration to the log file, or stdout. */
1077
if (logfile && loglevel >= LOG_INFO)
1078
cgroup_print_rules_config(logfile);
1080
flog(LOG_NOTICE, "Started the CGroup Rules Engine Daemon.");
1082
/* We loop endlesly in this function, unless we encounter an error. */
1083
ret = cgre_create_netlink_socket_process_msg();
1086
if (logfile && logfile != stdout)