dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / fs.d / reparsed / reparsed.c
blob62943b24e5325c168428027adab255d781f41350
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Reparsed daemon
30 #include <stdio.h>
31 #include <stdio_ext.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <signal.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <memory.h>
39 #include <alloca.h>
40 #include <ucontext.h>
41 #include <errno.h>
42 #include <syslog.h>
43 #include <string.h>
44 #include <strings.h>
45 #include <door.h>
46 #include <wait.h>
47 #include <libintl.h>
48 #include <locale.h>
49 #include <sys/param.h>
50 #include <sys/systeminfo.h>
51 #include <sys/thread.h>
52 #include <rpc/xdr.h>
53 #include <priv.h>
54 #include <sys/fs_reparse.h>
55 #include <priv_utils.h>
56 #include <rpcsvc/daemon_utils.h>
58 #define REPARSED_CMD_OPTS "v"
59 #define DOOR_RESULT_BUFSZ (MAXPATHLEN + sizeof (reparsed_door_res_t))
60 #define SAFETY_BUFFER 8*1024
62 static char *MyName;
63 static int verbose = 0;
65 static int start_reparsed_svcs();
66 static void daemonize(void);
67 static void reparsed_door_call_error(int error, int buflen);
68 static void reparsed_doorfunc(void *cookie, char *argp, size_t arg_size,
69 door_desc_t *dp, uint_t n_desc);
71 static void
72 usage()
74 syslog(LOG_ERR, "Usage: %s", MyName);
75 syslog(LOG_ERR, "\t[-v]\t\tverbose error messages)");
76 exit(1);
79 static void
80 warn_hup(int i)
82 syslog(LOG_ERR, "SIGHUP received: ignored");
83 (void) signal(SIGHUP, warn_hup);
87 * Processing for daemonization
89 static void
90 daemonize(void)
92 switch (fork()) {
93 case -1:
94 syslog(LOG_ERR, "reparsed: can't fork - errno %d", errno);
95 exit(2);
96 /* NOTREACHED */
97 case 0: /* child */
98 break;
100 default: /* parent */
101 _exit(0);
103 (void) chdir("/");
106 * Close stdin, stdout, and stderr.
107 * Open again to redirect input+output
109 (void) close(0);
110 (void) close(1);
111 (void) close(2);
112 (void) open("/dev/null", O_RDONLY);
113 (void) open("/dev/null", O_WRONLY);
114 (void) dup(1);
115 (void) setsid();
119 main(int argc, char *argv[])
121 pid_t pid;
122 int c, error;
123 struct rlimit rlset;
124 char *defval;
126 MyName = argv[0];
127 if (geteuid() != 0) {
128 syslog(LOG_ERR, "%s must be run as root", MyName);
129 exit(1);
132 while ((c = getopt(argc, argv, REPARSED_CMD_OPTS)) != EOF) {
133 switch (c) {
134 case 'v':
135 verbose++;
136 break;
137 default:
138 usage();
142 daemonize();
143 openlog(MyName, LOG_PID | LOG_NDELAY, LOG_DAEMON);
145 (void) _create_daemon_lock(REPARSED, DAEMON_UID, DAEMON_GID);
146 (void) enable_extended_FILE_stdio(-1, -1);
147 switch (_enter_daemon_lock(REPARSED)) {
148 case 0:
149 break;
150 case -1:
151 syslog(LOG_ERR, "Error locking for %s", REPARSED);
152 exit(2);
153 default:
154 /* daemon was already running */
155 exit(0);
158 (void) signal(SIGHUP, warn_hup);
161 * Make the process a privilege aware daemon.
162 * Only "basic" privileges are required.
165 if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, 0, 0,
166 NULL) == -1) {
167 syslog(LOG_ERR, "should be run with sufficient privileges");
168 exit(3);
172 * Clear basic privileges not required by reparsed.
174 __fini_daemon_priv(PRIV_PROC_FORK, PRIV_PROC_EXEC, PRIV_PROC_SESSION,
175 PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, NULL);
177 return (start_reparsed_svcs());
180 static void
181 reparsed_door_call_error(int error, int buflen)
183 reparsed_door_res_t rpd_res;
185 memset(&rpd_res, 0, sizeof (reparsed_door_res_t));
186 rpd_res.res_status = error;
187 rpd_res.res_len = buflen;
188 door_return((char *)&rpd_res, sizeof (reparsed_door_res_t), NULL, 0);
190 (void) door_return(NULL, 0, NULL, 0);
191 /* NOTREACHED */
195 * reparsed_doorfunc
197 * argp: "service_type:service_data" string
198 * dp & n_desc: not used.
200 static void
201 reparsed_doorfunc(void *cookie, char *argp, size_t arg_size,
202 door_desc_t *dp, uint_t n_desc)
204 int err;
205 size_t bufsz;
206 char *svc_type, *svc_data;
207 char *cp, *buf, *sbuf, res_buf[DOOR_RESULT_BUFSZ];
208 reparsed_door_res_t *resp;
210 if ((argp == NULL) || (arg_size == 0)) {
211 reparsed_door_call_error(EINVAL, 0);
212 /* NOTREACHED */
215 if (verbose)
216 syslog(LOG_NOTICE, "reparsed_door: [%s, %d]", argp, arg_size);
218 if ((svc_type = strdup(argp)) == NULL) {
219 reparsed_door_call_error(ENOMEM, 0);
220 /* NOTREACHED */
224 * Door argument string comes in "service_type:service_data" format.
225 * Need to break it into separate "service_type" and "service_data"
226 * string before passing them to reparse_deref() to process them.
228 if ((cp = strchr(svc_type, ':')) == NULL) {
229 free(svc_type);
230 reparsed_door_call_error(EINVAL, 0);
231 /* NOTREACHED */
233 *cp++ = '\0';
234 svc_data = cp;
237 * Setup buffer for reparse_deref(). 'bufsz' is the actual
238 * buffer size to hold the result returned by reparse_deref().
240 resp = (reparsed_door_res_t *)res_buf;
241 buf = resp->res_data;
242 bufsz = sizeof (res_buf) - sizeof (reparsed_door_res_t);
245 * reparse_deref() calls the service type plugin library to process
246 * the service data. The plugin library function should understand
247 * the context of the service data and should be the one to XDR the
248 * results before returning it to the caller.
250 err = reparse_deref(svc_type, svc_data, buf, &bufsz);
252 if (verbose)
253 syslog(LOG_NOTICE,
254 "reparsed_deref(svc_type: %s, data: %s, size: %d) -> %d",
255 svc_type, svc_data, bufsz, err);
257 switch (err) {
258 case 0:
259 break;
261 case EOVERFLOW:
263 * bufsz was returned with size needed by reparse_deref().
265 * We cannot use malloc() here because door_return() never
266 * returns, and memory allocated by malloc() would get leaked.
268 sbuf = alloca(bufsz + sizeof (reparsed_door_res_t));
269 if (sbuf == NULL || stack_inbounds(buf) == 0 ||
270 stack_inbounds(buf + sizeof (reparsed_door_res_t) +
271 SAFETY_BUFFER - 1) == 0) {
272 free(svc_type);
273 reparsed_door_call_error(ENOMEM, 0);
274 /* NOTREACHED */
277 resp = (reparsed_door_res_t *)sbuf;
278 if ((err = reparse_deref(svc_type, svc_data, resp->res_data,
279 &bufsz)) == 0)
280 break;
282 /* fall through */
284 default:
285 free(svc_type);
286 reparsed_door_call_error(err, 0);
287 /* NOTREACHED */
290 free(svc_type);
292 if (verbose)
293 syslog(LOG_NOTICE, "reparsed_door_return <buf=%s> size=%d",
294 buf, bufsz);
296 resp->res_status = 0;
297 resp->res_len = bufsz;
298 (void) door_return((char *)resp, bufsz + sizeof (reparsed_door_res_t),
299 NULL, 0);
301 (void) door_return(NULL, 0, NULL, 0);
302 /* NOTREACHED */
305 static int
306 start_reparsed_svcs()
308 int doorfd;
309 int dfd;
311 if ((doorfd = door_create(reparsed_doorfunc, NULL,
312 DOOR_REFUSE_DESC|DOOR_NO_CANCEL)) == -1) {
313 syslog(LOG_ERR, "Unable to create door");
314 return (1);
318 * Create a file system path for the door
320 if ((dfd = open(REPARSED_DOOR, O_RDWR|O_CREAT|O_TRUNC,
321 S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1) {
322 syslog(LOG_ERR, "unable to open %s", REPARSED_DOOR);
323 (void) close(doorfd);
324 return (1);
328 * Clean up any stale associations
330 (void) fdetach(REPARSED_DOOR);
333 * Register in the kernel namespace for door_ki_open().
335 if (fattach(doorfd, REPARSED_DOOR) == -1) {
336 syslog(LOG_ERR, "Unable to fattach door %s", REPARSED_DOOR);
337 (void) close(doorfd);
338 (void) close(dfd);
339 return (1);
341 (void) close(dfd);
344 * Wait for incoming calls
346 /*CONSTCOND*/
347 while (1)
348 (void) pause();
350 syslog(LOG_ERR, "Door server exited");
351 return (10);