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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * efdaemon - Emebbed Fcode Interpreter daemon.
31  *
32  * Opens /dev/fcode, detaches from tty and reads a request.  Upon successful
33  * return, invokes the Fcode interpreter via the shell script:
34  * /usr/lib/efcode/efcode.sh  Waits for completion of the interpreter.
35  */
36 
37 #include <stdio.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <stdlib.h>
41 #include <strings.h>
42 #include <syslog.h>
43 #include <errno.h>
44 #include <sys/wait.h>
45 #include <sys/fcode.h>
46 
47 char efcode_sh_file[] = "/usr/lib/efcode/efcode.sh";
48 char dev_fcode_file[] = "/dev/fcode";
49 
50 int debug = 0;
51 
52 int
53 main(int argc, char **argv)
54 {
55 	extern char *optarg;
56 	extern int optind, opterr, optopt;
57 	int c, fd, nbytes, status;
58 	char tc;
59 	pid_t pid, tpid;
60 	long nerr = 0;
61 	int error;
62 
63 	openlog("efdaemon", LOG_PID|LOG_CONS, LOG_DAEMON);
64 
65 	while ((c = getopt(argc, argv, "d")) != EOF) {
66 		switch (c) {
67 
68 		case 'd':
69 			debug++;
70 			break;
71 
72 		case '?':
73 			syslog(LOG_ERR, "Usage: efdaemon [ -d ]\n");
74 			exit(1);
75 		}
76 	}
77 
78 	/*
79 	 * Ensure we can open /dev/fcode
80 	 */
81 	if ((fd = open(dev_fcode_file, O_RDONLY)) < 0) {
82 		/*
83 		 * Only output message if debug is on.  On most systems,
84 		 * /dev/fcode will not exist, so this message would pollute the
85 		 * console.
86 		 */
87 		if (debug)
88 			syslog(LOG_ERR, "Can't open %s: %s\n", dev_fcode_file,
89 			    strerror(errno));
90 		exit(1);
91 	}
92 	close(fd);
93 
94 	/*
95 	 * Ensure that /usr/lib/efcode/efcode.sh exists and is executable.
96 	 */
97 	if (access(efcode_sh_file, X_OK | R_OK)) {
98 		syslog(LOG_ERR, "%s: %s\n", efcode_sh_file, strerror(errno));
99 		exit(1);
100 	}
101 
102 	/*
103 	 * Fork a child then parent exits so we're a child of initd.
104 	 */
105 	if ((pid = fork()) < 0) {
106 		syslog(LOG_ERR, "Fork failed: %s\n", strerror(errno));
107 		exit(1);
108 	}
109 	if (pid)
110 		exit(0);
111 
112 
113 	/*
114 	 * detach from tty here.
115 	 */
116 	setpgrp();
117 	close(0);
118 	close(1);
119 	close(2);
120 	(void) open("/dev/null", O_RDWR);
121 	(void) dup(0);
122 	(void) dup(0);
123 
124 	for (;;) {
125 		while ((fd = open(dev_fcode_file, O_RDONLY)) < 0) {
126 			nerr++;
127 			if (nerr == 1)
128 				syslog(LOG_ERR, "Can't open %s: %s\n",
129 				    dev_fcode_file, strerror(errno));
130 			sleep(1);
131 		}
132 		if (nerr > 1) {
133 			syslog(LOG_ERR, "Open on %s failed %d times\n",
134 			    dev_fcode_file, nerr);
135 		}
136 		nerr = 0;
137 		nbytes = read(fd, &tc, sizeof (tc));
138 		if (nbytes < 0) {
139 			syslog(LOG_ERR, "Read of %s: %s\n", dev_fcode_file,
140 			    strerror(errno));
141 			close(fd);
142 			continue;
143 		}
144 		if (debug)
145 			syslog(LOG_DEBUG, "Got request\n");
146 		while ((pid = fork()) < 0) {
147 			nerr++;
148 			if (nerr == 1)
149 				syslog(LOG_ERR, "Fork failed: %s\n",
150 				    strerror(errno));
151 			sleep(1);
152 		}
153 		if ((nerr > 1) && pid) {
154 			syslog(LOG_ERR, "Fork failed %d times\n", nerr);
155 		}
156 		nerr = 0;
157 		if (pid) {
158 			tpid = wait(&status);
159 			if (tpid < 0)
160 				syslog(LOG_ERR, "Wait error: %s\n",
161 				    strerror(errno));
162 			else if (pid != tpid)
163 				syslog(LOG_ERR, "Wait error, expect pid: %d"
164 				    " got %d, status: %x\n", pid, tpid, status);
165 			else if (status) {
166 				syslog(LOG_ERR, "Wait pid: %d status: %x\n",
167 				    pid, status);
168 				if (WIFEXITED(status) &&
169 				    (WEXITSTATUS(status) == 1)) {
170 					error = FC_FCODE_ABORT;
171 				} else {
172 					error = FC_EXEC_FAILED;
173 				}
174 				if (ioctl(fd, FC_SET_FCODE_ERROR, &error) < 0) {
175 					syslog(LOG_ERR,
176 					    "ioctl(FC_SET_FCODE_ERROR)"
177 					    " failed\n");
178 				}
179 			} else if (debug)
180 				syslog(LOG_DEBUG, "Wait: pid: %d\n", pid);
181 			close(fd);
182 			continue;
183 		}
184 		if (debug)
185 			syslog(LOG_DEBUG, "Child: %d processing request\n",
186 			    getpid());
187 		fcntl(fd, F_DUP2FD, 0);
188 		while (execl("/bin/sh", "sh", efcode_sh_file, NULL)) {
189 			nerr++;
190 			if (nerr == 1)
191 				syslog(LOG_ERR, "execl(/bin/sh) failed: %s\n",
192 				    strerror(errno));
193 			sleep(1);
194 		}
195 	}
196 
197 	return (0);
198 }
199