xref: /illumos-gate/usr/src/cmd/cmd-inet/lib/netcfgd/netcfgd.c (revision 440a8a36792bdf9ef51639066aab0b7771ffcab8)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * netcfgd - network configuration daemon.  At present, this daemon implements
29  * the configuration backend for libnwam (via calls to nwam_backend_init()
30  * and nwam_backend_fini()).  Initialization of the backend creates a  door
31  * that libnwam calls use to read, update and destroy persistent configuration.
32  *
33  * More long-term, netcfgd will be used to manage other sources of configuration
34  * data and the backend functionality currently contained in libnwam will be
35  * generalized.
36  */
37 
38 #include <errno.h>
39 #include <signal.h>
40 #include <stdio.h>
41 #include <stdarg.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <syslog.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <unistd.h>
48 #include <wait.h>
49 #include <libnwam_priv.h>
50 #include <libnwam.h>
51 
52 static const char *progname;
53 static boolean_t fg = B_FALSE;
54 
55 /*
56  * This function allows you to drop a dtrace probe here and trace
57  * complete strings (not just those containing formatting).  It's
58  * important that we actually format the strings so we could trace them
59  * even if we choose not to log them.
60  */
61 static void
62 log_out(int severity, const char *str)
63 {
64 	if (fg) {
65 		(void) fprintf(stderr, "%s: %s\n", progname, str);
66 	} else {
67 		syslog(severity, str);
68 	}
69 }
70 
71 /* PRINTFLIKE2 */
72 void
73 nlog(int severity, const char *fmt, ...)
74 {
75 	va_list ap;
76 	char *vbuf;
77 
78 	va_start(ap, fmt);
79 	if (vasprintf(&vbuf, fmt, ap) != -1) {
80 		log_out(severity, vbuf);
81 		free(vbuf);
82 	}
83 	va_end(ap);
84 }
85 
86 static void
87 start_logging(void)
88 {
89 	if (!fg)
90 		openlog(progname, LOG_PID, LOG_DAEMON);
91 
92 	nlog(LOG_DEBUG, "%s started", progname);
93 }
94 
95 static void
96 daemonize(void)
97 {
98 	pid_t pid;
99 
100 	/*
101 	 * A little bit of magic here.  By the first fork+setsid, we
102 	 * disconnect from our current controlling terminal and become
103 	 * a session group leader.  By forking again without calling
104 	 * setsid again, we make certain that we are not the session
105 	 * group leader and can never reacquire a controlling terminal.
106 	 */
107 	if ((pid = fork()) == -1) {
108 		nlog(LOG_ERR, "fork 1 failed");
109 		exit(EXIT_FAILURE);
110 	}
111 	if (pid != 0) {
112 		(void) wait(NULL);
113 		nlog(LOG_DEBUG, "child %ld exited, daemonizing", pid);
114 		_exit(0);
115 	}
116 	if (setsid() == (pid_t)-1) {
117 		nlog(LOG_ERR, "setsid");
118 		exit(EXIT_FAILURE);
119 	}
120 	if ((pid = fork()) == -1) {
121 		nlog(LOG_ERR, "fork 2 failed");
122 		exit(EXIT_FAILURE);
123 	}
124 	if (pid != 0) {
125 		_exit(0);
126 	}
127 	(void) chdir("/");
128 	(void) umask(022);
129 }
130 
131 /* ARGSUSED */
132 static void
133 graceful_shutdown(int signo)
134 {
135 	nwam_backend_fini();
136 	exit(EXIT_SUCCESS);
137 }
138 
139 int
140 main(int argc, char *argv[])
141 {
142 	int c;
143 	nwam_error_t err;
144 
145 	if ((progname = strrchr(argv[0], '/')) == NULL)
146 		progname = argv[0];
147 	else
148 		progname++;
149 
150 	while ((c = getopt(argc, argv, "f")) != -1) {
151 		switch (c) {
152 		case 'f':
153 			fg = B_TRUE;
154 			break;
155 		default:
156 			(void) fprintf(stderr, "%s: unrecognized option %c\n",
157 			    progname, optopt);
158 			exit(EXIT_FAILURE);
159 		}
160 	}
161 	start_logging();
162 
163 	if (!fg)
164 		daemonize();
165 
166 	(void) signal(SIGTERM, graceful_shutdown);
167 	(void) signal(SIGQUIT, graceful_shutdown);
168 	(void) signal(SIGPIPE, SIG_IGN);
169 	(void) signal(SIGCHLD, SIG_IGN);
170 	(void) atexit(nwam_backend_fini);
171 
172 	if ((err = nwam_backend_init()) != NWAM_SUCCESS) {
173 		nlog(LOG_ERR,
174 		    "couldn't initialize libnwam backend: %s",
175 		    nwam_strerror(err));
176 		exit(EXIT_FAILURE);
177 	}
178 
179 	for (;;)
180 		(void) pause();
181 
182 	/* NOTREACHED */
183 	return (EXIT_SUCCESS);
184 }
185