Page MenuHomeFreeBSD

D49945.id154040.diff
No OneTemporary

D49945.id154040.diff

diff --git a/lib/libsbuf/Symbol.map b/lib/libsbuf/Symbol.map
--- a/lib/libsbuf/Symbol.map
+++ b/lib/libsbuf/Symbol.map
@@ -42,3 +42,7 @@
FBSD_1.6 {
sbuf_printf_drain;
};
+
+FBSD_1.8 {
+ sbuf_prepend;
+};
diff --git a/lib/libsbuf/tests/sbuf_string_test.c b/lib/libsbuf/tests/sbuf_string_test.c
--- a/lib/libsbuf/tests/sbuf_string_test.c
+++ b/lib/libsbuf/tests/sbuf_string_test.c
@@ -210,6 +210,54 @@
sbuf_delete(sb);
}
+ATF_TC_WITHOUT_HEAD(sbuf_prepend_test);
+ATF_TC_BODY(sbuf_prepend_test, tc)
+{
+ struct sbuf *sb;
+ size_t test_sbuf_len;
+ const char subsystem_part[] = "subsystem=kernel";
+ const char type_part[] = " type=none";
+ const char data_part[] = " data=foo";
+ const char full_string[] = "subsystem=kernel type=none data=foo";
+
+ sb = sbuf_new_auto();
+ ATF_REQUIRE_MSG(sb != NULL, "sbuf_new_auto failed: %s",
+ strerror(errno));
+
+ ATF_CHECK_MSG(sbuf_cpy(sb, data_part) == 0, "sbuf_cat failed");
+
+ test_sbuf_len = sbuf_len(sb);
+ ATF_REQUIRE_MSG(test_sbuf_len == (ssize_t)strlen(data_part),
+ "sbuf_len(..) => %zd (actual) != %zu (expected)", test_sbuf_len,
+ sizeof(data_part) - 1);
+
+ ATF_CHECK_MSG(sbuf_prepend(sb, type_part) == 0, "sbuf_prepend failed");
+
+ test_sbuf_len = sbuf_len(sb);
+ ATF_REQUIRE_MSG(test_sbuf_len == (ssize_t)(strlen(type_part) +
+ strlen(data_part)),
+ "sbuf_len(..) => %zd (actual) != %zu (expected)", test_sbuf_len,
+ sizeof(type_part) + sizeof(data_part) - 2);
+
+ ATF_CHECK_MSG(sbuf_prepend(sb, subsystem_part) == 0, "sbuf_prepend failed");
+
+ test_sbuf_len = sbuf_len(sb);
+ ATF_REQUIRE_MSG(test_sbuf_len == (ssize_t)(strlen(subsystem_part) +
+ strlen(type_part) + strlen(data_part)),
+ "sbuf_len(..) => %zd (actual) != %zu (expected)", test_sbuf_len,
+ sizeof(subsystem_part) + sizeof(type_part) + sizeof(data_part) - 3);
+
+ ATF_REQUIRE_MSG(sbuf_finish(sb) == 0, "sbuf_finish failed: %s",
+ strerror(errno));
+
+ ATF_REQUIRE_STREQ_MSG(sbuf_data(sb), full_string,
+ "sbuf (\"%s\") != test string (\"%s\")", sbuf_data(sb),
+ full_string);
+
+ sbuf_delete(sb);
+}
+
+
ATF_TC_WITHOUT_HEAD(sbuf_putc_test);
ATF_TC_BODY(sbuf_putc_test, tc)
{
@@ -282,6 +330,7 @@
ATF_TP_ADD_TC(tp, sbuf_bcpy_test);
ATF_TP_ADD_TC(tp, sbuf_cat_test);
ATF_TP_ADD_TC(tp, sbuf_cpy_test);
+ ATF_TP_ADD_TC(tp, sbuf_prepend_test);
ATF_TP_ADD_TC(tp, sbuf_putc_test);
ATF_TP_ADD_TC(tp, sbuf_trim_test);
diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile
--- a/share/man/man9/Makefile
+++ b/share/man/man9/Makefile
@@ -1984,6 +1984,7 @@
sbuf.9 sbuf_new_auto.9 \
sbuf.9 sbuf_new_for_sysctl.9 \
sbuf.9 sbuf_nl_terminate.9 \
+ sbuf.9 sbuf_prepend.9 \
sbuf.9 sbuf_printf.9 \
sbuf.9 sbuf_printf_drain.9 \
sbuf.9 sbuf_putbuf.9 \
diff --git a/share/man/man9/sbuf.9 b/share/man/man9/sbuf.9
--- a/share/man/man9/sbuf.9
+++ b/share/man/man9/sbuf.9
@@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd October 3, 2023
+.Dd April 21, 2025
.Dt SBUF 9
.Os
.Sh NAME
@@ -43,6 +43,7 @@
.Nm sbuf_copyin ,
.Nm sbuf_cpy ,
.Nm sbuf_nl_terminate ,
+.Nm sbuf_prepend ,
.Nm sbuf_printf ,
.Nm sbuf_vprintf ,
.Nm sbuf_putc ,
@@ -131,6 +132,11 @@
.Ft int
.Fn sbuf_nl_terminate "struct sbuf *"
.Ft int
+.Fo sbuf_prepend
+.Fa "struct sbuf *s"
+.Fa "const char *str"
+.Fc
+.Ft int
.Fo sbuf_printf
.Fa "struct sbuf *s"
.Fa "const char *fmt" "..."
@@ -405,6 +411,12 @@
to the
.Fa sbuf
at the current position.
+The
+.Fn sbuf_prepend
+function prepends the NUL-terminated string
+.Fa str
+to the beginning of the
+.Fa sbuf .
.Pp
The
.Fn sbuf_set_drain
diff --git a/sys/kern/subr_sbuf.c b/sys/kern/subr_sbuf.c
--- a/sys/kern/subr_sbuf.c
+++ b/sys/kern/subr_sbuf.c
@@ -432,6 +432,59 @@
return (0);
}
+/*
+ * Prepend bytes to an sbuf. This is the core function for appending
+ * to an sbuf and is the main place that deals with extending the
+ * buffer and marking overflow.
+ */
+static void
+sbuf_prepend_bytes(struct sbuf *s, const char *buf, size_t len)
+{
+ size_t n, pos;
+
+ assert_sbuf_integrity(s);
+ assert_sbuf_state(s, 0);
+
+ if (s->s_error != 0)
+ return;
+
+ /*
+ * We can't prepend to sbufs with a drain function or sections at the
+ * moment.
+ */
+ if (s->s_drain_func != NULL || SBUF_ISSECTION(s)) {
+ s->s_error = ENXIO;
+ return;
+ }
+
+ /*
+ * We'll maintain the loop that sbuf_put_bytes() does since we can only
+ * allocate up to INT_MAX at a time.
+ */
+ pos = 0;
+ while (len > 0) {
+ if (SBUF_FREESPACE(s) <= 0) {
+ if (sbuf_extend(s, len > INT_MAX ? INT_MAX : len) < 0) {
+ s->s_error = ENOMEM;
+ return;
+ }
+ }
+ n = SBUF_FREESPACE(s);
+ if (len < n)
+ n = len;
+
+ /* Move anything currently in the way forward */
+ memmove(&s->s_buf[n + pos], &s->s_buf[pos], s->s_len - pos);
+
+ /* Append to anything previously prepended. */
+ memcpy(&s->s_buf[pos], buf, n);
+ s->s_len += n;
+ pos += n;
+ len -= n;
+ buf += n;
+ }
+}
+
/*
* Append bytes to an sbuf. This is the core function for appending
* to an sbuf and is the main place that deals with extending the
@@ -571,6 +624,21 @@
return (0);
}
+/*
+ * Prepend a string to an sbuf
+ */
+int
+sbuf_prepend(struct sbuf *s, const char *str)
+{
+ size_t n;
+
+ n = strlen(str);
+ sbuf_prepend_bytes(s, str, n);
+ if (s->s_error != 0)
+ return (-1);
+ return (0);
+}
+
#ifdef _KERNEL
/*
* Append a string from userland to an sbuf.
diff --git a/sys/sys/sbuf.h b/sys/sys/sbuf.h
--- a/sys/sys/sbuf.h
+++ b/sys/sys/sbuf.h
@@ -85,6 +85,7 @@
int sbuf_bcat(struct sbuf *, const void *, size_t);
int sbuf_bcpy(struct sbuf *, const void *, size_t);
int sbuf_cat(struct sbuf *, const char *);
+int sbuf_prepend(struct sbuf *, const char *);
int sbuf_cpy(struct sbuf *, const char *);
int sbuf_printf(struct sbuf *, const char *, ...)
__printflike(2, 3);

File Metadata

Mime Type
text/plain
Expires
Sun, Mar 1, 11:09 PM (8 m, 45 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29120445
Default Alt Text
D49945.id154040.diff (5 KB)

Event Timeline