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.3 (Berkeley) 05/09/89 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 pid_t sc_pgid; /* process group id 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_pgid = u.u_procp->p_pgrp->pg_id; 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_pgid = 0; 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 sleep((caddr_t)&msgbuf, LOG_RDPRI); 88 } 89 splx(s); 90 logsoftc.sc_state &= ~LOG_RDWAIT; 91 92 while (uio->uio_resid > 0) { 93 l = msgbuf.msg_bufx - msgbuf.msg_bufr; 94 if (l < 0) 95 l = MSG_BSIZE - msgbuf.msg_bufr; 96 l = MIN(l, uio->uio_resid); 97 if (l == 0) 98 break; 99 error = uiomove((caddr_t)&msgbuf.msg_bufc[msgbuf.msg_bufr], 100 (int)l, uio); 101 if (error) 102 break; 103 msgbuf.msg_bufr += l; 104 if (msgbuf.msg_bufr < 0 || msgbuf.msg_bufr >= MSG_BSIZE) 105 msgbuf.msg_bufr = 0; 106 } 107 return (error); 108 } 109 110 /*ARGSUSED*/ 111 logselect(dev, rw) 112 dev_t dev; 113 int rw; 114 { 115 int s = splhigh(); 116 117 switch (rw) { 118 119 case FREAD: 120 if (msgbuf.msg_bufr != msgbuf.msg_bufx) { 121 splx(s); 122 return (1); 123 } 124 logsoftc.sc_selp = u.u_procp; 125 break; 126 } 127 splx(s); 128 return (0); 129 } 130 131 logwakeup() 132 { 133 134 if (!log_open) 135 return; 136 if (logsoftc.sc_selp) { 137 selwakeup(logsoftc.sc_selp, 0); 138 logsoftc.sc_selp = 0; 139 } 140 if (logsoftc.sc_state & LOG_ASYNC) 141 gsignal(logsoftc.sc_pgid, SIGIO); 142 if (logsoftc.sc_state & LOG_RDWAIT) { 143 wakeup((caddr_t)&msgbuf); 144 logsoftc.sc_state &= ~LOG_RDWAIT; 145 } 146 } 147 148 /*ARGSUSED*/ 149 logioctl(com, data, flag) 150 caddr_t data; 151 { 152 long l; 153 int s; 154 155 switch (com) { 156 157 /* return number of characters immediately available */ 158 case FIONREAD: 159 s = splhigh(); 160 l = msgbuf.msg_bufx - msgbuf.msg_bufr; 161 splx(s); 162 if (l < 0) 163 l += MSG_BSIZE; 164 *(off_t *)data = l; 165 break; 166 167 case FIONBIO: 168 if (*(int *)data) 169 logsoftc.sc_state |= LOG_NBIO; 170 else 171 logsoftc.sc_state &= ~LOG_NBIO; 172 break; 173 174 case FIOASYNC: 175 if (*(int *)data) 176 logsoftc.sc_state |= LOG_ASYNC; 177 else 178 logsoftc.sc_state &= ~LOG_ASYNC; 179 break; 180 181 case TIOCSPGRP: { 182 logsoftc.sc_pgid = *(int *)data; 183 break; 184 } 185 186 case TIOCGPGRP: 187 *(int *)data = logsoftc.sc_pgid; 188 break; 189 190 default: 191 return (-1); 192 } 193 return (0); 194 } 195