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