media: radio: Replace strlcat() with seq_buf in TEA drivers
Subsystems (2)
PATCH 1/1 media: radio: Replace strlcat() with seq_buf in TEA drivers
In preparation for removing the deprecated strlcat() API[1], replace the strscpy() and strlcat() calls used to construct V4L2 card names in the TEA5777 and TEA575x radio drivers.
seq_buf tracks the current write position and remaining capacity across appends, avoiding repeated scans of the destination buffer. This preserves the resulting strings, including truncation behavior.
--- drivers/media/radio/radio-tea5777.c | 10 ++++++++-- drivers/media/radio/tea575x.c | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-)
drivers/media/radio/radio-tea5777.c +8 -2
@@ -13,6 +13,7 @@#include <linux/init.h> #include <linux/module.h> #include <linux/sched.h> +#include <linux/seq_buf.h> #include <linux/slab.h> #include <media/v4l2-device.h> #include <media/v4l2-dev.h>
@@ -255,10 +256,15 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) {struct radio_tea5777 *tea =video_drvdata (file); +struct seq_buf s;strscpy (v->driver, tea->v4l2_dev->name,sizeof (v->driver)); -strscpy (v->card, tea->card,sizeof (v->card)); -strlcat (v->card," TEA5777" ,sizeof (v->card)); + +seq_buf_init (&s, (char *)v->card,sizeof (v->card)); +seq_buf_puts (&s, (const char *)tea->card); +seq_buf_puts (&s," TEA5777" ); +seq_buf_terminate (&s); +strscpy (v->bus_info, tea->bus_info,sizeof (v->bus_info));return 0 ; }
drivers/media/radio/tea575x.c +8 -2
@@ -9,6 +9,7 @@#include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/seq_buf.h> #include <linux/sched.h> #include <asm/io.h> #include <media/v4l2-device.h>
@@ -221,10 +222,15 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) {struct snd_tea575x *tea =video_drvdata (file); +struct seq_buf s;strscpy (v->driver, tea->v4l2_dev->name,sizeof (v->driver)); -strscpy (v->card, tea->card,sizeof (v->card)); -strlcat (v->card, tea->tea5759 ?" TEA5759" :" TEA5757" ,sizeof (v->card)); + +seq_buf_init (&s, (char *)v->card,sizeof (v->card)); +seq_buf_puts (&s, (const char *)tea->card); +seq_buf_puts (&s, tea->tea5759 ?" TEA5759" :" TEA5757" ); +seq_buf_terminate (&s); +strscpy (v->bus_info, tea->bus_info,sizeof (v->bus_info));return 0 ; }
Signature · 1 line
2.43.0
Hi Mariia,
Quoted 35 lines
Date: 2026-11-05 23:46:39-0800
From: Mariia Nikitash <[email protected]>In preparation for removing the deprecated
strlcat()API[1], replace thestrscpy()andstrlcat()calls used to construct V4L2 card names in the TEA5777 and TEA575x radio drivers.
seq_buftracks the current write position and remaining capacity across appends, avoiding repeated scans of the destination buffer. This preserves the resulting strings, including truncation behavior.Signed-off-by Mariia Nikitash <[email protected]>--- drivers/media/radio/radio-tea5777.c | 10 ++++++++-- drivers/media/radio/tea575x.c | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-)drivers/media/radio/radio-tea5777.c +2
-0@@ -13,6 +13,7 @@#include <linux/init.h> #include <linux/module.h> #include <linux/sched.h> +#include <linux/seq_buf.h> #include <linux/slab.h> #include <media/v4l2-device.h> #include <media/v4l2-dev.h> @@ -255,10 +256,15 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) {struct radio_tea5777 *tea =video_drvdata (file); +struct seq_buf s;
drivers/media/radio/radio-tea5777.c static int vidioc_querycap(struct file *file, void *priv, · line 267
Quoted 10 lines
drivers/media/radio/radio-tea5777.c +6
-2strscpy (v->driver, tea->v4l2_dev->name,sizeof (v->driver)); -strscpy (v->card, tea->card,sizeof (v->card)); -strlcat (v->card," TEA5777" ,sizeof (v->card)); + +seq_buf_init (&s, (char *)v->card,sizeof (v->card)); +seq_buf_puts (&s, (const char *)tea->card); +seq_buf_puts (&s," TEA5777" ); +seq_buf_terminate (&s); +
Why are the casts needed?
Have a lovely day!
Alex
Quoted 37 lines
drivers/media/radio/radio-tea5777.c +0
-0strscpy (v->bus_info, tea->bus_info,sizeof (v->bus_info));return 0 ; }drivers/media/radio/tea575x.c +8
-2@@ -9,6 +9,7 @@#include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/seq_buf.h> #include <linux/sched.h> #include <asm/io.h> #include <media/v4l2-device.h> @@ -221,10 +222,15 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) {struct snd_tea575x *tea =video_drvdata (file); +struct seq_buf s;strscpy (v->driver, tea->v4l2_dev->name,sizeof (v->driver)); -strscpy (v->card, tea->card,sizeof (v->card)); -strlcat (v->card, tea->tea5759 ?" TEA5759" :" TEA5757" ,sizeof (v->card)); + +seq_buf_init (&s, (char *)v->card,sizeof (v->card)); +seq_buf_puts (&s, (const char *)tea->card); +seq_buf_puts (&s, tea->tea5759 ?" TEA5759" :" TEA5757" ); +seq_buf_terminate (&s); +strscpy (v->bus_info, tea->bus_info,sizeof (v->bus_info));return 0 ; }Signature · 1 line
2.43.0
Signature · 1 line
<https://www.alejandro-colomar.es>
Quoted 39 lines · Alejandro Colomar
Hi Mariia,
Quoted 36 lines
Date: 2026-11-05 23:46:39-0800
From: Mariia Nikitash <[email protected]>In preparation for removing the deprecated
strlcat()API[1], replace thestrscpy()andstrlcat()calls used to construct V4L2 card names in the TEA5777 and TEA575x radio drivers.
seq_buftracks the current write position and remaining capacity across appends, avoiding repeated scans of the destination buffer. This preserves the resulting strings, including truncation behavior.Signed-off-by Mariia Nikitash <[email protected]>--- drivers/media/radio/radio-tea5777.c | 10 ++++++++-- drivers/media/radio/tea575x.c | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-)drivers/media/radio/radio-tea5777.c +2
-0@@ -13,6 +13,7 @@#include <linux/init.h> #include <linux/module.h> #include <linux/sched.h> +#include <linux/seq_buf.h> #include <linux/slab.h> #include <media/v4l2-device.h> #include <media/v4l2-dev.h> @@ -255,10 +256,15 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) {struct radio_tea5777 *tea =video_drvdata (file); +struct seq_buf s;
Quoted 11 lines
drivers/media/radio/radio-tea5777.c static int vidioc_querycap(struct file *file, void *priv, · line 267
Quoted 9 lines
drivers/media/radio/radio-tea5777.c +6
-2strscpy (v->driver, tea->v4l2_dev->name,sizeof (v->driver)); -strscpy (v->card, tea->card,sizeof (v->card)); -strlcat (v->card," TEA5777" ,sizeof (v->card)); + +seq_buf_init (&s, (char *)v->card,sizeof (v->card)); +seq_buf_puts (&s, (const char *)tea->card); +seq_buf_puts (&s," TEA5777" ); +seq_buf_terminate (&s); +Why are the casts needed?
Hi Alex,
I added the casts to make conversions from u8/__u8 to character-pointer types expected by the seq_buf helpers explicit.
I'm also considering simplifying these two-part string constructions using scnprintf() instead. Would this approach be preferred?
Quoted 2 lines
Have a lovely day!
Alex
Thanks,
Mariia
Quoted 41 lines
Quoted 35 lines
drivers/media/radio/radio-tea5777.c +0
-0strscpy (v->bus_info, tea->bus_info,sizeof (v->bus_info));return 0 ; }drivers/media/radio/tea575x.c +8
-3@@ -9,6 +9,7 @@#include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/seq_buf.h> #include <linux/sched.h> #include <asm/io.h> #include <media/v4l2-device.h> @@ -221,10 +222,15 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) {struct snd_tea575x *tea =video_drvdata (file); +struct seq_buf s;strscpy (v->driver, tea->v4l2_dev->name,sizeof (v->driver)); -strscpy (v->card, tea->card,sizeof (v->card)); -strlcat (v->card, tea->tea5759 ?" TEA5759" :" TEA5757" ,sizeof (v->card)); + +seq_buf_init (&s, (char *)v->card,sizeof (v->card)); +seq_buf_puts (&s, (const char *)tea->card); +seq_buf_puts (&s, tea->tea5759 ?" TEA5759" :" TEA5757" ); +seq_buf_terminate (&s); +strscpy (v->bus_info, tea->bus_info,sizeof (v->bus_info));return 0 ; } --Quoted 3 lines
2.43.0
Hi Mariia,
Quoted 3 lines
Date: 2026-11-06 20:31:53-0800
From: Mariia Nikitash <[email protected]>
[...]
Quoted 18 lines
Quoted 6 lines
Quoted 6 lines
drivers/media/radio/radio-tea5777.c +1
-0@@ -255,10 +256,15 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) {struct radio_tea5777 *tea =video_drvdata (file); +struct seq_buf s;Quoted 11 lines
drivers/media/radio/radio-tea5777.c static int vidioc_querycap(struct file *file, void *priv, · line 267
Quoted 9 lines
drivers/media/radio/radio-tea5777.c +6
-2strscpy (v->driver, tea->v4l2_dev->name,sizeof (v->driver)); -strscpy (v->card, tea->card,sizeof (v->card)); -strlcat (v->card," TEA5777" ,sizeof (v->card)); + +seq_buf_init (&s, (char *)v->card,sizeof (v->card)); +seq_buf_puts (&s, (const char *)tea->card); +seq_buf_puts (&s," TEA5777" ); +seq_buf_terminate (&s); +Why are the casts needed?
Quoted 4 lines
Hi Alex,
I added the casts to make conversions from u8/__u8 to character-pointer types expected by the
seq_bufhelpers explicit.
I was surprised that it wasn't needed before. In theory, strscpy() should be expecting the same types, so if it wasn't needed before, it shouldn't be needed now (and conversely, if it is needed now, it would have been needed before).
Quoted 3 lines
I'm also considering simplifying these two-part string constructions using
scnprintf()instead. Would this approach be preferred?
I certainly prefer scnprintf() over seq_buf. :)
Have a lovely day!
Alex
Signature · 1 line
<https://www.alejandro-colomar.es>
Quoted 7 lines · On Thu, 5 Nov 2026 23:46:39 -0800 Mariia Nikitash…
In preparation for removing the deprecated
strlcat()API[1], replace thestrscpy()andstrlcat()calls used to construct V4L2 card names in the TEA5777 and TEA575x radio drivers.
seq_buftracks the current write position and remaining capacity across appends, avoiding repeated scans of the destination buffer. This preserves the resulting strings, including truncation behavior.
seq_buf is just OTT.
Using to replace a single strcat() is just silly.
There is no point doing these patches until there is a sensible alternative.
Quoted 21 lines
Signed-off-by Mariia Nikitash <[email protected]>--- drivers/media/radio/radio-tea5777.c | 10 ++++++++-- drivers/media/radio/tea575x.c | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-)drivers/media/radio/radio-tea5777.c +1
-0@@ -13,6 +13,7 @@#include <linux/init.h> #include <linux/module.h> #include <linux/sched.h> +#include <linux/seq_buf.h> #include <linux/slab.h> #include <media/v4l2-device.h> #include <media/v4l2-dev.h>
drivers/media/radio/radio-tea5777.c static int vidioc_querycap(struct file *file, void *priv, · line 261
Quoted 8 lines
drivers/media/radio/radio-tea5777.c +1
-2@@ -255,10 +256,15 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) {struct radio_tea5777 *tea =video_drvdata (file); +struct seq_buf s;strscpy (v->driver, tea->v4l2_dev->name,sizeof (v->driver)); -strscpy (v->card, tea->card,sizeof (v->card)); -strlcat (v->card," TEA5777" ,sizeof (v->card));
What is wrong with (and almost OTT):
#define TEA5777 " TEA5777" BUILD_BUG_ON(sizeof(TEA5777) <= sizeof(v->card)) len = strscpy(v->card, tea->card, sizeof(v->card) - sizeof(TEA5777) + 1); if (len < 0) goto fail; memcpy(v->card + len, TEA5777, sizeof(TEA5777);
What might be useful is a helper that would let you write:
len = strscpy(v->card, tea->card); len = strscpy_at(v->card, len, " TEA5777" [, implied_length]); if (len < 0) goto fail;
David
Quoted 39 lines
drivers/media/radio/radio-tea5777.c +6
-0+ +seq_buf_init (&s, (char *)v->card,sizeof (v->card)); +seq_buf_puts (&s, (const char *)tea->card); +seq_buf_puts (&s," TEA5777" ); +seq_buf_terminate (&s); +strscpy (v->bus_info, tea->bus_info,sizeof (v->bus_info));return 0 ; }drivers/media/radio/tea575x.c +8
-2@@ -9,6 +9,7 @@#include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/seq_buf.h> #include <linux/sched.h> #include <asm/io.h> #include <media/v4l2-device.h> @@ -221,10 +222,15 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) {struct snd_tea575x *tea =video_drvdata (file); +struct seq_buf s;strscpy (v->driver, tea->v4l2_dev->name,sizeof (v->driver)); -strscpy (v->card, tea->card,sizeof (v->card)); -strlcat (v->card, tea->tea5759 ?" TEA5759" :" TEA5757" ,sizeof (v->card)); + +seq_buf_init (&s, (char *)v->card,sizeof (v->card)); +seq_buf_puts (&s, (const char *)tea->card); +seq_buf_puts (&s, tea->tea5759 ?" TEA5759" :" TEA5757" ); +seq_buf_terminate (&s); +strscpy (v->bus_info, tea->bus_info,sizeof (v->bus_info));return 0 ; }
Hi David,
Quoted 3 lines
Date: 2026-11-08 21:02:32+0000
From: David Laight <[email protected]>
[...]
Quoted 4 lines
seq_bufis just OTT.
Using to replace a singlestrcat()is just silly.
There is no point doing these patches until there is a sensible alternative.
Agree.
[...]
Quoted 9 lines
drivers/media/radio/radio-tea5777.c static int vidioc_querycap(struct file *file, void *priv, · line 261
Quoted 3 lines
drivers/media/radio/radio-tea5777.c +0
-2strscpy (v->driver, tea->v4l2_dev->name,sizeof (v->driver)); -strscpy (v->card, tea->card,sizeof (v->card)); -strlcat (v->card," TEA5777" ,sizeof (v->card));What is wrong with (and almost OTT):
#define TEA5777 " TEA5777" BUILD_BUG_ON(sizeof(TEA5777) <= sizeof(v->card)) len = strscpy(v->card, tea->card, sizeof(v->card) - sizeof(TEA5777) + 1);
I can answer this one: bugs (particularly, off by one) are quite prone in such code.
From the Authors of strlcat(3), you can look at OpenBSD's manual page:
Since it is known how many characters were copied the first time, things can be sped up a bit by using a copy instead of an append: char *dir, *file, pname[PATH_MAX]; size_t n; ... n = strlcpy(pname, dir, sizeof(pname)); if (n >= sizeof(pname)) goto toolong; if (strlcpy(pname + n, file, sizeof(pname) - n) >= sizeof(pname) - n) goto toolong; However, one may question the validity of such optimizations, as they defeat the whole purpose of strlcpy() and strlcat(). As a matter of fact, the first version of this manual page got it wrong.
Quoted 9 lines
if (len < 0) goto fail; memcpy(v->card + len, TEA5777, sizeof(TEA5777);What might be useful is a helper that would let you write:
len = strscpy(v->card, tea->card); len = strscpy_at(v->card, len, " TEA5777" [, implied_length]); if (len < 0) goto fail;
Indeed, as said in other threads, I have such an API:
p = v->card; e = ARRAY_END(v->card); p = stpecpy(p, e, tea->card); p = stpecpy(p, e, " TEA5777"); if (p == NULL) goto fail;
Linus didn't like my function name. We could indeed call it strscpy_at().
Have a lovely night!
Alex
Quoted 44 lines
David
Quoted 39 lines
drivers/media/radio/radio-tea5777.c +6
-0+ +seq_buf_init (&s, (char *)v->card,sizeof (v->card)); +seq_buf_puts (&s, (const char *)tea->card); +seq_buf_puts (&s," TEA5777" ); +seq_buf_terminate (&s); +strscpy (v->bus_info, tea->bus_info,sizeof (v->bus_info));return 0 ; }drivers/media/radio/tea575x.c +8
-2@@ -9,6 +9,7 @@#include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/seq_buf.h> #include <linux/sched.h> #include <asm/io.h> #include <media/v4l2-device.h> @@ -221,10 +222,15 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) {struct snd_tea575x *tea =video_drvdata (file); +struct seq_buf s;strscpy (v->driver, tea->v4l2_dev->name,sizeof (v->driver)); -strscpy (v->card, tea->card,sizeof (v->card)); -strlcat (v->card, tea->tea5759 ?" TEA5759" :" TEA5757" ,sizeof (v->card)); + +seq_buf_init (&s, (char *)v->card,sizeof (v->card)); +seq_buf_puts (&s, (const char *)tea->card); +seq_buf_puts (&s, tea->tea5759 ?" TEA5759" :" TEA5757" ); +seq_buf_terminate (&s); +strscpy (v->bus_info, tea->bus_info,sizeof (v->bus_info));return 0 ; }
Signature · 1 line
<https://www.alejandro-colomar.es>
Quoted 10 lines · Mariia Nikitash
In preparation for removing the deprecated
strlcat()API[1], replace thestrscpy()andstrlcat()calls used to construct V4L2 card names in the TEA5777 and TEA575x radio drivers.
seq_buftracks the current write position and remaining capacity across appends, avoiding repeated scans of the destination buffer. This preserves the resulting strings, including truncation behavior.Signed-off-by Mariia Nikitash <[email protected]>
This is silly. Just use scnprintf().
Regards,
Hans
Quoted 65 lines
--- drivers/media/radio/radio-tea5777.c | 10 ++++++++-- drivers/media/radio/tea575x.c | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-)drivers/media/radio/radio-tea5777.c +8
-2@@ -13,6 +13,7 @@#include <linux/init.h> #include <linux/module.h> #include <linux/sched.h> +#include <linux/seq_buf.h> #include <linux/slab.h> #include <media/v4l2-device.h> #include <media/v4l2-dev.h> @@ -255,10 +256,15 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) {struct radio_tea5777 *tea =video_drvdata (file); +struct seq_buf s;strscpy (v->driver, tea->v4l2_dev->name,sizeof (v->driver)); -strscpy (v->card, tea->card,sizeof (v->card)); -strlcat (v->card," TEA5777" ,sizeof (v->card)); + +seq_buf_init (&s, (char *)v->card,sizeof (v->card)); +seq_buf_puts (&s, (const char *)tea->card); +seq_buf_puts (&s," TEA5777" ); +seq_buf_terminate (&s); +strscpy (v->bus_info, tea->bus_info,sizeof (v->bus_info));return 0 ; }drivers/media/radio/tea575x.c +8
-2@@ -9,6 +9,7 @@#include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/seq_buf.h> #include <linux/sched.h> #include <asm/io.h> #include <media/v4l2-device.h> @@ -221,10 +222,15 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) {struct snd_tea575x *tea =video_drvdata (file); +struct seq_buf s;strscpy (v->driver, tea->v4l2_dev->name,sizeof (v->driver)); -strscpy (v->card, tea->card,sizeof (v->card)); -strlcat (v->card, tea->tea5759 ?" TEA5759" :" TEA5757" ,sizeof (v->card)); + +seq_buf_init (&s, (char *)v->card,sizeof (v->card)); +seq_buf_puts (&s, (const char *)tea->card); +seq_buf_puts (&s, tea->tea5759 ?" TEA5759" :" TEA5757" ); +seq_buf_terminate (&s); +strscpy (v->bus_info, tea->bus_info,sizeof (v->bus_info));return 0 ; }
Quoted 9 lines · On Tue, 10 Nov 2026 11:08:30 +0100 Hans Verkuil <[email protected]>…
Quoted 8 lines · Mariia Nikitash
In preparation for removing the deprecated
strlcat()API[1], replace thestrscpy()andstrlcat()calls used to construct V4L2 card names in the TEA5777 and TEA575x radio drivers.
seq_buftracks the current write position and remaining capacity across appends, avoiding repeated scans of the destination buffer. This preserves the resulting strings, including truncation behavior.
Quoted 6 lines
Quoted 2 lines
Signed-off-by Mariia Nikitash <[email protected]>Nacked-by Hans Verkuil <[email protected]>This is silly. Just use
scnprintf().
Or wait for someone to add a call that just does what is needed. In this case the first stscpy() returns the length (and it is often known).
So you could have:
len = strscpy(buf, tea->card[, buflen]); len = strscpy_at(buf, len, " TEA5777"[, buflen]); or: len = strscat(buf, buflen, tea->card, " TEA5777", ....);
or some variant that will do a strnlen(buf, buflen) to get the offset.
But it really is best to leave the strlcat() calls in there for now.
David
Quoted 72 lines
Regards,
Hans
Quoted 65 lines
--- drivers/media/radio/radio-tea5777.c | 10 ++++++++-- drivers/media/radio/tea575x.c | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-)drivers/media/radio/radio-tea5777.c +8
-2@@ -13,6 +13,7 @@#include <linux/init.h> #include <linux/module.h> #include <linux/sched.h> +#include <linux/seq_buf.h> #include <linux/slab.h> #include <media/v4l2-device.h> #include <media/v4l2-dev.h> @@ -255,10 +256,15 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) {struct radio_tea5777 *tea =video_drvdata (file); +struct seq_buf s;strscpy (v->driver, tea->v4l2_dev->name,sizeof (v->driver)); -strscpy (v->card, tea->card,sizeof (v->card)); -strlcat (v->card," TEA5777" ,sizeof (v->card)); + +seq_buf_init (&s, (char *)v->card,sizeof (v->card)); +seq_buf_puts (&s, (const char *)tea->card); +seq_buf_puts (&s," TEA5777" ); +seq_buf_terminate (&s); +strscpy (v->bus_info, tea->bus_info,sizeof (v->bus_info));return 0 ; }drivers/media/radio/tea575x.c +8
-2@@ -9,6 +9,7 @@#include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/seq_buf.h> #include <linux/sched.h> #include <asm/io.h> #include <media/v4l2-device.h> @@ -221,10 +222,15 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) {struct snd_tea575x *tea =video_drvdata (file); +struct seq_buf s;strscpy (v->driver, tea->v4l2_dev->name,sizeof (v->driver)); -strscpy (v->card, tea->card,sizeof (v->card)); -strlcat (v->card, tea->tea5759 ?" TEA5759" :" TEA5757" ,sizeof (v->card)); + +seq_buf_init (&s, (char *)v->card,sizeof (v->card)); +seq_buf_puts (&s, (const char *)tea->card); +seq_buf_puts (&s, tea->tea5759 ?" TEA5759" :" TEA5757" ); +seq_buf_terminate (&s); +strscpy (v->bus_info, tea->bus_info,sizeof (v->bus_info));return 0 ; }
Quoted 13 lines · David Laight
Quoted 9 lines · On Tue, 10 Nov 2026 11:08:30 +0100 Hans Verkuil <[email protected]>…
Quoted 8 lines · Mariia Nikitash
In preparation for removing the deprecated
strlcat()API[1], replace thestrscpy()andstrlcat()calls used to construct V4L2 card names in the TEA5777 and TEA575x radio drivers.
seq_buftracks the current write position and remaining capacity across appends, avoiding repeated scans of the destination buffer. This preserves the resulting strings, including truncation behavior.
Quoted 5 lines
Quoted 5 lines
Quoted 2 lines
Signed-off-by Mariia Nikitash <[email protected]>Nacked-by Hans Verkuil <[email protected]>
Hi,
Quoted 6 lines
Quoted 1 line
This is silly. Just use
scnprintf().Or wait for someone to add a call that just does what is needed. In this case the first
stscpy()returns the length (and it is often known).
So you could have:
Quoted 8 lines
len = strscpy(buf, tea->card[, buflen]); len = strscpy_at(buf, len, " TEA5777"[, buflen]); or: len = strscat(buf, buflen, tea->card, " TEA5777", ....);or some variant that will do a
strnlen(buf, buflen)to get the offset.But it really is best to leave the
strlcat()calls in there for now.
Thanks Hans and David for the feedback.
I agree that seq_buf is too complex here. I'll look into using scnprintf() as Hans suggested.
David, I also see your point about leaving strlcat() in place until a more suitable append helper is available. I'll revisit the approach before deciding on a v2.
Best,
Mariia
Quoted 75 lines
David
Quoted 72 lines
Regards,
Hans
Quoted 65 lines
--- drivers/media/radio/radio-tea5777.c | 10 ++++++++-- drivers/media/radio/tea575x.c | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-)drivers/media/radio/radio-tea5777.c +8
-2@@ -13,6 +13,7 @@#include <linux/init.h> #include <linux/module.h> #include <linux/sched.h> +#include <linux/seq_buf.h> #include <linux/slab.h> #include <media/v4l2-device.h> #include <media/v4l2-dev.h> @@ -255,10 +256,15 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) {struct radio_tea5777 *tea =video_drvdata (file); +struct seq_buf s;strscpy (v->driver, tea->v4l2_dev->name,sizeof (v->driver)); -strscpy (v->card, tea->card,sizeof (v->card)); -strlcat (v->card," TEA5777" ,sizeof (v->card)); + +seq_buf_init (&s, (char *)v->card,sizeof (v->card)); +seq_buf_puts (&s, (const char *)tea->card); +seq_buf_puts (&s," TEA5777" ); +seq_buf_terminate (&s); +strscpy (v->bus_info, tea->bus_info,sizeof (v->bus_info));return 0 ; }drivers/media/radio/tea575x.c +8
-2@@ -9,6 +9,7 @@#include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/seq_buf.h> #include <linux/sched.h> #include <asm/io.h> #include <media/v4l2-device.h> @@ -221,10 +222,15 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) {struct snd_tea575x *tea =video_drvdata (file); +struct seq_buf s;strscpy (v->driver, tea->v4l2_dev->name,sizeof (v->driver)); -strscpy (v->card, tea->card,sizeof (v->card)); -strlcat (v->card, tea->tea5759 ?" TEA5759" :" TEA5757" ,sizeof (v->card)); + +seq_buf_init (&s, (char *)v->card,sizeof (v->card)); +seq_buf_puts (&s, (const char *)tea->card); +seq_buf_puts (&s, tea->tea5759 ?" TEA5759" :" TEA5757" ); +seq_buf_terminate (&s); +strscpy (v->bus_info, tea->bus_info,sizeof (v->bus_info));return 0 ; }
Quoted 3 lines · On Tue, 10 Nov 2026 10:41:06 -0800 Mariia Nikitash…
David, I also see your point about leaving
strlcat()in place until a more suitable append helper is available. I'll revisit the approach before deciding on a v2.
I really don't understand why strlcat() got marked deprecated without a suitable replacement.
The performance of any form of strcpy(t + strlen(t), s) is horrid. The only extra issue strlcat() has is to do with it doing strlen(s) to generated the return value that most code doesn't want (and in pretty much all reasonable cases is actually fine).
David