FreeBSD/Linux Kernel Cross Reference
sys/dev/cons.c
1 /* $NetBSD: cons.c,v 1.65 2008/01/24 17:32:52 ad Exp $ */
2
3 /*
4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * the Systems Programming Group of the University of Utah Computer
9 * Science Department.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * from: Utah $Hdr: cons.c 1.7 92/01/21$
36 *
37 * @(#)cons.c 8.2 (Berkeley) 1/12/94
38 */
39
40 /*
41 * Copyright (c) 1988 University of Utah.
42 *
43 * This code is derived from software contributed to Berkeley by
44 * the Systems Programming Group of the University of Utah Computer
45 * Science Department.
46 *
47 * Redistribution and use in source and binary forms, with or without
48 * modification, are permitted provided that the following conditions
49 * are met:
50 * 1. Redistributions of source code must retain the above copyright
51 * notice, this list of conditions and the following disclaimer.
52 * 2. Redistributions in binary form must reproduce the above copyright
53 * notice, this list of conditions and the following disclaimer in the
54 * documentation and/or other materials provided with the distribution.
55 * 3. All advertising materials mentioning features or use of this software
56 * must display the following acknowledgement:
57 * This product includes software developed by the University of
58 * California, Berkeley and its contributors.
59 * 4. Neither the name of the University nor the names of its contributors
60 * may be used to endorse or promote products derived from this software
61 * without specific prior written permission.
62 *
63 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
64 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
65 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
66 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
67 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
68 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
69 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
70 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
71 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
72 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
73 * SUCH DAMAGE.
74 *
75 * from: Utah $Hdr: cons.c 1.7 92/01/21$
76 *
77 * @(#)cons.c 8.2 (Berkeley) 1/12/94
78 */
79
80 #include <sys/cdefs.h>
81 __KERNEL_RCSID(0, "$NetBSD: cons.c,v 1.65 2008/01/24 17:32:52 ad Exp $");
82
83 #include <sys/param.h>
84 #include <sys/proc.h>
85 #include <sys/user.h>
86 #include <sys/systm.h>
87 #include <sys/buf.h>
88 #include <sys/ioctl.h>
89 #include <sys/poll.h>
90 #include <sys/tty.h>
91 #include <sys/file.h>
92 #include <sys/conf.h>
93 #include <sys/vnode.h>
94 #include <sys/kauth.h>
95 #include <sys/mutex.h>
96
97 #include <dev/cons.h>
98
99 dev_type_open(cnopen);
100 dev_type_close(cnclose);
101 dev_type_read(cnread);
102 dev_type_write(cnwrite);
103 dev_type_ioctl(cnioctl);
104 dev_type_poll(cnpoll);
105 dev_type_kqfilter(cnkqfilter);
106
107 static bool cn_redirect(dev_t *, int, int *);
108
109 const struct cdevsw cons_cdevsw = {
110 cnopen, cnclose, cnread, cnwrite, cnioctl,
111 nostop, notty, cnpoll, nommap, cnkqfilter, D_TTY
112 };
113
114 struct tty *constty = NULL; /* virtual console output device */
115 struct consdev *cn_tab; /* physical console device info */
116 struct vnode *cn_devvp[2]; /* vnode for underlying device. */
117
118 int
119 cnopen(dev_t dev, int flag, int mode, struct lwp *l)
120 {
121 dev_t cndev;
122 int unit, error;
123
124 unit = minor(dev);
125 if (unit > 1)
126 return ENODEV;
127
128 if (cn_tab == NULL)
129 return (0);
130
131 /*
132 * always open the 'real' console device, so we don't get nailed
133 * later. This follows normal device semantics; they always get
134 * open() calls.
135 */
136 cndev = cn_tab->cn_dev;
137 if (cndev == NODEV) {
138 /*
139 * This is most likely an error in the console attach
140 * code. Panicking looks better than jumping into nowhere
141 * through cdevsw below....
142 */
143 panic("cnopen: no console device");
144 }
145 if (dev == cndev) {
146 /*
147 * This causes cnopen() to be called recursively, which
148 * is generally a bad thing. It is often caused when
149 * dev == 0 and cn_dev has not been set, but was probably
150 * initialised to 0.
151 */
152 panic("cnopen: cn_tab->cn_dev == dev");
153 }
154 if (cn_devvp[unit] != NULLVP)
155 return 0;
156 if ((error = cdevvp(cndev, &cn_devvp[unit])) != 0)
157 printf("cnopen: unable to get vnode reference\n");
158 error = vn_lock(cn_devvp[unit], LK_EXCLUSIVE | LK_RETRY);
159 if (error == 0) {
160 error = VOP_OPEN(cn_devvp[unit], flag, kauth_cred_get());
161 VOP_UNLOCK(cn_devvp[unit], 0);
162 }
163 return error;
164 }
165
166 int
167 cnclose(dev_t dev, int flag, int mode, struct lwp *l)
168 {
169 struct vnode *vp;
170 int unit, error;
171
172 unit = minor(dev);
173
174 if (cn_tab == NULL)
175 return (0);
176
177 vp = cn_devvp[unit];
178 cn_devvp[unit] = NULL;
179 error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
180 if (error == 0) {
181 error = VOP_CLOSE(vp, flag, kauth_cred_get());
182 VOP_UNLOCK(vp, 0);
183 }
184 return error;
185 }
186
187 int
188 cnread(dev_t dev, struct uio *uio, int flag)
189 {
190 int error;
191
192 /*
193 * If we would redirect input, punt. This will keep strange
194 * things from happening to people who are using the real
195 * console. Nothing should be using /dev/console for
196 * input (except a shell in single-user mode, but then,
197 * one wouldn't TIOCCONS then).
198 */
199 if (!cn_redirect(&dev, 1, &error))
200 return error;
201 return cdev_read(dev, uio, flag);
202 }
203
204 int
205 cnwrite(dev_t dev, struct uio *uio, int flag)
206 {
207 int error;
208
209 /* Redirect output, if that's appropriate. */
210 if (!cn_redirect(&dev, 0, &error))
211 return error;
212 return cdev_write(dev, uio, flag);
213 }
214
215 int
216 cnioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
217 {
218 int error;
219
220 error = 0;
221
222 /*
223 * Superuser can always use this to wrest control of console
224 * output from the "virtual" console.
225 */
226 if (cmd == TIOCCONS && constty != NULL) {
227 error = kauth_authorize_generic(l->l_cred,
228 KAUTH_GENERIC_ISSUSER, NULL);
229 if (!error)
230 constty = NULL;
231 return (error);
232 }
233
234 /*
235 * Redirect the ioctl, if that's appropriate.
236 * Note that strange things can happen, if a program does
237 * ioctls on /dev/console, then the console is redirected
238 * out from under it.
239 */
240 if (!cn_redirect(&dev, 0, &error))
241 return error;
242 return cdev_ioctl(dev, cmd, data, flag, l);
243 }
244
245 /*ARGSUSED*/
246 int
247 cnpoll(dev_t dev, int events, struct lwp *l)
248 {
249 int error;
250
251 /*
252 * Redirect the poll, if that's appropriate.
253 * I don't want to think of the possible side effects
254 * of console redirection here.
255 */
256 if (!cn_redirect(&dev, 0, &error))
257 return POLLHUP;
258 return cdev_poll(dev, events, l);
259 }
260
261 /*ARGSUSED*/
262 int
263 cnkqfilter(dev_t dev, struct knote *kn)
264 {
265 int error;
266
267 /*
268 * Redirect the kqfilter, if that's appropriate.
269 * I don't want to think of the possible side effects
270 * of console redirection here.
271 */
272 if (!cn_redirect(&dev, 0, &error))
273 return error;
274 return cdev_kqfilter(dev, kn);
275 }
276
277 int
278 cngetc(void)
279 {
280 if (cn_tab == NULL)
281 return (0);
282 return ((*cn_tab->cn_getc)(cn_tab->cn_dev));
283 }
284
285 int
286 cngetsn(char *cp, int size)
287 {
288 char *lp;
289 int c, len;
290
291 cnpollc(1);
292
293 lp = cp;
294 len = 0;
295 for (;;) {
296 c = cngetc();
297 switch (c) {
298 case '\n':
299 case '\r':
300 printf("\n");
301 *lp++ = '\0';
302 cnpollc(0);
303 return (len);
304 case '\b':
305 case '\177':
306 case '#':
307 if (len) {
308 --len;
309 --lp;
310 printf("\b \b");
311 }
312 continue;
313 case '@':
314 case 'u'&037: /* CTRL-u */
315 len = 0;
316 lp = cp;
317 printf("\n");
318 continue;
319 default:
320 if (len + 1 >= size || c < ' ') {
321 printf("\007");
322 continue;
323 }
324 printf("%c", c);
325 ++len;
326 *lp++ = c;
327 }
328 }
329 }
330
331 void
332 cnputc(int c)
333 {
334
335 if (cn_tab == NULL)
336 return;
337
338 if (c) {
339 (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
340 if (c == '\n')
341 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
342 }
343 }
344
345 void
346 cnpollc(int on)
347 {
348 static int refcount = 0;
349
350 if (cn_tab == NULL)
351 return;
352 if (!on)
353 --refcount;
354 if (refcount == 0)
355 (*cn_tab->cn_pollc)(cn_tab->cn_dev, on);
356 if (on)
357 ++refcount;
358 }
359
360 void
361 nullcnpollc(dev_t dev, int on)
362 {
363
364 }
365
366 void
367 cnbell(u_int pitch, u_int period, u_int volume)
368 {
369
370 if (cn_tab == NULL || cn_tab->cn_bell == NULL)
371 return;
372 (*cn_tab->cn_bell)(cn_tab->cn_dev, pitch, period, volume);
373 }
374
375 void
376 cnflush(void)
377 {
378 if (cn_tab == NULL || cn_tab->cn_flush == NULL)
379 return;
380 (*cn_tab->cn_flush)(cn_tab->cn_dev);
381 }
382
383 void
384 cnhalt(void)
385 {
386 if (cn_tab == NULL || cn_tab->cn_halt == NULL)
387 return;
388 (*cn_tab->cn_halt)(cn_tab->cn_dev);
389 }
390
391 /*
392 * Redirect output, if that's appropriate. If there's no real console,
393 * return ENXIO.
394 *
395 * Call with tty_mutex held.
396 */
397 static bool
398 cn_redirect(dev_t *devp, int is_read, int *error)
399 {
400 dev_t dev = *devp;
401
402 *error = ENXIO;
403 if (constty != NULL && minor(dev) == 0 &&
404 (cn_tab == NULL || (cn_tab->cn_pri != CN_REMOTE))) {
405 if (is_read) {
406 *error = 0;
407 return false;
408 }
409 dev = constty->t_dev;
410 } else if (cn_tab == NULL)
411 return false;
412 else
413 dev = cn_tab->cn_dev;
414 *devp = dev;
415 return true;
416 }
Cache object: 13759c9877482a05b3c8828121d8900c
|