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 2000-2002 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 
46 char efcode_sh_file[] = "/usr/lib/efcode/efcode.sh";
47 char dev_fcode_file[] = "/dev/fcode";
48 
49 int debug = 0;
50 
51 int
52 main(int argc, char **argv)
53 {
54 	extern char *optarg;
55 	extern int optind, opterr, optopt;
56 	int c, fd, nbytes, status;
57 	char tc;
58 	pid_t pid, tpid;
59 	long nerr = 0;
60 
61 	openlog("efdaemon", LOG_PID|LOG_CONS, LOG_DAEMON);
62 
63 	while ((c = getopt(argc, argv, "d")) != EOF) {
64 		switch (c) {
65 
66 		case 'd':
67 			debug++;
68 			break;
69 
70 		case '?':
71 			syslog(LOG_ERR, "Usage: efdaemon [ -d ]\n");
72 			exit(1);
73 		}
74 	}
75 
76 	/*
77 	 * Ensure we can open /dev/fcode
78 	 */
79 	if ((fd = open(dev_fcode_file, O_RDONLY)) < 0) {
80 		/*
81 		 * Only output message if debug is on.  On most systems,
82 		 * /dev/fcode will not exist, so this message would pollute the
83 		 * console.
84 		 */
85 		if (debug)
86 			syslog(LOG_ERR, "Can't open %s: %s\n", dev_fcode_file,
87 			    strerror(errno));
88 		exit(1);
89 	}
90 	close(fd);
91 
92 	/*
93 	 * Ensure that /usr/lib/efcode/efcode.sh exists and is executable.
94 	 */
95 	if (access(efcode_sh_file, X_OK | R_OK)) {
96 		syslog(LOG_ERR, "%s: %s\n", efcode_sh_file, strerror(errno));
97 		exit(1);
98 	}
99 
100 	/*
101 	 * Fork a child then parent exits so we're a child of initd.
102 	 */
103 	if ((pid = fork()) < 0) {
104 		syslog(LOG_ERR, "Fork failed: %s\n", strerror(errno));
105 		exit(1);
106 	}
107 	if (pid)
108 		exit(0);
109 
110 
111 	/*
112 	 * detach from tty here.
113 	 */
114 	setpgrp();
115 	close(0);
116 	close(1);
117 	close(2);
118 	(void) open("/dev/null", O_RDWR);
119 	(void) dup(0);
120 	(void) dup(0);
121 
122 	for (;;) {
123 		while ((fd = open(dev_fcode_file, O_RDONLY)) < 0) {
124 			nerr++;
125 			if (nerr == 1)
126 				syslog(LOG_ERR, "Can't open %s: %s\n",
127 				    dev_fcode_file, strerror(errno));
128 			sleep(1);
129 		}
130 		if (nerr > 1) {
131 			syslog(LOG_ERR, "Open on %s failed %d times\n",
132 			    dev_fcode_file, nerr);
133 		}
134 		nerr = 0;
135 		nbytes = read(fd, &tc, sizeof (tc));
136 		if (nbytes < 0) {
137 			syslog(LOG_ERR, "Read of %s: %s\n", dev_fcode_file,
138 			    strerror(errno));
139 			close(fd);
140 			continue;
141 		}
142 		if (debug)
143 			syslog(LOG_DEBUG, "Got request\n");
144 		while ((pid = fork()) < 0) {
145 			nerr++;
146 			if (nerr == 1)
147 				syslog(LOG_ERR, "Fork failed: %s\n",
148 				    strerror(errno));
149 			sleep(1);
150 		}
151 		if ((nerr > 1) && pid) {
152 			syslog(LOG_ERR, "Fork failed %d times\n", nerr);
153 		}
154 		nerr = 0;
155 		if (pid) {
156 			tpid = wait(&status);
157 			if (tpid < 0)
158 				syslog(LOG_ERR, "Wait error: %s\n",
159 				    strerror(errno));
160 			else if (pid != tpid)
161 				syslog(LOG_ERR, "Wait error, expect pid: %d"
162 				    " got %d, status: %x\n", pid, tpid, status);
163 			else if (status)
164 				syslog(LOG_ERR, "Wait pid: %d status: %x\n",
165 				    pid, status);
166 			else if (debug)
167 				syslog(LOG_DEBUG, "Wait: pid: %d\n", pid);
168 			close(fd);
169 			continue;
170 		}
171 		if (debug)
172 			syslog(LOG_DEBUG, "Child: %d processing request\n",
173 			    getpid());
174 		fcntl(fd, F_DUP2FD, 0);
175 		while (execl("/bin/sh", "sh", efcode_sh_file, NULL)) {
176 			nerr++;
177 			if (nerr == 1)
178 				syslog(LOG_ERR, "execl(/bin/sh) failed: %s\n",
179 				    strerror(errno));
180 			sleep(1);
181 		}
182 	}
183 
184 	return (0);
185 }
186