19454b2d8SWarner Losh /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 38a36da99SPedro F. Giffuni * 44784a469SIan Dowse * Copyright (c) 2003 Ian Dowse. All rights reserved. 54784a469SIan Dowse * 64784a469SIan Dowse * Redistribution and use in source and binary forms, with or without 74784a469SIan Dowse * modification, are permitted provided that the following conditions 84784a469SIan Dowse * are met: 94784a469SIan Dowse * 1. Redistributions of source code must retain the above copyright 104784a469SIan Dowse * notice, this list of conditions and the following disclaimer. 114784a469SIan Dowse * 2. Redistributions in binary form must reproduce the above copyright 124784a469SIan Dowse * notice, this list of conditions and the following disclaimer in the 134784a469SIan Dowse * documentation and/or other materials provided with the distribution. 144784a469SIan Dowse * 154784a469SIan Dowse * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 164784a469SIan Dowse * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 174784a469SIan Dowse * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 184784a469SIan Dowse * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 194784a469SIan Dowse * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 204784a469SIan Dowse * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 214784a469SIan Dowse * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 224784a469SIan Dowse * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 234784a469SIan Dowse * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 244784a469SIan Dowse * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 254784a469SIan Dowse * SUCH DAMAGE. 264784a469SIan Dowse * 274784a469SIan Dowse * $FreeBSD$ 284784a469SIan Dowse */ 294784a469SIan Dowse 304784a469SIan Dowse /* 314784a469SIan Dowse * Generic message buffer support routines. 324784a469SIan Dowse */ 334784a469SIan Dowse 344784a469SIan Dowse #include <sys/param.h> 354784a469SIan Dowse #include <sys/systm.h> 36d42a4eb5SKenneth D. Merry #include <sys/lock.h> 37f17a6f1bSEitan Adler #include <sys/kernel.h> 38d42a4eb5SKenneth D. Merry #include <sys/mutex.h> 394784a469SIan Dowse #include <sys/msgbuf.h> 40f17a6f1bSEitan Adler #include <sys/sysctl.h> 414784a469SIan Dowse 42d42a4eb5SKenneth D. Merry /* 43d42a4eb5SKenneth D. Merry * Maximum number conversion buffer length: uintmax_t in base 2, plus <> 44d42a4eb5SKenneth D. Merry * around the priority, and a terminating NUL. 45d42a4eb5SKenneth D. Merry */ 46d42a4eb5SKenneth D. Merry #define MAXPRIBUF (sizeof(intmax_t) * NBBY + 3) 47d42a4eb5SKenneth D. Merry 484784a469SIan Dowse /* Read/write sequence numbers are modulo a multiple of the buffer size. */ 494784a469SIan Dowse #define SEQMOD(size) ((size) * 16) 504784a469SIan Dowse 514784a469SIan Dowse static u_int msgbuf_cksum(struct msgbuf *mbp); 524784a469SIan Dowse 534784a469SIan Dowse /* 5424c10828SEitan Adler * Timestamps in msgbuf are useful when trying to diagnose when core dumps 55e3043798SPedro F. Giffuni * or other actions occurred. 56f17a6f1bSEitan Adler */ 57f17a6f1bSEitan Adler static int msgbuf_show_timestamp = 0; 58af3b2549SHans Petter Selasky SYSCTL_INT(_kern, OID_AUTO, msgbuf_show_timestamp, CTLFLAG_RWTUN, 59f17a6f1bSEitan Adler &msgbuf_show_timestamp, 0, "Show timestamp in msgbuf"); 60f17a6f1bSEitan Adler 61f17a6f1bSEitan Adler /* 624784a469SIan Dowse * Initialize a message buffer of the specified size at the specified 634784a469SIan Dowse * location. This also zeros the buffer area. 644784a469SIan Dowse */ 654784a469SIan Dowse void 664784a469SIan Dowse msgbuf_init(struct msgbuf *mbp, void *ptr, int size) 674784a469SIan Dowse { 684784a469SIan Dowse 694784a469SIan Dowse mbp->msg_ptr = ptr; 704784a469SIan Dowse mbp->msg_size = size; 714784a469SIan Dowse mbp->msg_seqmod = SEQMOD(size); 72d42a4eb5SKenneth D. Merry mbp->msg_lastpri = -1; 73f17a6f1bSEitan Adler mbp->msg_flags = 0; 7481dc0033SAlexander Motin msgbuf_clear(mbp); 7581dc0033SAlexander Motin mbp->msg_magic = MSG_MAGIC; 76534917efSKenneth D. Merry bzero(&mbp->msg_lock, sizeof(mbp->msg_lock)); 77d42a4eb5SKenneth D. Merry mtx_init(&mbp->msg_lock, "msgbuf", NULL, MTX_SPIN); 784784a469SIan Dowse } 794784a469SIan Dowse 804784a469SIan Dowse /* 814784a469SIan Dowse * Reinitialize a message buffer, retaining its previous contents if 824784a469SIan Dowse * the size and checksum are correct. If the old contents cannot be 834784a469SIan Dowse * recovered, the message buffer is cleared. 844784a469SIan Dowse */ 854784a469SIan Dowse void 864784a469SIan Dowse msgbuf_reinit(struct msgbuf *mbp, void *ptr, int size) 874784a469SIan Dowse { 884784a469SIan Dowse u_int cksum; 894784a469SIan Dowse 904784a469SIan Dowse if (mbp->msg_magic != MSG_MAGIC || mbp->msg_size != size) { 914784a469SIan Dowse msgbuf_init(mbp, ptr, size); 924784a469SIan Dowse return; 934784a469SIan Dowse } 944784a469SIan Dowse mbp->msg_seqmod = SEQMOD(size); 954784a469SIan Dowse mbp->msg_wseq = MSGBUF_SEQNORM(mbp, mbp->msg_wseq); 964784a469SIan Dowse mbp->msg_rseq = MSGBUF_SEQNORM(mbp, mbp->msg_rseq); 974784a469SIan Dowse mbp->msg_ptr = ptr; 984784a469SIan Dowse cksum = msgbuf_cksum(mbp); 994784a469SIan Dowse if (cksum != mbp->msg_cksum) { 100ce914a08SPoul-Henning Kamp if (bootverbose) { 1014784a469SIan Dowse printf("msgbuf cksum mismatch (read %x, calc %x)\n", 1024784a469SIan Dowse mbp->msg_cksum, cksum); 103ce914a08SPoul-Henning Kamp printf("Old msgbuf not recovered\n"); 104ce914a08SPoul-Henning Kamp } 1054784a469SIan Dowse msgbuf_clear(mbp); 1064784a469SIan Dowse } 107d42a4eb5SKenneth D. Merry 108d42a4eb5SKenneth D. Merry mbp->msg_lastpri = -1; 109d42a4eb5SKenneth D. Merry /* Assume that the old message buffer didn't end in a newline. */ 110f17a6f1bSEitan Adler mbp->msg_flags |= MSGBUF_NEEDNL; 111534917efSKenneth D. Merry bzero(&mbp->msg_lock, sizeof(mbp->msg_lock)); 112d42a4eb5SKenneth D. Merry mtx_init(&mbp->msg_lock, "msgbuf", NULL, MTX_SPIN); 1134784a469SIan Dowse } 1144784a469SIan Dowse 1154784a469SIan Dowse /* 1164784a469SIan Dowse * Clear the message buffer. 1174784a469SIan Dowse */ 1184784a469SIan Dowse void 1194784a469SIan Dowse msgbuf_clear(struct msgbuf *mbp) 1204784a469SIan Dowse { 1214784a469SIan Dowse 1224784a469SIan Dowse bzero(mbp->msg_ptr, mbp->msg_size); 1234784a469SIan Dowse mbp->msg_wseq = 0; 1244784a469SIan Dowse mbp->msg_rseq = 0; 1254784a469SIan Dowse mbp->msg_cksum = 0; 12681dc0033SAlexander Motin mbp->msg_flags &= ~MSGBUF_WRAP; 1274784a469SIan Dowse } 1284784a469SIan Dowse 1294784a469SIan Dowse /* 1304784a469SIan Dowse * Get a count of the number of unread characters in the message buffer. 1314784a469SIan Dowse */ 1324784a469SIan Dowse int 1334784a469SIan Dowse msgbuf_getcount(struct msgbuf *mbp) 1344784a469SIan Dowse { 1354784a469SIan Dowse u_int len; 1364784a469SIan Dowse 1374784a469SIan Dowse len = MSGBUF_SEQSUB(mbp, mbp->msg_wseq, mbp->msg_rseq); 1384784a469SIan Dowse if (len > mbp->msg_size) 1394784a469SIan Dowse len = mbp->msg_size; 1404784a469SIan Dowse return (len); 1414784a469SIan Dowse } 1424784a469SIan Dowse 1434784a469SIan Dowse /* 144d42a4eb5SKenneth D. Merry * Add a character into the message buffer, and update the checksum and 145d42a4eb5SKenneth D. Merry * sequence number. 146d42a4eb5SKenneth D. Merry * 147d42a4eb5SKenneth D. Merry * The caller should hold the message buffer spinlock. 148d42a4eb5SKenneth D. Merry */ 14924c10828SEitan Adler static void 15081dc0033SAlexander Motin msgbuf_do_addchar(struct msgbuf * const mbp, const int c) 151d42a4eb5SKenneth D. Merry { 152d42a4eb5SKenneth D. Merry u_int pos; 153d42a4eb5SKenneth D. Merry 154d42a4eb5SKenneth D. Merry /* Make sure we properly wrap the sequence number. */ 15581dc0033SAlexander Motin pos = MSGBUF_SEQ_TO_POS(mbp, mbp->msg_wseq); 15624c10828SEitan Adler mbp->msg_cksum += (u_int)(u_char)c - 157d42a4eb5SKenneth D. Merry (u_int)(u_char)mbp->msg_ptr[pos]; 158d42a4eb5SKenneth D. Merry mbp->msg_ptr[pos] = c; 15981dc0033SAlexander Motin mbp->msg_wseq = MSGBUF_SEQADD(mbp, mbp->msg_wseq, 1); 160d42a4eb5SKenneth D. Merry } 161d42a4eb5SKenneth D. Merry 162d42a4eb5SKenneth D. Merry /* 163d42a4eb5SKenneth D. Merry * Append a character to a message buffer. 1644784a469SIan Dowse */ 1654784a469SIan Dowse void 1664784a469SIan Dowse msgbuf_addchar(struct msgbuf *mbp, int c) 1674784a469SIan Dowse { 168d42a4eb5SKenneth D. Merry mtx_lock_spin(&mbp->msg_lock); 1694784a469SIan Dowse 17081dc0033SAlexander Motin msgbuf_do_addchar(mbp, c); 17181dc0033SAlexander Motin if (mbp->msg_wseq >= mbp->msg_size) 17281dc0033SAlexander Motin mbp->msg_flags |= MSGBUF_WRAP; 173d42a4eb5SKenneth D. Merry 174d42a4eb5SKenneth D. Merry mtx_unlock_spin(&mbp->msg_lock); 175d42a4eb5SKenneth D. Merry } 176d42a4eb5SKenneth D. Merry 177d42a4eb5SKenneth D. Merry /* 178d42a4eb5SKenneth D. Merry * Append a NUL-terminated string with a priority to a message buffer. 179d42a4eb5SKenneth D. Merry * Filter carriage returns if the caller requests it. 180d42a4eb5SKenneth D. Merry * 181d42a4eb5SKenneth D. Merry * XXX The carriage return filtering behavior is present in the 182d42a4eb5SKenneth D. Merry * msglogchar() API, however testing has shown that we don't seem to send 183d42a4eb5SKenneth D. Merry * carriage returns down this path. So do we still need it? 184d42a4eb5SKenneth D. Merry */ 185d42a4eb5SKenneth D. Merry void 18621aa6e83SKyle Evans msgbuf_addstr(struct msgbuf *mbp, int pri, const char *str, int filter_cr) 187d42a4eb5SKenneth D. Merry { 188d42a4eb5SKenneth D. Merry size_t len, prefix_len; 189d42a4eb5SKenneth D. Merry char prefix[MAXPRIBUF]; 19024c10828SEitan Adler char buf[32]; 191151ba793SAlexander Kabaev int i, j, needtime; 192d42a4eb5SKenneth D. Merry 193d42a4eb5SKenneth D. Merry len = strlen(str); 194d42a4eb5SKenneth D. Merry prefix_len = 0; 195d42a4eb5SKenneth D. Merry 196d42a4eb5SKenneth D. Merry /* If we have a zero-length string, no need to do anything. */ 197d42a4eb5SKenneth D. Merry if (len == 0) 198d42a4eb5SKenneth D. Merry return; 199d42a4eb5SKenneth D. Merry 200d42a4eb5SKenneth D. Merry mtx_lock_spin(&mbp->msg_lock); 201d42a4eb5SKenneth D. Merry 202d42a4eb5SKenneth D. Merry /* 203d42a4eb5SKenneth D. Merry * If this is true, we may need to insert a new priority sequence, 204d42a4eb5SKenneth D. Merry * so prepare the prefix. 205d42a4eb5SKenneth D. Merry */ 206d42a4eb5SKenneth D. Merry if (pri != -1) 207d42a4eb5SKenneth D. Merry prefix_len = sprintf(prefix, "<%d>", pri); 208d42a4eb5SKenneth D. Merry 209d42a4eb5SKenneth D. Merry /* 210d42a4eb5SKenneth D. Merry * Whenever there is a change in priority, we have to insert a 211d42a4eb5SKenneth D. Merry * newline, and a priority prefix if the priority is not -1. Here 212d42a4eb5SKenneth D. Merry * we detect whether there was a priority change, and whether we 213d42a4eb5SKenneth D. Merry * did not end with a newline. If that is the case, we need to 214d42a4eb5SKenneth D. Merry * insert a newline before this string. 215d42a4eb5SKenneth D. Merry */ 216f17a6f1bSEitan Adler if (mbp->msg_lastpri != pri && (mbp->msg_flags & MSGBUF_NEEDNL) != 0) { 21781dc0033SAlexander Motin msgbuf_do_addchar(mbp, '\n'); 218f17a6f1bSEitan Adler mbp->msg_flags &= ~MSGBUF_NEEDNL; 219d42a4eb5SKenneth D. Merry } 220d42a4eb5SKenneth D. Merry 22124c10828SEitan Adler needtime = 1; 222d42a4eb5SKenneth D. Merry for (i = 0; i < len; i++) { 223d42a4eb5SKenneth D. Merry /* 224d42a4eb5SKenneth D. Merry * If we just had a newline, and the priority is not -1 225d42a4eb5SKenneth D. Merry * (and therefore prefix_len != 0), then we need a priority 226d42a4eb5SKenneth D. Merry * prefix for this line. 227d42a4eb5SKenneth D. Merry */ 228f17a6f1bSEitan Adler if ((mbp->msg_flags & MSGBUF_NEEDNL) == 0 && prefix_len != 0) { 229d42a4eb5SKenneth D. Merry int j; 230d42a4eb5SKenneth D. Merry 231d42a4eb5SKenneth D. Merry for (j = 0; j < prefix_len; j++) 23281dc0033SAlexander Motin msgbuf_do_addchar(mbp, prefix[j]); 233d42a4eb5SKenneth D. Merry } 234d42a4eb5SKenneth D. Merry 23524c10828SEitan Adler if (msgbuf_show_timestamp && needtime == 1 && 23624c10828SEitan Adler (mbp->msg_flags & MSGBUF_NEEDNL) == 0) { 23745ae223aSWarner Losh if (msgbuf_show_timestamp == 1) { 23824c10828SEitan Adler snprintf(buf, sizeof(buf), "[%jd] ", 23924c10828SEitan Adler (intmax_t)time_uptime); 24045ae223aSWarner Losh } else { 24145ae223aSWarner Losh struct timeval tv; 24245ae223aSWarner Losh 24345ae223aSWarner Losh microuptime(&tv); 24445ae223aSWarner Losh snprintf(buf, sizeof(buf), "[%jd.%06d] ", 24545ae223aSWarner Losh (intmax_t)tv.tv_sec, (int)tv.tv_usec); 24645ae223aSWarner Losh } 24724c10828SEitan Adler for (j = 0; buf[j] != '\0'; j++) 24881dc0033SAlexander Motin msgbuf_do_addchar(mbp, buf[j]); 24924c10828SEitan Adler needtime = 0; 25024c10828SEitan Adler } 25124c10828SEitan Adler 252d42a4eb5SKenneth D. Merry /* 253d42a4eb5SKenneth D. Merry * Don't copy carriage returns if the caller requested 254d42a4eb5SKenneth D. Merry * filtering. 255d42a4eb5SKenneth D. Merry * 256d42a4eb5SKenneth D. Merry * XXX This matches the behavior of msglogchar(), but is it 257d42a4eb5SKenneth D. Merry * necessary? Testing has shown that we don't seem to get 258d42a4eb5SKenneth D. Merry * carriage returns here. 259d42a4eb5SKenneth D. Merry */ 260d42a4eb5SKenneth D. Merry if ((filter_cr != 0) && (str[i] == '\r')) 261d42a4eb5SKenneth D. Merry continue; 262d42a4eb5SKenneth D. Merry 263d42a4eb5SKenneth D. Merry /* 264d42a4eb5SKenneth D. Merry * Clear this flag if we see a newline. This affects whether 265d42a4eb5SKenneth D. Merry * we need to insert a new prefix or insert a newline later. 266d42a4eb5SKenneth D. Merry */ 267d42a4eb5SKenneth D. Merry if (str[i] == '\n') 268f17a6f1bSEitan Adler mbp->msg_flags &= ~MSGBUF_NEEDNL; 269d42a4eb5SKenneth D. Merry else 270f17a6f1bSEitan Adler mbp->msg_flags |= MSGBUF_NEEDNL; 271d42a4eb5SKenneth D. Merry 27281dc0033SAlexander Motin msgbuf_do_addchar(mbp, str[i]); 273d42a4eb5SKenneth D. Merry } 27481dc0033SAlexander Motin if (mbp->msg_wseq >= mbp->msg_size) 27581dc0033SAlexander Motin mbp->msg_flags |= MSGBUF_WRAP; 276d42a4eb5SKenneth D. Merry 277d42a4eb5SKenneth D. Merry /* 278d42a4eb5SKenneth D. Merry * Set the last priority. 279d42a4eb5SKenneth D. Merry */ 280d42a4eb5SKenneth D. Merry mbp->msg_lastpri = pri; 281d42a4eb5SKenneth D. Merry 282d42a4eb5SKenneth D. Merry mtx_unlock_spin(&mbp->msg_lock); 283d42a4eb5SKenneth D. Merry 2844784a469SIan Dowse } 2854784a469SIan Dowse 2864784a469SIan Dowse /* 2874784a469SIan Dowse * Read and mark as read a character from a message buffer. 2884784a469SIan Dowse * Returns the character, or -1 if no characters are available. 2894784a469SIan Dowse */ 2904784a469SIan Dowse int 2914784a469SIan Dowse msgbuf_getchar(struct msgbuf *mbp) 2924784a469SIan Dowse { 2934784a469SIan Dowse u_int len, wseq; 2944784a469SIan Dowse int c; 2954784a469SIan Dowse 296d42a4eb5SKenneth D. Merry mtx_lock_spin(&mbp->msg_lock); 297d42a4eb5SKenneth D. Merry 2984784a469SIan Dowse wseq = mbp->msg_wseq; 2994784a469SIan Dowse len = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_rseq); 300d42a4eb5SKenneth D. Merry if (len == 0) { 301d42a4eb5SKenneth D. Merry mtx_unlock_spin(&mbp->msg_lock); 3024784a469SIan Dowse return (-1); 303d42a4eb5SKenneth D. Merry } 3044784a469SIan Dowse if (len > mbp->msg_size) 30581dc0033SAlexander Motin mbp->msg_rseq = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_size); 3064784a469SIan Dowse c = (u_char)mbp->msg_ptr[MSGBUF_SEQ_TO_POS(mbp, mbp->msg_rseq)]; 30781dc0033SAlexander Motin mbp->msg_rseq = MSGBUF_SEQADD(mbp, mbp->msg_rseq, 1); 308d42a4eb5SKenneth D. Merry 309d42a4eb5SKenneth D. Merry mtx_unlock_spin(&mbp->msg_lock); 310d42a4eb5SKenneth D. Merry 3114784a469SIan Dowse return (c); 3124784a469SIan Dowse } 3134784a469SIan Dowse 3144784a469SIan Dowse /* 3154784a469SIan Dowse * Read and mark as read a number of characters from a message buffer. 3164784a469SIan Dowse * Returns the number of characters that were placed in `buf'. 3174784a469SIan Dowse */ 3184784a469SIan Dowse int 3194784a469SIan Dowse msgbuf_getbytes(struct msgbuf *mbp, char *buf, int buflen) 3204784a469SIan Dowse { 3214784a469SIan Dowse u_int len, pos, wseq; 3224784a469SIan Dowse 323d42a4eb5SKenneth D. Merry mtx_lock_spin(&mbp->msg_lock); 324d42a4eb5SKenneth D. Merry 3254784a469SIan Dowse wseq = mbp->msg_wseq; 3264784a469SIan Dowse len = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_rseq); 327d42a4eb5SKenneth D. Merry if (len == 0) { 328d42a4eb5SKenneth D. Merry mtx_unlock_spin(&mbp->msg_lock); 3294784a469SIan Dowse return (0); 330d42a4eb5SKenneth D. Merry } 3314784a469SIan Dowse if (len > mbp->msg_size) { 33281dc0033SAlexander Motin mbp->msg_rseq = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_size); 3334784a469SIan Dowse len = mbp->msg_size; 3344784a469SIan Dowse } 3354784a469SIan Dowse pos = MSGBUF_SEQ_TO_POS(mbp, mbp->msg_rseq); 3364784a469SIan Dowse len = min(len, mbp->msg_size - pos); 3374784a469SIan Dowse len = min(len, (u_int)buflen); 3384784a469SIan Dowse 3394784a469SIan Dowse bcopy(&mbp->msg_ptr[pos], buf, len); 34081dc0033SAlexander Motin mbp->msg_rseq = MSGBUF_SEQADD(mbp, mbp->msg_rseq, len); 341d42a4eb5SKenneth D. Merry 342d42a4eb5SKenneth D. Merry mtx_unlock_spin(&mbp->msg_lock); 343d42a4eb5SKenneth D. Merry 3444784a469SIan Dowse return (len); 3454784a469SIan Dowse } 3464784a469SIan Dowse 3474784a469SIan Dowse /* 3484784a469SIan Dowse * Peek at the full contents of a message buffer without marking any 3494784a469SIan Dowse * data as read. `seqp' should point to an unsigned integer that 3504784a469SIan Dowse * msgbuf_peekbytes() can use to retain state between calls so that 3514784a469SIan Dowse * the whole message buffer can be read in multiple short reads. 3524784a469SIan Dowse * To initialise this variable to the start of the message buffer, 3534784a469SIan Dowse * call msgbuf_peekbytes() with a NULL `buf' parameter. 3544784a469SIan Dowse * 3554784a469SIan Dowse * Returns the number of characters that were placed in `buf'. 3564784a469SIan Dowse */ 3574784a469SIan Dowse int 3584784a469SIan Dowse msgbuf_peekbytes(struct msgbuf *mbp, char *buf, int buflen, u_int *seqp) 3594784a469SIan Dowse { 3604784a469SIan Dowse u_int len, pos, wseq; 3614784a469SIan Dowse 362d42a4eb5SKenneth D. Merry mtx_lock_spin(&mbp->msg_lock); 363d42a4eb5SKenneth D. Merry 3644784a469SIan Dowse if (buf == NULL) { 3654784a469SIan Dowse /* Just initialise *seqp. */ 36681dc0033SAlexander Motin if (mbp->msg_flags & MSGBUF_WRAP) 36781dc0033SAlexander Motin *seqp = MSGBUF_SEQSUB(mbp, mbp->msg_wseq, mbp->msg_size); 36881dc0033SAlexander Motin else 36981dc0033SAlexander Motin *seqp = 0; 370d42a4eb5SKenneth D. Merry mtx_unlock_spin(&mbp->msg_lock); 3714784a469SIan Dowse return (0); 3724784a469SIan Dowse } 3734784a469SIan Dowse 3744784a469SIan Dowse wseq = mbp->msg_wseq; 3754784a469SIan Dowse len = MSGBUF_SEQSUB(mbp, wseq, *seqp); 376d42a4eb5SKenneth D. Merry if (len == 0) { 377d42a4eb5SKenneth D. Merry mtx_unlock_spin(&mbp->msg_lock); 3784784a469SIan Dowse return (0); 379d42a4eb5SKenneth D. Merry } 3804784a469SIan Dowse if (len > mbp->msg_size) { 38181dc0033SAlexander Motin *seqp = MSGBUF_SEQSUB(mbp, wseq, mbp->msg_size); 3824784a469SIan Dowse len = mbp->msg_size; 3834784a469SIan Dowse } 3844784a469SIan Dowse pos = MSGBUF_SEQ_TO_POS(mbp, *seqp); 3854784a469SIan Dowse len = min(len, mbp->msg_size - pos); 3864784a469SIan Dowse len = min(len, (u_int)buflen); 3874784a469SIan Dowse bcopy(&mbp->msg_ptr[MSGBUF_SEQ_TO_POS(mbp, *seqp)], buf, len); 38881dc0033SAlexander Motin *seqp = MSGBUF_SEQADD(mbp, *seqp, len); 389d42a4eb5SKenneth D. Merry 390d42a4eb5SKenneth D. Merry mtx_unlock_spin(&mbp->msg_lock); 391d42a4eb5SKenneth D. Merry 3924784a469SIan Dowse return (len); 3934784a469SIan Dowse } 3944784a469SIan Dowse 3954784a469SIan Dowse /* 3964784a469SIan Dowse * Compute the checksum for the complete message buffer contents. 3974784a469SIan Dowse */ 3984784a469SIan Dowse static u_int 3994784a469SIan Dowse msgbuf_cksum(struct msgbuf *mbp) 4004784a469SIan Dowse { 4014784a469SIan Dowse u_int i, sum; 4024784a469SIan Dowse 4034784a469SIan Dowse sum = 0; 4044784a469SIan Dowse for (i = 0; i < mbp->msg_size; i++) 4054784a469SIan Dowse sum += (u_char)mbp->msg_ptr[i]; 4064784a469SIan Dowse return (sum); 4074784a469SIan Dowse } 4084784a469SIan Dowse 4094784a469SIan Dowse /* 4104784a469SIan Dowse * Copy from one message buffer to another. 4114784a469SIan Dowse */ 4124784a469SIan Dowse void 4134784a469SIan Dowse msgbuf_copy(struct msgbuf *src, struct msgbuf *dst) 4144784a469SIan Dowse { 4154784a469SIan Dowse int c; 4164784a469SIan Dowse 4174784a469SIan Dowse while ((c = msgbuf_getchar(src)) >= 0) 4184784a469SIan Dowse msgbuf_addchar(dst, c); 4194784a469SIan Dowse } 420588ab3c7SMitchell Horne 421588ab3c7SMitchell Horne /* 422588ab3c7SMitchell Horne * Get a snapshot of the message buffer, without modifying its internal state 423588ab3c7SMitchell Horne * (i.e. don't mark any new characters as read). 424588ab3c7SMitchell Horne */ 425588ab3c7SMitchell Horne void 426588ab3c7SMitchell Horne msgbuf_duplicate(struct msgbuf *src, struct msgbuf *dst, char *dst_msgptr) 427588ab3c7SMitchell Horne { 428588ab3c7SMitchell Horne 429588ab3c7SMitchell Horne mtx_lock_spin(&src->msg_lock); 430588ab3c7SMitchell Horne bcopy(src, dst, sizeof(struct msgbuf)); 431588ab3c7SMitchell Horne dst->msg_ptr = dst_msgptr; 432588ab3c7SMitchell Horne bcopy(src->msg_ptr, dst->msg_ptr, src->msg_size); 433588ab3c7SMitchell Horne mtx_unlock_spin(&src->msg_lock); 434588ab3c7SMitchell Horne } 435