cons.c revision 1.63 1 /* $NetBSD: cons.c,v 1.63 2007/03/04 06:01:41 christos 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.63 2007/03/04 06:01:41 christos 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 const struct cdevsw *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 const struct cdevsw *cdev;
122 dev_t cndev;
123 int unit;
124
125 unit = minor(dev);
126 if (unit > 1)
127 return ENODEV;
128
129 if (cn_tab == NULL)
130 return (0);
131
132 /*
133 * always open the 'real' console device, so we don't get nailed
134 * later. This follows normal device semantics; they always get
135 * open() calls.
136 */
137 cndev = cn_tab->cn_dev;
138 if (cndev == NODEV) {
139 /*
140 * This is most likely an error in the console attach
141 * code. Panicking looks better than jumping into nowhere
142 * through cdevsw below....
143 */
144 panic("cnopen: no console device");
145 }
146 if (dev == cndev) {
147 /*
148 * This causes cnopen() to be called recursively, which
149 * is generally a bad thing. It is often caused when
150 * dev == 0 and cn_dev has not been set, but was probably
151 * initialised to 0.
152 */
153 panic("cnopen: cn_tab->cn_dev == dev");
154 }
155 cdev = cdevsw_lookup(cndev);
156 if (cdev == NULL)
157 return (ENXIO);
158
159 if (cn_devvp[unit] == NULLVP) {
160 /* try to get a reference on its vnode, but fail silently */
161 cdevvp(cndev, &cn_devvp[unit]);
162 }
163 return ((*cdev->d_open)(cndev, flag, mode, l));
164 }
165
166 int
167 cnclose(dev_t dev, int flag, int mode, struct lwp *l)
168 {
169 const struct cdevsw *cdev;
170 struct vnode *vp;
171 int unit;
172
173 unit = minor(dev);
174
175 if (cn_tab == NULL)
176 return (0);
177
178 /*
179 * If the real console isn't otherwise open, close it.
180 * If it's otherwise open, don't close it, because that'll
181 * screw up others who have it open.
182 */
183 dev = cn_tab->cn_dev;
184 cdev = cdevsw_lookup(dev);
185 if (cdev == NULL)
186 return (ENXIO);
187 if (cn_devvp[unit] != NULLVP) {
188 /* release our reference to real dev's vnode */
189 vrele(cn_devvp[unit]);
190 cn_devvp[unit] = NULLVP;
191 }
192 if (vfinddev(dev, VCHR, &vp) && vcount(vp))
193 return (0);
194 return ((*cdev->d_close)(dev, flag, mode, l));
195 }
196
197 int
198 cnread(dev_t dev, struct uio *uio, int flag)
199 {
200 const struct cdevsw *cdev;
201 int error;
202
203 /*
204 * If we would redirect input, punt. This will keep strange
205 * things from happening to people who are using the real
206 * console. Nothing should be using /dev/console for
207 * input (except a shell in single-user mode, but then,
208 * one wouldn't TIOCCONS then).
209 */
210 cdev = cn_redirect(&dev, 1, &error);
211 if (cdev == NULL)
212 return error;
213 return ((*cdev->d_read)(dev, uio, flag));
214 }
215
216 int
217 cnwrite(dev_t dev, struct uio *uio, int flag)
218 {
219 const struct cdevsw *cdev;
220 int error;
221
222 /* Redirect output, if that's appropriate. */
223 cdev = cn_redirect(&dev, 0, &error);
224 if (cdev == NULL)
225 return error;
226
227 return ((*cdev->d_write)(dev, uio, flag));
228 }
229
230 int
231 cnioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
232 {
233 const struct cdevsw *cdev;
234 int error;
235
236 error = 0;
237
238 /*
239 * Superuser can always use this to wrest control of console
240 * output from the "virtual" console.
241 */
242 #ifdef notyet
243 mutex_enter(&tty_mutex);
244 #endif
245 if (cmd == TIOCCONS && constty != NULL) {
246 error = kauth_authorize_generic(l->l_cred,
247 KAUTH_GENERIC_ISSUSER, NULL);
248 if (!error)
249 constty = NULL;
250 #ifdef notyet
251 mutex_exit(&tty_mutex);
252 #endif
253 return (error);
254 }
255
256 /*
257 * Redirect the ioctl, if that's appropriate.
258 * Note that strange things can happen, if a program does
259 * ioctls on /dev/console, then the console is redirected
260 * out from under it.
261 */
262 cdev = cn_redirect(&dev, 0, &error);
263 #ifdef notyet
264 mutex_exit(&tty_mutex);
265 #endif
266 if (cdev != NULL)
267 error = (*cdev->d_ioctl)(dev, cmd, data, flag, l);
268 return (error);
269 }
270
271 /*ARGSUSED*/
272 int
273 cnpoll(dev_t dev, int events, struct lwp *l)
274 {
275 const struct cdevsw *cdev;
276 int error;
277
278 /*
279 * Redirect the poll, if that's appropriate.
280 * I don't want to think of the possible side effects
281 * of console redirection here.
282 */
283 cdev = cn_redirect(&dev, 0, &error);
284 if (cdev == NULL)
285 return POLLHUP;
286 return ((*cdev->d_poll)(dev, events, l));
287 }
288
289 /*ARGSUSED*/
290 int
291 cnkqfilter(dev_t dev, struct knote *kn)
292 {
293 const struct cdevsw *cdev;
294 int error;
295
296 /*
297 * Redirect the kqfilter, if that's appropriate.
298 * I don't want to think of the possible side effects
299 * of console redirection here.
300 */
301 cdev = cn_redirect(&dev, 0, &error);
302 if (cdev == NULL)
303 return error;
304 return ((*cdev->d_kqfilter)(dev, kn));
305 }
306
307 int
308 cngetc(void)
309 {
310 if (cn_tab == NULL)
311 return (0);
312 return ((*cn_tab->cn_getc)(cn_tab->cn_dev));
313 }
314
315 int
316 cngetsn(char *cp, int size)
317 {
318 char *lp;
319 int c, len;
320
321 cnpollc(1);
322
323 lp = cp;
324 len = 0;
325 for (;;) {
326 c = cngetc();
327 switch (c) {
328 case '\n':
329 case '\r':
330 printf("\n");
331 *lp++ = '\0';
332 cnpollc(0);
333 return (len);
334 case '\b':
335 case '\177':
336 case '#':
337 if (len) {
338 --len;
339 --lp;
340 printf("\b \b");
341 }
342 continue;
343 case '@':
344 case 'u'&037: /* CTRL-u */
345 len = 0;
346 lp = cp;
347 printf("\n");
348 continue;
349 default:
350 if (len + 1 >= size || c < ' ') {
351 printf("\007");
352 continue;
353 }
354 printf("%c", c);
355 ++len;
356 *lp++ = c;
357 }
358 }
359 }
360
361 void
362 cnputc(int c)
363 {
364
365 if (cn_tab == NULL)
366 return;
367
368 if (c) {
369 (*cn_tab->cn_putc)(cn_tab->cn_dev, c);
370 if (c == '\n')
371 (*cn_tab->cn_putc)(cn_tab->cn_dev, '\r');
372 }
373 }
374
375 void
376 cnpollc(int on)
377 {
378 static int refcount = 0;
379
380 if (cn_tab == NULL)
381 return;
382 if (!on)
383 --refcount;
384 if (refcount == 0)
385 (*cn_tab->cn_pollc)(cn_tab->cn_dev, on);
386 if (on)
387 ++refcount;
388 }
389
390 void
391 nullcnpollc(dev_t dev, int on)
392 {
393
394 }
395
396 void
397 cnbell(u_int pitch, u_int period, u_int volume)
398 {
399
400 if (cn_tab == NULL || cn_tab->cn_bell == NULL)
401 return;
402 (*cn_tab->cn_bell)(cn_tab->cn_dev, pitch, period, volume);
403 }
404
405 void
406 cnflush(void)
407 {
408 if (cn_tab == NULL || cn_tab->cn_flush == NULL)
409 return;
410 (*cn_tab->cn_flush)(cn_tab->cn_dev);
411 }
412
413 void
414 cnhalt(void)
415 {
416 if (cn_tab == NULL || cn_tab->cn_halt == NULL)
417 return;
418 (*cn_tab->cn_halt)(cn_tab->cn_dev);
419 }
420
421 /*
422 * Redirect output, if that's appropriate. If there's no real console,
423 * return ENXIO.
424 *
425 * Call with tty_mutex held.
426 */
427 static const struct cdevsw *
428 cn_redirect(dev_t *devp, int is_read, int *error)
429 {
430 dev_t dev = *devp;
431
432 *error = ENXIO;
433 if (constty != NULL && minor(dev) == 0 &&
434 (cn_tab == NULL || (cn_tab->cn_pri != CN_REMOTE))) {
435 if (is_read) {
436 *error = 0;
437 return NULL;
438 }
439 dev = constty->t_dev;
440 } else if (cn_tab == NULL)
441 return NULL;
442 else
443 dev = cn_tab->cn_dev;
444 *devp = dev;
445 return cdevsw_lookup(dev);
446 }
447