1 /* 2 * Copyright (c) 1982, 1986 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)subr_log.c 7.1 (Berkeley) 06/05/86 7 */ 8 9 /* 10 * Error log buffer for kernel printf's. 11 */ 12 13 #include "param.h" 14 #include "dir.h" 15 #include "user.h" 16 #include "proc.h" 17 #include "ioctl.h" 18 #include "msgbuf.h" 19 #include "file.h" 20 #include "errno.h" 21 22 #define LOG_RDPRI (PZERO + 1) 23 24 #define LOG_NBIO 0x02 25 #define LOG_ASYNC 0x04 26 #define LOG_RDWAIT 0x08 27 28 struct logsoftc { 29 int sc_state; /* see above for possibilities */ 30 struct proc *sc_selp; /* process waiting on select call */ 31 int sc_pgrp; /* process group for async I/O */ 32 } logsoftc; 33 34 int log_open; /* also used in log() */ 35 36 /*ARGSUSED*/ 37 logopen(dev) 38 dev_t dev; 39 { 40 41 if (log_open) 42 return (EBUSY); 43 log_open = 1; 44 logsoftc.sc_selp = 0; 45 logsoftc.sc_pgrp = u.u_procp->p_pgrp; 46 /* 47 * Potential race here with putchar() but since putchar should be 48 * called by autoconf, msg_magic should be initialized by the time 49 * we get here. 50 */ 51 if (msgbuf.msg_magic != MSG_MAGIC) { 52 register int i; 53 54 msgbuf.msg_magic = MSG_MAGIC; 55 msgbuf.msg_bufx = msgbuf.msg_bufr = 0; 56 for (i=0; i < MSG_BSIZE; i++) 57 msgbuf.msg_bufc[i] = 0; 58 } 59 return (0); 60 } 61 62 /*ARGSUSED*/ 63 logclose(dev, flag) 64 dev_t dev; 65 { 66 log_open = 0; 67 logsoftc.sc_state = 0; 68 logsoftc.sc_selp = 0; 69 logsoftc.sc_pgrp = 0; 70 } 71 72 /*ARGSUSED*/ 73 logread(dev, uio) 74 dev_t dev; 75 struct uio *uio; 76 { 77 register long l; 78 register int s; 79 int error = 0; 80 81 s = splhigh(); 82 while (msgbuf.msg_bufr == msgbuf.msg_bufx) { 83 if (logsoftc.sc_state & LOG_NBIO) { 84 splx(s); 85 return (EWOULDBLOCK); 86 } 87 logsoftc.sc_state |= LOG_RDWAIT; 88 sleep((caddr_t)&msgbuf, LOG_RDPRI); 89 } 90 splx(s); 91 logsoftc.sc_state &= ~LOG_RDWAIT; 92 93 while (uio->uio_resid > 0) { 94 l = msgbuf.msg_bufx - msgbuf.msg_bufr; 95 if (l < 0) 96 l = MSG_BSIZE - msgbuf.msg_bufr; 97 l = MIN(l, uio->uio_resid); 98 if (l == 0) 99 break; 100 error = uiomove((caddr_t)&msgbuf.msg_bufc[msgbuf.msg_bufr], 101 (int)l, UIO_READ, uio); 102 if (error) 103 break; 104 msgbuf.msg_bufr += l; 105 if (msgbuf.msg_bufr < 0 || msgbuf.msg_bufr >= MSG_BSIZE) 106 msgbuf.msg_bufr = 0; 107 } 108 return (error); 109 } 110 111 /*ARGSUSED*/ 112 logselect(dev, rw) 113 dev_t dev; 114 int rw; 115 { 116 int s = splhigh(); 117 118 switch (rw) { 119 120 case FREAD: 121 if (msgbuf.msg_bufr != msgbuf.msg_bufx) { 122 splx(s); 123 return (1); 124 } 125 logsoftc.sc_selp = u.u_procp; 126 break; 127 } 128 splx(s); 129 return (0); 130 } 131 132 logwakeup() 133 { 134 135 if (!log_open) 136 return; 137 if (logsoftc.sc_selp) { 138 selwakeup(logsoftc.sc_selp, 0); 139 logsoftc.sc_selp = 0; 140 } 141 if (logsoftc.sc_state & LOG_ASYNC) 142 gsignal(logsoftc.sc_pgrp, SIGIO); 143 if (logsoftc.sc_state & LOG_RDWAIT) { 144 wakeup((caddr_t)&msgbuf); 145 logsoftc.sc_state &= ~LOG_RDWAIT; 146 } 147 } 148 149 /*ARGSUSED*/ 150 logioctl(com, data, flag) 151 caddr_t data; 152 { 153 long l; 154 int s; 155 156 switch (com) { 157 158 /* return number of characters immediately available */ 159 case FIONREAD: 160 s = splhigh(); 161 l = msgbuf.msg_bufx - msgbuf.msg_bufr; 162 splx(s); 163 if (l < 0) 164 l += MSG_BSIZE; 165 *(off_t *)data = l; 166 break; 167 168 case FIONBIO: 169 if (*(int *)data) 170 logsoftc.sc_state |= LOG_NBIO; 171 else 172 logsoftc.sc_state &= ~LOG_NBIO; 173 break; 174 175 case FIOASYNC: 176 if (*(int *)data) 177 logsoftc.sc_state |= LOG_ASYNC; 178 else 179 logsoftc.sc_state &= ~LOG_ASYNC; 180 break; 181 182 case TIOCSPGRP: 183 logsoftc.sc_pgrp = *(int *)data; 184 break; 185 186 case TIOCGPGRP: 187 *(int *)data = logsoftc.sc_pgrp; 188 break; 189 190 default: 191 return (-1); 192 } 193 return (0); 194 } 195