FreeBSD kernel kern code
subr_log.c
Go to the documentation of this file.
1 /*-
2  * Copyright (c) 1982, 1986, 1993
3  * The Regents of the University of California. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * @(#)subr_log.c 8.1 (Berkeley) 6/10/93
30  */
31 
32 /*
33  * Error log buffer for kernel printf's.
34  */
35 
36 #include <sys/cdefs.h>
37 __FBSDID("$BSDSUniX$");
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/conf.h>
42 #include <sys/proc.h>
43 #include <sys/vnode.h>
44 #include <sys/filio.h>
45 #include <sys/ttycom.h>
46 #include <sys/msgbuf.h>
47 #include <sys/signalvar.h>
48 #include <sys/kernel.h>
49 #include <sys/poll.h>
50 #include <sys/filedesc.h>
51 #include <sys/sysctl.h>
52 
53 #define LOG_RDPRI (PZERO + 1)
54 
55 #define LOG_ASYNC 0x04
56 
57 static d_open_t logopen;
58 static d_close_t logclose;
59 static d_read_t logread;
60 static d_ioctl_t logioctl;
61 static d_poll_t logpoll;
62 static d_kqfilter_t logkqfilter;
63 
64 static void logtimeout(void *arg);
65 
66 static struct cdevsw log_cdevsw = {
67  .d_version = D_VERSION,
68  .d_open = logopen,
69  .d_close = logclose,
70  .d_read = logread,
71  .d_ioctl = logioctl,
72  .d_poll = logpoll,
73  .d_kqfilter = logkqfilter,
74  .d_name = "log",
75 };
76 
77 static int logkqread(struct knote *note, long hint);
78 static void logkqdetach(struct knote *note);
79 
80 static struct filterops log_read_filterops = {
81  .f_isfd = 1,
82  .f_attach = NULL,
83  .f_detach = logkqdetach,
84  .f_event = logkqread,
85 };
86 
87 static struct logsoftc {
88  int sc_state; /* see above for possibilities */
89  struct selinfo sc_selp; /* process waiting on select call */
90  struct sigio *sc_sigio; /* information for async I/O */
91  struct callout sc_callout; /* callout to wakeup syslog */
92 } logsoftc;
93 
94 int log_open; /* also used in log() */
95 static struct cv log_wakeup;
96 struct mtx msgbuf_lock;
97 MTX_SYSINIT(msgbuf_lock, &msgbuf_lock, "msgbuf lock", MTX_DEF);
98 
99 /* Times per second to check for a pending syslog wakeup. */
100 static int log_wakeups_per_second = 5;
101 SYSCTL_INT(_kern, OID_AUTO, log_wakeups_per_second, CTLFLAG_RW,
102  &log_wakeups_per_second, 0, "");
103 
104 /*ARGSUSED*/
105 static int
106 logopen(struct cdev *dev, int flags, int mode, struct thread *td)
107 {
108 
109  if (log_wakeups_per_second < 1) {
110  printf("syslog wakeup is less than one. Adjusting to 1.\n");
112  }
113 
114  mtx_lock(&msgbuf_lock);
115  if (log_open) {
116  mtx_unlock(&msgbuf_lock);
117  return (EBUSY);
118  }
119  log_open = 1;
120  callout_reset(&logsoftc.sc_callout, hz / log_wakeups_per_second,
121  logtimeout, NULL);
122  mtx_unlock(&msgbuf_lock);
123 
124  fsetown(td->td_proc->p_pid, &logsoftc.sc_sigio); /* signal process only */
125  return (0);
126 }
127 
128 /*ARGSUSED*/
129 static int
130 logclose(struct cdev *dev, int flag, int mode, struct thread *td)
131 {
132 
134 
135  mtx_lock(&msgbuf_lock);
136  callout_stop(&logsoftc.sc_callout);
137  logsoftc.sc_state = 0;
138  log_open = 0;
139  mtx_unlock(&msgbuf_lock);
140 
141  return (0);
142 }
143 
144 /*ARGSUSED*/
145 static int
146 logread(struct cdev *dev, struct uio *uio, int flag)
147 {
148  char buf[128];
149  struct msgbuf *mbp = msgbufp;
150  int error = 0, l;
151 
152  mtx_lock(&msgbuf_lock);
153  while (msgbuf_getcount(mbp) == 0) {
154  if (flag & IO_NDELAY) {
155  mtx_unlock(&msgbuf_lock);
156  return (EWOULDBLOCK);
157  }
158  if ((error = cv_wait_sig(&log_wakeup, &msgbuf_lock)) != 0) {
159  mtx_unlock(&msgbuf_lock);
160  return (error);
161  }
162  }
163 
164  while (uio->uio_resid > 0) {
165  l = imin(sizeof(buf), uio->uio_resid);
166  l = msgbuf_getbytes(mbp, buf, l);
167  if (l == 0)
168  break;
169  mtx_unlock(&msgbuf_lock);
170  error = uiomove(buf, l, uio);
171  if (error || uio->uio_resid == 0)
172  return (error);
173  mtx_lock(&msgbuf_lock);
174  }
175  mtx_unlock(&msgbuf_lock);
176  return (error);
177 }
178 
179 /*ARGSUSED*/
180 static int
181 logpoll(struct cdev *dev, int events, struct thread *td)
182 {
183  int revents = 0;
184 
185  if (events & (POLLIN | POLLRDNORM)) {
186  mtx_lock(&msgbuf_lock);
187  if (msgbuf_getcount(msgbufp) > 0)
188  revents |= events & (POLLIN | POLLRDNORM);
189  else
190  selrecord(td, &logsoftc.sc_selp);
191  mtx_unlock(&msgbuf_lock);
192  }
193  return (revents);
194 }
195 
196 static int
197 logkqfilter(struct cdev *dev, struct knote *kn)
198 {
199 
200  if (kn->kn_filter != EVFILT_READ)
201  return (EINVAL);
202 
203  kn->kn_fop = &log_read_filterops;
204  kn->kn_hook = NULL;
205 
206  mtx_lock(&msgbuf_lock);
207  knlist_add(&logsoftc.sc_selp.si_note, kn, 1);
208  mtx_unlock(&msgbuf_lock);
209  return (0);
210 }
211 
212 static int
213 logkqread(struct knote *kn, long hint)
214 {
215 
216  mtx_assert(&msgbuf_lock, MA_OWNED);
217  kn->kn_data = msgbuf_getcount(msgbufp);
218  return (kn->kn_data != 0);
219 }
220 
221 static void
222 logkqdetach(struct knote *kn)
223 {
224 
225  mtx_lock(&msgbuf_lock);
226  knlist_remove(&logsoftc.sc_selp.si_note, kn, 1);
227  mtx_unlock(&msgbuf_lock);
228 }
229 
230 static void
231 logtimeout(void *arg)
232 {
233 
234  if (!log_open)
235  return;
236  if (log_wakeups_per_second < 1) {
237  printf("syslog wakeup is less than one. Adjusting to 1.\n");
239  }
240  if (msgbuftrigger == 0) {
243  return;
244  }
245  msgbuftrigger = 0;
247  KNOTE_LOCKED(&logsoftc.sc_selp.si_note, 0);
248  if ((logsoftc.sc_state & LOG_ASYNC) && logsoftc.sc_sigio != NULL)
249  pgsigio(&logsoftc.sc_sigio, SIGIO, 0);
252 }
253 
254 /*ARGSUSED*/
255 static int
256 logioctl(struct cdev *dev, u_long com, caddr_t data, int flag, struct thread *td)
257 {
258 
259  switch (com) {
260 
261  /* return number of characters immediately available */
262  case FIONREAD:
263  *(int *)data = msgbuf_getcount(msgbufp);
264  break;
265 
266  case FIONBIO:
267  break;
268 
269  case FIOASYNC:
270  mtx_lock(&msgbuf_lock);
271  if (*(int *)data)
273  else
275  mtx_unlock(&msgbuf_lock);
276  break;
277 
278  case FIOSETOWN:
279  return (fsetown(*(int *)data, &logsoftc.sc_sigio));
280 
281  case FIOGETOWN:
282  *(int *)data = fgetown(&logsoftc.sc_sigio);
283  break;
284 
285  /* This is deprecated, FIOSETOWN should be used instead. */
286  case TIOCSPGRP:
287  return (fsetown(-(*(int *)data), &logsoftc.sc_sigio));
288 
289  /* This is deprecated, FIOGETOWN should be used instead */
290  case TIOCGPGRP:
291  *(int *)data = -fgetown(&logsoftc.sc_sigio);
292  break;
293 
294  default:
295  return (ENOTTY);
296  }
297  return (0);
298 }
299 
300 static void
301 log_drvinit(void *unused)
302 {
303 
304  cv_init(&log_wakeup, "klog");
305  callout_init_mtx(&logsoftc.sc_callout, &msgbuf_lock, 0);
307  make_dev_credf(MAKEDEV_ETERNAL, &log_cdevsw, 0, NULL, UID_ROOT,
308  GID_WHEEL, 0600, "klog");
309 }
310 
311 SYSINIT(logdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE,log_drvinit,NULL);
pid_t fgetown(struct sigio **sigiop)
int fsetown(pid_t pgid, struct sigio **sigiop)
static struct filterops log_read_filterops
Definition: subr_log.c:80
struct buf * buf
Definition: vfs_bio.c:97
#define LOG_RDPRI
Definition: subr_log.c:53
static d_read_t logread
Definition: subr_log.c:59
int mode
void selrecord(struct thread *selector, struct selinfo *sip)
Definition: sys_generic.c:1606
struct callout sc_callout
Definition: subr_log.c:91
struct sigio * sc_sigio
Definition: subr_log.c:90
void knote(struct knlist *list, long hint, int lockflags)
Definition: kern_event.c:1806
void selwakeuppri(struct selinfo *sip, int pri)
Definition: sys_generic.c:1664
struct cdev * make_dev_credf(int flags, struct cdevsw *devsw, int unit, struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt,...)
Definition: kern_conf.c:843
int callout_schedule(struct callout *c, int to_ticks)
Definition: kern_timeout.c:867
void funsetown(struct sigio **sigiop)
Definition: kern_descrip.c:990
__FBSDID("$BSDSUniX$")
SYSINIT(logdev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, log_drvinit, NULL)
static void logtimeout(void *arg)
Definition: subr_log.c:231
MTX_SYSINIT(msgbuf_lock,&msgbuf_lock,"msgbuf lock", MTX_DEF)
#define LOG_ASYNC
Definition: subr_log.c:55
void knlist_remove(struct knlist *knl, struct knote *kn, int islocked)
Definition: kern_event.c:1909
struct selinfo sc_selp
Definition: subr_log.c:89
static void log_drvinit(void *unused)
Definition: subr_log.c:301
void cv_broadcastpri(struct cv *cvp, int pri)
Definition: kern_condvar.c:434
int sc_state
Definition: subr_log.c:88
void knlist_add(struct knlist *knl, struct knote *kn, int islocked)
Definition: kern_event.c:1866
static d_ioctl_t logioctl
Definition: subr_log.c:60
struct mtx msgbuf_lock
Definition: subr_log.c:96
void cv_init(struct cv *cvp, const char *desc)
Definition: kern_condvar.c:63
static d_close_t logclose
Definition: subr_log.c:58
int uiomove(void *cp, int n, struct uio *uio)
Definition: subr_uio.c:202
static void logkqdetach(struct knote *note)
Definition: subr_log.c:222
int printf(const char *fmt,...)
Definition: subr_prf.c:367
static struct cv log_wakeup
Definition: subr_log.c:95
static int logkqread(struct knote *note, long hint)
Definition: subr_log.c:213
int msgbuftrigger
Definition: subr_prf.c:103
static d_open_t logopen
Definition: subr_log.c:57
int log_open
Definition: subr_log.c:94
int msgbuf_getcount(struct msgbuf *mbp)
Definition: subr_msgbuf.c:131
static int log_wakeups_per_second
Definition: subr_log.c:100
static d_poll_t logpoll
Definition: subr_log.c:61
SYSCTL_INT(_kern, OID_AUTO, log_wakeups_per_second, CTLFLAG_RW,&log_wakeups_per_second, 0,"")
static d_kqfilter_t logkqfilter
Definition: subr_log.c:62
void knlist_init_mtx(struct knlist *knl, struct mtx *lock)
Definition: kern_event.c:1995
int msgbuf_getbytes(struct msgbuf *mbp, char *buf, int buflen)
Definition: subr_msgbuf.c:321
int flag
void pgsigio(struct sigio **sigiop, int sig, int checkctty)
Definition: kern_sig.c:3372
static struct logsoftc logsoftc
int hz
Definition: subr_param.c:84
static struct cdevsw log_cdevsw
Definition: subr_log.c:66