FreeBSD/Linux Kernel Cross Reference
sys/kern/subr_log.c
1 /* $OpenBSD: subr_log.c,v 1.75 2022/07/02 08:50:42 visa Exp $ */
2 /* $NetBSD: subr_log.c,v 1.11 1996/03/30 22:24:44 christos Exp $ */
3
4 /*
5 * Copyright (c) 1982, 1986, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * @(#)subr_log.c 8.1 (Berkeley) 6/10/93
33 */
34
35 /*
36 * Error log buffer for kernel printf's.
37 */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/proc.h>
42 #include <sys/vnode.h>
43 #include <sys/ioctl.h>
44 #include <sys/msgbuf.h>
45 #include <sys/file.h>
46 #include <sys/tty.h>
47 #include <sys/signalvar.h>
48 #include <sys/syslog.h>
49 #include <sys/malloc.h>
50 #include <sys/filedesc.h>
51 #include <sys/socket.h>
52 #include <sys/socketvar.h>
53 #include <sys/fcntl.h>
54 #include <sys/mutex.h>
55 #include <sys/timeout.h>
56
57 #ifdef KTRACE
58 #include <sys/ktrace.h>
59 #endif
60
61 #include <sys/mount.h>
62 #include <sys/syscallargs.h>
63
64 #include <dev/cons.h>
65
66 #define LOG_RDPRI (PZERO + 1)
67 #define LOG_TICK 50 /* log tick interval in msec */
68
69 #define LOG_ASYNC 0x04
70 #define LOG_RDWAIT 0x08
71
72 /*
73 * Locking:
74 * L log_mtx
75 */
76 struct logsoftc {
77 int sc_state; /* [L] see above for possibilities */
78 struct selinfo sc_selp; /* process waiting on select call */
79 struct sigio_ref sc_sigio; /* async I/O registration */
80 int sc_need_wakeup; /* if set, wake up waiters */
81 struct timeout sc_tick; /* wakeup poll timeout */
82 } logsoftc;
83
84 int log_open; /* also used in log() */
85 int msgbufmapped; /* is the message buffer mapped */
86 struct msgbuf *msgbufp; /* the mapped buffer, itself. */
87 struct msgbuf *consbufp; /* console message buffer. */
88
89 struct file *syslogf;
90 struct rwlock syslogf_rwlock = RWLOCK_INITIALIZER("syslogf");
91
92 /*
93 * Lock that serializes access to log message buffers.
94 * This should be kept as a leaf lock in order not to constrain where
95 * printf(9) can be used.
96 */
97 struct mutex log_mtx =
98 MUTEX_INITIALIZER_FLAGS(IPL_HIGH, "logmtx", MTX_NOWITNESS);
99
100 void filt_logrdetach(struct knote *kn);
101 int filt_logread(struct knote *kn, long hint);
102
103 const struct filterops logread_filtops = {
104 .f_flags = FILTEROP_ISFD,
105 .f_attach = NULL,
106 .f_detach = filt_logrdetach,
107 .f_event = filt_logread,
108 };
109
110 int dosendsyslog(struct proc *, const char *, size_t, int, enum uio_seg);
111 void logtick(void *);
112 size_t msgbuf_getlen(struct msgbuf *);
113 void msgbuf_putchar_locked(struct msgbuf *, const char);
114
115 void
116 initmsgbuf(caddr_t buf, size_t bufsize)
117 {
118 struct msgbuf *mbp;
119 long new_bufs;
120
121 /* Sanity-check the given size. */
122 if (bufsize < sizeof(struct msgbuf))
123 return;
124
125 mbp = msgbufp = (struct msgbuf *)buf;
126
127 new_bufs = bufsize - offsetof(struct msgbuf, msg_bufc);
128 if ((mbp->msg_magic != MSG_MAGIC) || (mbp->msg_bufs != new_bufs) ||
129 (mbp->msg_bufr < 0) || (mbp->msg_bufr >= mbp->msg_bufs) ||
130 (mbp->msg_bufx < 0) || (mbp->msg_bufx >= mbp->msg_bufs)) {
131 /*
132 * If the buffer magic number is wrong, has changed
133 * size (which shouldn't happen often), or is
134 * internally inconsistent, initialize it.
135 */
136
137 memset(buf, 0, bufsize);
138 mbp->msg_magic = MSG_MAGIC;
139 mbp->msg_bufs = new_bufs;
140 }
141
142 /*
143 * Always start new buffer data on a new line.
144 * Avoid using log_mtx because mutexes do not work during early boot
145 * on some architectures.
146 */
147 if (mbp->msg_bufx > 0 && mbp->msg_bufc[mbp->msg_bufx - 1] != '\n')
148 msgbuf_putchar_locked(mbp, '\n');
149
150 /* mark it as ready for use. */
151 msgbufmapped = 1;
152 }
153
154 void
155 initconsbuf(void)
156 {
157 /* Set up a buffer to collect /dev/console output */
158 consbufp = malloc(CONSBUFSIZE, M_TTYS, M_WAITOK | M_ZERO);
159 consbufp->msg_magic = MSG_MAGIC;
160 consbufp->msg_bufs = CONSBUFSIZE - offsetof(struct msgbuf, msg_bufc);
161 }
162
163 void
164 msgbuf_putchar(struct msgbuf *mbp, const char c)
165 {
166 if (mbp->msg_magic != MSG_MAGIC)
167 /* Nothing we can do */
168 return;
169
170 mtx_enter(&log_mtx);
171 msgbuf_putchar_locked(mbp, c);
172 mtx_leave(&log_mtx);
173 }
174
175 void
176 msgbuf_putchar_locked(struct msgbuf *mbp, const char c)
177 {
178 mbp->msg_bufc[mbp->msg_bufx++] = c;
179 if (mbp->msg_bufx < 0 || mbp->msg_bufx >= mbp->msg_bufs)
180 mbp->msg_bufx = 0;
181 /* If the buffer is full, keep the most recent data. */
182 if (mbp->msg_bufr == mbp->msg_bufx) {
183 if (++mbp->msg_bufr >= mbp->msg_bufs)
184 mbp->msg_bufr = 0;
185 mbp->msg_bufd++;
186 }
187 }
188
189 size_t
190 msgbuf_getlen(struct msgbuf *mbp)
191 {
192 long len;
193
194 mtx_enter(&log_mtx);
195 len = mbp->msg_bufx - mbp->msg_bufr;
196 if (len < 0)
197 len += mbp->msg_bufs;
198 mtx_leave(&log_mtx);
199 return (len);
200 }
201
202 int
203 logopen(dev_t dev, int flags, int mode, struct proc *p)
204 {
205 if (log_open)
206 return (EBUSY);
207 log_open = 1;
208 sigio_init(&logsoftc.sc_sigio);
209 timeout_set(&logsoftc.sc_tick, logtick, NULL);
210 timeout_add_msec(&logsoftc.sc_tick, LOG_TICK);
211 return (0);
212 }
213
214 int
215 logclose(dev_t dev, int flag, int mode, struct proc *p)
216 {
217 struct file *fp;
218
219 rw_enter_write(&syslogf_rwlock);
220 fp = syslogf;
221 syslogf = NULL;
222 rw_exit(&syslogf_rwlock);
223
224 if (fp)
225 FRELE(fp, p);
226 log_open = 0;
227 timeout_del(&logsoftc.sc_tick);
228 logsoftc.sc_state = 0;
229 sigio_free(&logsoftc.sc_sigio);
230 return (0);
231 }
232
233 int
234 logread(dev_t dev, struct uio *uio, int flag)
235 {
236 struct sleep_state sls;
237 struct msgbuf *mbp = msgbufp;
238 size_t l, rpos;
239 int error = 0;
240
241 mtx_enter(&log_mtx);
242 while (mbp->msg_bufr == mbp->msg_bufx) {
243 if (flag & IO_NDELAY) {
244 error = EWOULDBLOCK;
245 goto out;
246 }
247 logsoftc.sc_state |= LOG_RDWAIT;
248 mtx_leave(&log_mtx);
249 /*
250 * Set up and enter sleep manually instead of using msleep()
251 * to keep log_mtx as a leaf lock.
252 */
253 sleep_setup(&sls, mbp, LOG_RDPRI | PCATCH, "klog", 0);
254 error = sleep_finish(&sls, logsoftc.sc_state & LOG_RDWAIT);
255 mtx_enter(&log_mtx);
256 if (error)
257 goto out;
258 }
259
260 if (mbp->msg_bufd > 0) {
261 char buf[64];
262 long ndropped;
263
264 ndropped = mbp->msg_bufd;
265 mtx_leave(&log_mtx);
266 l = snprintf(buf, sizeof(buf),
267 "<%d>klog: dropped %ld byte%s, message buffer full\n",
268 LOG_KERN|LOG_WARNING, ndropped,
269 ndropped == 1 ? "" : "s");
270 error = uiomove(buf, ulmin(l, sizeof(buf) - 1), uio);
271 mtx_enter(&log_mtx);
272 if (error)
273 goto out;
274 mbp->msg_bufd -= ndropped;
275 }
276
277 while (uio->uio_resid > 0) {
278 if (mbp->msg_bufx >= mbp->msg_bufr)
279 l = mbp->msg_bufx - mbp->msg_bufr;
280 else
281 l = mbp->msg_bufs - mbp->msg_bufr;
282 l = ulmin(l, uio->uio_resid);
283 if (l == 0)
284 break;
285 rpos = mbp->msg_bufr;
286 mtx_leave(&log_mtx);
287 /* Ignore that concurrent readers may consume the same data. */
288 error = uiomove(&mbp->msg_bufc[rpos], l, uio);
289 mtx_enter(&log_mtx);
290 if (error)
291 break;
292 mbp->msg_bufr += l;
293 if (mbp->msg_bufr < 0 || mbp->msg_bufr >= mbp->msg_bufs)
294 mbp->msg_bufr = 0;
295 }
296 out:
297 mtx_leave(&log_mtx);
298 return (error);
299 }
300
301 int
302 logkqfilter(dev_t dev, struct knote *kn)
303 {
304 struct klist *klist;
305 int s;
306
307 switch (kn->kn_filter) {
308 case EVFILT_READ:
309 klist = &logsoftc.sc_selp.si_note;
310 kn->kn_fop = &logread_filtops;
311 break;
312 default:
313 return (EINVAL);
314 }
315
316 kn->kn_hook = (void *)msgbufp;
317
318 s = splhigh();
319 klist_insert_locked(klist, kn);
320 splx(s);
321
322 return (0);
323 }
324
325 void
326 filt_logrdetach(struct knote *kn)
327 {
328 int s;
329
330 s = splhigh();
331 klist_remove_locked(&logsoftc.sc_selp.si_note, kn);
332 splx(s);
333 }
334
335 int
336 filt_logread(struct knote *kn, long hint)
337 {
338 struct msgbuf *mbp = kn->kn_hook;
339
340 kn->kn_data = msgbuf_getlen(mbp);
341 return (kn->kn_data != 0);
342 }
343
344 void
345 logwakeup(void)
346 {
347 /*
348 * The actual wakeup has to be deferred because logwakeup() can be
349 * called in very varied contexts.
350 * Keep the print routines usable in as many situations as possible
351 * by not using locking here.
352 */
353
354 /*
355 * Ensure that preceding stores become visible to other CPUs
356 * before the flag.
357 */
358 membar_producer();
359
360 logsoftc.sc_need_wakeup = 1;
361 }
362
363 void
364 logtick(void *arg)
365 {
366 int state;
367
368 if (!log_open)
369 return;
370
371 if (!logsoftc.sc_need_wakeup)
372 goto out;
373 logsoftc.sc_need_wakeup = 0;
374
375 /*
376 * sc_need_wakeup has to be cleared before handling the wakeup.
377 * Visiting log_mtx ensures the proper order.
378 */
379
380 mtx_enter(&log_mtx);
381 state = logsoftc.sc_state;
382 if (logsoftc.sc_state & LOG_RDWAIT)
383 logsoftc.sc_state &= ~LOG_RDWAIT;
384 mtx_leave(&log_mtx);
385
386 selwakeup(&logsoftc.sc_selp);
387 if (state & LOG_ASYNC)
388 pgsigio(&logsoftc.sc_sigio, SIGIO, 0);
389 if (state & LOG_RDWAIT)
390 wakeup(msgbufp);
391 out:
392 timeout_add_msec(&logsoftc.sc_tick, LOG_TICK);
393 }
394
395 int
396 logioctl(dev_t dev, u_long com, caddr_t data, int flag, struct proc *p)
397 {
398 struct file *fp, *newfp;
399 int error;
400
401 switch (com) {
402
403 /* return number of characters immediately available */
404 case FIONREAD:
405 *(int *)data = (int)msgbuf_getlen(msgbufp);
406 break;
407
408 case FIONBIO:
409 break;
410
411 case FIOASYNC:
412 mtx_enter(&log_mtx);
413 if (*(int *)data)
414 logsoftc.sc_state |= LOG_ASYNC;
415 else
416 logsoftc.sc_state &= ~LOG_ASYNC;
417 mtx_leave(&log_mtx);
418 break;
419
420 case FIOSETOWN:
421 case TIOCSPGRP:
422 return (sigio_setown(&logsoftc.sc_sigio, com, data));
423
424 case FIOGETOWN:
425 case TIOCGPGRP:
426 sigio_getown(&logsoftc.sc_sigio, com, data);
427 break;
428
429 case LIOCSFD:
430 if ((error = suser(p)) != 0)
431 return (error);
432 if ((error = getsock(p, *(int *)data, &newfp)) != 0)
433 return (error);
434
435 rw_enter_write(&syslogf_rwlock);
436 fp = syslogf;
437 syslogf = newfp;
438 rw_exit(&syslogf_rwlock);
439
440 if (fp)
441 FRELE(fp, p);
442 break;
443
444 default:
445 return (ENOTTY);
446 }
447 return (0);
448 }
449
450 /*
451 * If syslogd is not running, temporarily store a limited amount of messages
452 * in kernel. After log stash is full, drop messages and count them. When
453 * syslogd is available again, next log message will flush the stashed
454 * messages and insert a message with drop count. Calls to malloc(9) and
455 * copyin(9) may sleep, protect data structures with rwlock.
456 */
457
458 #define LOGSTASH_SIZE 100
459 struct logstash_message {
460 char *lgs_buffer;
461 size_t lgs_size;
462 } logstash_messages[LOGSTASH_SIZE];
463
464 struct logstash_message *logstash_in = &logstash_messages[0];
465 struct logstash_message *logstash_out = &logstash_messages[0];
466
467 struct rwlock logstash_rwlock = RWLOCK_INITIALIZER("logstash");
468
469 int logstash_dropped, logstash_error, logstash_pid;
470
471 int logstash_insert(const char *, size_t, int, pid_t);
472 void logstash_remove(void);
473 int logstash_sendsyslog(struct proc *);
474
475 static inline int
476 logstash_full(void)
477 {
478 rw_assert_anylock(&logstash_rwlock);
479
480 return logstash_out->lgs_buffer != NULL &&
481 logstash_in == logstash_out;
482 }
483
484 static inline void
485 logstash_increment(struct logstash_message **msg)
486 {
487 rw_assert_wrlock(&logstash_rwlock);
488
489 KASSERT((*msg) >= &logstash_messages[0]);
490 KASSERT((*msg) < &logstash_messages[LOGSTASH_SIZE]);
491 if ((*msg) == &logstash_messages[LOGSTASH_SIZE - 1])
492 (*msg) = &logstash_messages[0];
493 else
494 (*msg)++;
495 }
496
497 int
498 logstash_insert(const char *buf, size_t nbyte, int logerror, pid_t pid)
499 {
500 int error;
501
502 rw_enter_write(&logstash_rwlock);
503
504 if (logstash_full()) {
505 if (logstash_dropped == 0) {
506 logstash_error = logerror;
507 logstash_pid = pid;
508 }
509 logstash_dropped++;
510
511 rw_exit(&logstash_rwlock);
512 return (0);
513 }
514
515 logstash_in->lgs_buffer = malloc(nbyte, M_LOG, M_WAITOK);
516 error = copyin(buf, logstash_in->lgs_buffer, nbyte);
517 if (error) {
518 free(logstash_in->lgs_buffer, M_LOG, nbyte);
519 logstash_in->lgs_buffer = NULL;
520
521 rw_exit(&logstash_rwlock);
522 return (error);
523 }
524 logstash_in->lgs_size = nbyte;
525 logstash_increment(&logstash_in);
526
527 rw_exit(&logstash_rwlock);
528 return (0);
529 }
530
531 void
532 logstash_remove(void)
533 {
534 rw_assert_wrlock(&logstash_rwlock);
535
536 KASSERT(logstash_out->lgs_buffer != NULL);
537 free(logstash_out->lgs_buffer, M_LOG, logstash_out->lgs_size);
538 logstash_out->lgs_buffer = NULL;
539 logstash_increment(&logstash_out);
540
541 /* Insert dropped message in sequence where messages were dropped. */
542 if (logstash_dropped) {
543 size_t l, nbyte;
544 char buf[80];
545
546 l = snprintf(buf, sizeof(buf),
547 "<%d>sendsyslog: dropped %d message%s, error %d, pid %d",
548 LOG_KERN|LOG_WARNING, logstash_dropped,
549 logstash_dropped == 1 ? "" : "s",
550 logstash_error, logstash_pid);
551 logstash_dropped = 0;
552 logstash_error = 0;
553 logstash_pid = 0;
554
555 /* Cannot fail, we have just freed a slot. */
556 KASSERT(!logstash_full());
557 nbyte = ulmin(l, sizeof(buf) - 1);
558 logstash_in->lgs_buffer = malloc(nbyte, M_LOG, M_WAITOK);
559 memcpy(logstash_in->lgs_buffer, buf, nbyte);
560 logstash_in->lgs_size = nbyte;
561 logstash_increment(&logstash_in);
562 }
563 }
564
565 int
566 logstash_sendsyslog(struct proc *p)
567 {
568 int error;
569
570 rw_enter_write(&logstash_rwlock);
571
572 while (logstash_out->lgs_buffer != NULL) {
573 error = dosendsyslog(p, logstash_out->lgs_buffer,
574 logstash_out->lgs_size, 0, UIO_SYSSPACE);
575 if (error) {
576 rw_exit(&logstash_rwlock);
577 return (error);
578 }
579 logstash_remove();
580 }
581
582 rw_exit(&logstash_rwlock);
583 return (0);
584 }
585
586 /*
587 * Send syslog(3) message from userland to socketpair(2) created by syslogd(8).
588 * Store message in kernel log stash for later if syslogd(8) is not available
589 * or sending fails. Send to console if LOG_CONS is set and syslogd(8) socket
590 * does not exist.
591 */
592
593 int
594 sys_sendsyslog(struct proc *p, void *v, register_t *retval)
595 {
596 struct sys_sendsyslog_args /* {
597 syscallarg(const char *) buf;
598 syscallarg(size_t) nbyte;
599 syscallarg(int) flags;
600 } */ *uap = v;
601 size_t nbyte;
602 int error;
603
604 nbyte = SCARG(uap, nbyte);
605 if (nbyte > LOG_MAXLINE)
606 nbyte = LOG_MAXLINE;
607
608 logstash_sendsyslog(p);
609 error = dosendsyslog(p, SCARG(uap, buf), nbyte, SCARG(uap, flags),
610 UIO_USERSPACE);
611 if (error && error != EFAULT)
612 logstash_insert(SCARG(uap, buf), nbyte, error, p->p_p->ps_pid);
613 return (error);
614 }
615
616 int
617 dosendsyslog(struct proc *p, const char *buf, size_t nbyte, int flags,
618 enum uio_seg sflg)
619 {
620 #ifdef KTRACE
621 struct iovec ktriov;
622 #endif
623 struct file *fp;
624 char pri[6], *kbuf;
625 struct iovec aiov;
626 struct uio auio;
627 size_t i, len;
628 int error;
629
630 /* Global variable syslogf may change during sleep, use local copy. */
631 rw_enter_read(&syslogf_rwlock);
632 fp = syslogf;
633 if (fp)
634 FREF(fp);
635 rw_exit(&syslogf_rwlock);
636
637 if (fp == NULL) {
638 if (!ISSET(flags, LOG_CONS))
639 return (ENOTCONN);
640 /*
641 * Strip off syslog priority when logging to console.
642 * LOG_PRIMASK | LOG_FACMASK is 0x03ff, so at most 4
643 * decimal digits may appear in priority as <1023>.
644 */
645 len = MIN(nbyte, sizeof(pri));
646 if (sflg == UIO_USERSPACE) {
647 if ((error = copyin(buf, pri, len)))
648 return (error);
649 } else
650 memcpy(pri, buf, len);
651 if (0 < len && pri[0] == '<') {
652 for (i = 1; i < len; i++) {
653 if (pri[i] < '' || pri[i] > '9')
654 break;
655 }
656 if (i < len && pri[i] == '>') {
657 i++;
658 /* There must be at least one digit <0>. */
659 if (i >= 3) {
660 buf += i;
661 nbyte -= i;
662 }
663 }
664 }
665 }
666
667 aiov.iov_base = (char *)buf;
668 aiov.iov_len = nbyte;
669 auio.uio_iov = &aiov;
670 auio.uio_iovcnt = 1;
671 auio.uio_segflg = sflg;
672 auio.uio_rw = UIO_WRITE;
673 auio.uio_procp = p;
674 auio.uio_offset = 0;
675 auio.uio_resid = aiov.iov_len;
676 #ifdef KTRACE
677 if (sflg == UIO_USERSPACE && KTRPOINT(p, KTR_GENIO))
678 ktriov = aiov;
679 else
680 ktriov.iov_len = 0;
681 #endif
682
683 len = auio.uio_resid;
684 if (fp) {
685 int flags = (fp->f_flag & FNONBLOCK) ? MSG_DONTWAIT : 0;
686 error = sosend(fp->f_data, NULL, &auio, NULL, NULL, flags);
687 if (error == 0)
688 len -= auio.uio_resid;
689 } else {
690 KERNEL_LOCK();
691 if (constty || cn_devvp) {
692 error = cnwrite(0, &auio, 0);
693 if (error == 0)
694 len -= auio.uio_resid;
695 aiov.iov_base = "\r\n";
696 aiov.iov_len = 2;
697 auio.uio_iov = &aiov;
698 auio.uio_iovcnt = 1;
699 auio.uio_segflg = UIO_SYSSPACE;
700 auio.uio_rw = UIO_WRITE;
701 auio.uio_procp = p;
702 auio.uio_offset = 0;
703 auio.uio_resid = aiov.iov_len;
704 cnwrite(0, &auio, 0);
705 } else {
706 /* XXX console redirection breaks down... */
707 if (sflg == UIO_USERSPACE) {
708 kbuf = malloc(len, M_TEMP, M_WAITOK);
709 error = copyin(aiov.iov_base, kbuf, len);
710 } else {
711 kbuf = aiov.iov_base;
712 error = 0;
713 }
714 if (error == 0)
715 for (i = 0; i < len; i++) {
716 if (kbuf[i] == '\0')
717 break;
718 cnputc(kbuf[i]);
719 auio.uio_resid--;
720 }
721 if (sflg == UIO_USERSPACE)
722 free(kbuf, M_TEMP, len);
723 if (error == 0)
724 len -= auio.uio_resid;
725 cnputc('\n');
726 }
727 KERNEL_UNLOCK();
728 }
729
730 #ifdef KTRACE
731 if (error == 0 && ktriov.iov_len != 0)
732 ktrgenio(p, -1, UIO_WRITE, &ktriov, len);
733 #endif
734 if (fp)
735 FRELE(fp, p);
736 else if (error != EFAULT)
737 error = ENOTCONN;
738 return (error);
739 }
Cache object: 4d35c5c291a79b5ed71e6baec17ab676
|