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