mailing list of musl libc
 help / color / mirror / code / Atom feed
* Re: [musl] What if the line in /proc/mounts is too long when calling getmntent_r?
@ 2021-08-27 13:26 Érico Nogueira
  2021-08-27 13:43 ` Rich Felker
  0 siblings, 1 reply; 6+ messages in thread
From: Érico Nogueira @ 2021-08-27 13:26 UTC (permalink / raw)
  To: musl, 2010267516

Apparently I failed to CC you	in my original reply, sorry.

Forwarded message from Érico Nogueira on Fri Aug 27, 2021 at 10:05 AM:

Unfortunately your message was sent all garbled (please try to stick to
plain text email ;), so I'm reproducing it cleanly underneath with my
answer:

>Hi!
>  I want to get cgroups mount information from /proc/mounts, but when i calling struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen), i got nothing...
>  I run the program in a container.
>
>  alpine docker image:  amd64/alpine:3.14
>  musl: 1.2.2
>  program:  
>
>    #include <stdio.h>
>
>    #include <stdlib.h>
>
>    #include <mntent.h>
>
>
>    #define CGROUP_MAX_VAL 512
>
>
>    int main(void)
>
>    {
>
>      struct mntent ent;
>
>      FILE *f;
>
>      char buf[CGROUP_MAX_VAL];
>
>
>      f = setmntent("/proc/mounts", "r");
>
>      if (f == NULL) {
>
>        perror("setmntent");
>
>        exit(1);
>
>      }
>
>
>      while (getmntent_r(f, &ent, buf, sizeof(buf)) != NULL) {
>
>        printf("%s %s\n", ent.mnt_type, ent.mnt_opts);
>
>      }

The man page specifies that getmntent_r can return NULL on error, you
should check errno to see if anything happened. In this case, it would
be ERANGE, which tells you your buffer was too small.

>
>
>      endmntent(f);
>
>    }
>
>  contents of file "/proc/mounts"
>
>    overlay / overlay rw,relatime,lowerdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/955/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/954/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/953/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/952/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/941/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/940/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/879/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/325/fs,upperdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/956/fs,workdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/956/work 0 0
>
>    proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
>
>    tmpfs /dev tmpfs rw,nosuid,size=65536k,mode=755 0 0
>
>    devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666 0 0
>
>    mqueue /dev/mqueue mqueue rw,nosuid,nodev,noexec,relatime 0 0
>
>    sysfs /sys sysfs ro,nosuid,nodev,noexec,relatime 0 0
>
>    tmpfs /sys/fs/cgroup tmpfs rw,nosuid,nodev,noexec,relatime,mode=755 0 0
>
>    cgroup /sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd 0 0
>
>    cgroup /sys/fs/cgroup/net_cls,net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_prio,net_cls 0 0
>
>    cgroup /sys/fs/cgroup/pids cgroup rw,nosuid,nodev,noexec,relatime,pids 0 0
>
>    cgroup /sys/fs/cgroup/hugetlb cgroup rw,nosuid,nodev,noexec,relatime,hugetlb 0 0
>
>    cgroup /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0
>
>    cgroup /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0
>
>    cgroup /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0
>
>    cgroup /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0
>
>    cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpuacct,cpu 0 0
>
>    cgroup /sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0
>
>    cgroup /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0
>
>    ...
>
>
>  I find the first line of the file /proc/mounts has 822 characters(In theory the 'overlay' could be even longer), more than CGROUP_MAX_VAL(512) defined in the proagram. Function fget in getmntent_r cann't get the whole line into linebuf, neither the character '\n'. And the function strchr(linebuf, '\n') returns false, causing program returnd. 
>  The function struct mntent *getmntent(FILE *f) is a good chioce to deal this. But it can not be used in multiple threads, right?

Correct, getmntent isn't thread safe.

>  Maybe the implementation of GNU libc struct mntent *__getmntent_r (FILE *stream, struct mntent *mp, char *buffer, int bufsiz) can be referenced.

From what I can see, glibc silently throws away any and all chars that
don't fit in the provided buffer until it finds a newline. getmntent_r
isn't actually specified, so I guess its behavior is a bit up to the
implementation. Anyhow, musl's reports ERANGE properly (maybe the man
page can be fixed to mention it?) and you should use a dynamic buffer in
your program if you expect to deal with huge entries, and resize it if
getmntent_r fails with ERANGE.

>
>  thanks!


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [musl] What if the line in /proc/mounts is too long when calling getmntent_r?
  2021-08-27 13:26 [musl] What if the line in /proc/mounts is too long when calling getmntent_r? Érico Nogueira
@ 2021-08-27 13:43 ` Rich Felker
  2021-08-28  2:58   ` Érico Nogueira
  0 siblings, 1 reply; 6+ messages in thread
From: Rich Felker @ 2021-08-27 13:43 UTC (permalink / raw)
  To: Érico Nogueira; +Cc: musl, 2010267516

On Fri, Aug 27, 2021 at 10:26:35AM -0300, Érico Nogueira wrote:
> Apparently I failed to CC you	in my original reply, sorry.
> 
> Forwarded message from Érico Nogueira on Fri Aug 27, 2021 at 10:05 AM:
> 
> Unfortunately your message was sent all garbled (please try to stick to
> plain text email ;), so I'm reproducing it cleanly underneath with my
> answer:
> 
> >Hi!
> >  I want to get cgroups mount information from /proc/mounts, but when i calling struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen), i got nothing...
> >  I run the program in a container.
> >
> >  alpine docker image:  amd64/alpine:3.14
> >  musl: 1.2.2
> >  program:  
> >
> >    #include <stdio.h>
> >
> >    #include <stdlib.h>
> >
> >    #include <mntent.h>
> >
> >
> >    #define CGROUP_MAX_VAL 512
> >
> >
> >    int main(void)
> >
> >    {
> >
> >      struct mntent ent;
> >
> >      FILE *f;
> >
> >      char buf[CGROUP_MAX_VAL];
> >
> >
> >      f = setmntent("/proc/mounts", "r");
> >
> >      if (f == NULL) {
> >
> >        perror("setmntent");
> >
> >        exit(1);
> >
> >      }
> >
> >
> >      while (getmntent_r(f, &ent, buf, sizeof(buf)) != NULL) {
> >
> >        printf("%s %s\n", ent.mnt_type, ent.mnt_opts);
> >
> >      }
> 
> The man page specifies that getmntent_r can return NULL on error, you
> should check errno to see if anything happened. In this case, it would
> be ERANGE, which tells you your buffer was too small.
> 
> >
> >
> >      endmntent(f);
> >
> >    }
> >
> >  contents of file "/proc/mounts"
> >
> >    overlay / overlay rw,relatime,lowerdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/955/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/954/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/953/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/952/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/941/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/940/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/879/fs:/var/lib/containerd/io..containerd.snapshotter.v1.overlayfs/snapshots/325/fs,upperdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/956/fs,workdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/956/work 0 0
> >
> >    proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
> >
> >    tmpfs /dev tmpfs rw,nosuid,size=65536k,mode=755 0 0
> >
> >    devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666 0 0
> >
> >    mqueue /dev/mqueue mqueue rw,nosuid,nodev,noexec,relatime 0 0
> >
> >    sysfs /sys sysfs ro,nosuid,nodev,noexec,relatime 0 0
> >
> >    tmpfs /sys/fs/cgroup tmpfs rw,nosuid,nodev,noexec,relatime,mode=755 0 0
> >
> >    cgroup /sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd 0 0
> >
> >    cgroup /sys/fs/cgroup/net_cls,net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_prio,net_cls 0 0
> >
> >    cgroup /sys/fs/cgroup/pids cgroup rw,nosuid,nodev,noexec,relatime,pids 0 0
> >
> >    cgroup /sys/fs/cgroup/hugetlb cgroup rw,nosuid,nodev,noexec,relatime,hugetlb 0 0
> >
> >    cgroup /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0
> >
> >    cgroup /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0
> >
> >    cgroup /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0
> >
> >    cgroup /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0
> >
> >    cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpuacct,cpu 0 0
> >
> >    cgroup /sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0
> >
> >    cgroup /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0
> >
> >    ...
> >
> >
> >  I find the first line of the file /proc/mounts has 822 characters(In theory the 'overlay' could be even longer), more than CGROUP_MAX_VAL(512) defined in the proagram. Function fget in getmntent_r cann't get the whole line into linebuf, neither the character '\n'. And the function strchr(linebuf, '\n') returns false, causing program returnd. 
> >  The function struct mntent *getmntent(FILE *f) is a good chioce to deal this. But it can not be used in multiple threads, right?
> 
> Correct, getmntent isn't thread safe.
> 
> >  Maybe the implementation of GNU libc struct mntent *__getmntent_r (FILE *stream, struct mntent *mp, char *buffer, int bufsiz) can be referenced.
> 
> >From what I can see, glibc silently throws away any and all chars that
> don't fit in the provided buffer until it finds a newline. getmntent_r
> isn't actually specified, so I guess its behavior is a bit up to the
> implementation. Anyhow, musl's reports ERANGE properly (maybe the man
> page can be fixed to mention it?) and you should use a dynamic buffer in
> your program if you expect to deal with huge entries, and resize it if
> getmntent_r fails with ERANGE.

I'm not sure what the right way to recover in that situation is
supposed to be, though... You can't just call it again with musl's
current implementation or you'll start in the middle of a line, which
is clearly wrong. But if you do the glibc thing and throw away the
rest of the line, you also lose a line of data.

Rich

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [musl] What if the line in /proc/mounts is too long when calling getmntent_r?
  2021-08-27 13:43 ` Rich Felker
@ 2021-08-28  2:58   ` Érico Nogueira
  2021-08-28  6:17     ` Markus Wichmann
  0 siblings, 1 reply; 6+ messages in thread
From: Érico Nogueira @ 2021-08-28  2:58 UTC (permalink / raw)
  To: musl; +Cc: 2010267516

On Fri Aug 27, 2021 at 10:43 AM -03, Rich Felker wrote:
> On Fri, Aug 27, 2021 at 10:26:35AM -0300, Érico Nogueira wrote:
> > Apparently I failed to CC you	in my original reply, sorry.
> > 
> > Forwarded message from Érico Nogueira on Fri Aug 27, 2021 at 10:05 AM:
> > 
> > Unfortunately your message was sent all garbled (please try to stick to
> > plain text email ;), so I'm reproducing it cleanly underneath with my
> > answer:
> > 
> > >Hi!
> > >  I want to get cgroups mount information from /proc/mounts, but when i calling struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen), i got nothing...
> > >  I run the program in a container.
> > >
> > >  alpine docker image:  amd64/alpine:3.14
> > >  musl: 1.2.2
> > >  program:  
> > >
> > >    #include <stdio.h>
> > >
> > >    #include <stdlib.h>
> > >
> > >    #include <mntent.h>
> > >
> > >
> > >    #define CGROUP_MAX_VAL 512
> > >
> > >
> > >    int main(void)
> > >
> > >    {
> > >
> > >      struct mntent ent;
> > >
> > >      FILE *f;
> > >
> > >      char buf[CGROUP_MAX_VAL];
> > >
> > >
> > >      f = setmntent("/proc/mounts", "r");
> > >
> > >      if (f == NULL) {
> > >
> > >        perror("setmntent");
> > >
> > >        exit(1);
> > >
> > >      }
> > >
> > >
> > >      while (getmntent_r(f, &ent, buf, sizeof(buf)) != NULL) {
> > >
> > >        printf("%s %s\n", ent.mnt_type, ent.mnt_opts);
> > >
> > >      }
> > 
> > The man page specifies that getmntent_r can return NULL on error, you
> > should check errno to see if anything happened. In this case, it would
> > be ERANGE, which tells you your buffer was too small.
> > 
> > >
> > >
> > >      endmntent(f);
> > >
> > >    }
> > >
> > >  contents of file "/proc/mounts"
> > >
> > >    overlay / overlay rw,relatime,lowerdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/955/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/954/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/953/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/952/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/941/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/940/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/879/fs:/var/lib/containerd/io..containerd.snapshotter.v1.overlayfs/snapshots/325/fs,upperdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/956/fs,workdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/956/work 0 0
> > >
> > >    proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
> > >
> > >    tmpfs /dev tmpfs rw,nosuid,size=65536k,mode=755 0 0
> > >
> > >    devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666 0 0
> > >
> > >    mqueue /dev/mqueue mqueue rw,nosuid,nodev,noexec,relatime 0 0
> > >
> > >    sysfs /sys sysfs ro,nosuid,nodev,noexec,relatime 0 0
> > >
> > >    tmpfs /sys/fs/cgroup tmpfs rw,nosuid,nodev,noexec,relatime,mode=755 0 0
> > >
> > >    cgroup /sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd 0 0
> > >
> > >    cgroup /sys/fs/cgroup/net_cls,net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_prio,net_cls 0 0
> > >
> > >    cgroup /sys/fs/cgroup/pids cgroup rw,nosuid,nodev,noexec,relatime,pids 0 0
> > >
> > >    cgroup /sys/fs/cgroup/hugetlb cgroup rw,nosuid,nodev,noexec,relatime,hugetlb 0 0
> > >
> > >    cgroup /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0
> > >
> > >    cgroup /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0
> > >
> > >    cgroup /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0
> > >
> > >    cgroup /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0
> > >
> > >    cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpuacct,cpu 0 0
> > >
> > >    cgroup /sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0
> > >
> > >    cgroup /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0
> > >
> > >    ...
> > >
> > >
> > >  I find the first line of the file /proc/mounts has 822 characters(In theory the 'overlay' could be even longer), more than CGROUP_MAX_VAL(512) defined in the proagram. Function fget in getmntent_r cann't get the whole line into linebuf, neither the character '\n'. And the function strchr(linebuf, '\n') returns false, causing program returnd. 
> > >  The function struct mntent *getmntent(FILE *f) is a good chioce to deal this. But it can not be used in multiple threads, right?
> > 
> > Correct, getmntent isn't thread safe.
> > 
> > >  Maybe the implementation of GNU libc struct mntent *__getmntent_r (FILE *stream, struct mntent *mp, char *buffer, int bufsiz) can be referenced.
> > 
> > >From what I can see, glibc silently throws away any and all chars that
> > don't fit in the provided buffer until it finds a newline. getmntent_r
> > isn't actually specified, so I guess its behavior is a bit up to the
> > implementation. Anyhow, musl's reports ERANGE properly (maybe the man
> > page can be fixed to mention it?) and you should use a dynamic buffer in
> > your program if you expect to deal with huge entries, and resize it if
> > getmntent_r fails with ERANGE.
>
> I'm not sure what the right way to recover in that situation is
> supposed to be, though... You can't just call it again with musl's
> current implementation or you'll start in the middle of a line, which
> is clearly wrong. But if you do the glibc thing and throw away the
> rest of the line, you also lose a line of data.

Don't you just skip the line entirely, due to the fscanf call? At least
that's what I assumed it was meant for.

		if (!strchr(linebuf, '\n')) {
			fscanf(f, "%*[^\n]%*[\n]");
			errno = ERANGE;
			return 0;
		}

So the current interface doesn't allow trying again to read the too-long
entry, since it will just have moved to the next one. I doubt any users
of the function will try to call getmntent_r again after it's returned
0, even if in this case it might still return the rest of the entries.

For possible changes, losing the rest of the line bothers me somewhat,
though it's supposedly what users on glibc will already expect. Do you
think doing fseek(f, -fgets_result, SEEK_CUR) without the fscanf call to
rewind until the start of the line would be valid? It would allow one to
retry again with bigger buffers. This is bad, of course, if there are
folks writing code to call getmntent_r again even after it returns 0 (it
would be very kooky code, since differentiating between the 0 returns
sounds complicated to me, unless they used errno==ERANGE as a
sinalizer); in their case, they expect to receive the next entry, but
the function would just loop eternally with too short a buffer. This
corner case feels like it would come from coding to the observed
behavior rather than any specification, so I don't know if it needs to
be respected.

>
> Rich


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [musl] What if the line in /proc/mounts is too long when calling getmntent_r?
  2021-08-28  2:58   ` Érico Nogueira
@ 2021-08-28  6:17     ` Markus Wichmann
  0 siblings, 0 replies; 6+ messages in thread
From: Markus Wichmann @ 2021-08-28  6:17 UTC (permalink / raw)
  To: musl

On Fri, Aug 27, 2021 at 11:58:11PM -0300, Érico Nogueira wrote:
> This is bad, of course, if there are
> folks writing code to call getmntent_r again even after it returns 0 (it
> would be very kooky code, since differentiating between the 0 returns
> sounds complicated to me, unless they used errno==ERANGE as a
> sinalizer); in their case, they expect to receive the next entry, but
> the function would just loop eternally with too short a buffer. This
> corner case feels like it would come from coding to the observed
> behavior rather than any specification, so I don't know if it needs to
> be respected.
>

This type of behavior is also used in other functions. readdir() returns
a NULL pointer at end of directory and on error. And getpriority()
returns -1 on error and if the priority currently actually is -1. So
zeroing out errno and testing it after the call is a normal way to
distinguish error returns and normal returns in some interfaces.

The entire mntent library is non-standard, according to the manpage. So
the only specification that exists is glibc behavior. And it skips over
too long lines. Therefore we will have to do the same. Anyone who wants
something else will have to write their own parser. mntent is not the
most complicated format in the world.

Ciao,
Markus

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [musl] What if the line in /proc/mounts is too long when calling getmntent_r?
  2021-08-27  4:48 care
@ 2021-08-27 13:05 ` Érico Nogueira
  0 siblings, 0 replies; 6+ messages in thread
From: Érico Nogueira @ 2021-08-27 13:05 UTC (permalink / raw)
  To: musl

Unfortunately your message was sent all garbled (please try to stick to
plain text email ;), so I'm reproducing it cleanly underneath with my
answer:

>Hi!
>  I want to get cgroups mount information from /proc/mounts, but when i calling struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen), i got nothing...
>  I run the program in a container.
>
>  alpine docker image:  amd64/alpine:3.14
>  musl: 1.2.2
>  program:  
>
>    #include <stdio.h>
>
>    #include <stdlib.h>
>
>    #include <mntent.h>
>
>
>    #define CGROUP_MAX_VAL 512
>
>
>    int main(void)
>
>    {
>
>      struct mntent ent;
>
>      FILE *f;
>
>      char buf[CGROUP_MAX_VAL];
>
>
>      f = setmntent("/proc/mounts", "r");
>
>      if (f == NULL) {
>
>        perror("setmntent");
>
>        exit(1);
>
>      }
>
>
>      while (getmntent_r(f, &ent, buf, sizeof(buf)) != NULL) {
>
>        printf("%s %s\n", ent.mnt_type, ent.mnt_opts);
>
>      }

The man page specifies that getmntent_r can return NULL on error, you
should check errno to see if anything happened. In this case, it would
be ERANGE, which tells you your buffer was too small.

>
>
>      endmntent(f);
>
>    }
>
>  contents of file "/proc/mounts"
>
>    overlay / overlay rw,relatime,lowerdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/955/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/954/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/953/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/952/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/941/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/940/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/879/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/325/fs,upperdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/956/fs,workdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/956/work 0 0
>
>    proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
>
>    tmpfs /dev tmpfs rw,nosuid,size=65536k,mode=755 0 0
>
>    devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666 0 0
>
>    mqueue /dev/mqueue mqueue rw,nosuid,nodev,noexec,relatime 0 0
>
>    sysfs /sys sysfs ro,nosuid,nodev,noexec,relatime 0 0
>
>    tmpfs /sys/fs/cgroup tmpfs rw,nosuid,nodev,noexec,relatime,mode=755 0 0
>
>    cgroup /sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd 0 0
>
>    cgroup /sys/fs/cgroup/net_cls,net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_prio,net_cls 0 0
>
>    cgroup /sys/fs/cgroup/pids cgroup rw,nosuid,nodev,noexec,relatime,pids 0 0
>
>    cgroup /sys/fs/cgroup/hugetlb cgroup rw,nosuid,nodev,noexec,relatime,hugetlb 0 0
>
>    cgroup /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0
>
>    cgroup /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0
>
>    cgroup /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0
>
>    cgroup /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0
>
>    cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpuacct,cpu 0 0
>
>    cgroup /sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0
>
>    cgroup /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0
>
>    ...
>
>
>  I find the first line of the file /proc/mounts has 822 characters(In theory the 'overlay' could be even longer), more than CGROUP_MAX_VAL(512) defined in the proagram. Function fget in getmntent_r cann't get the whole line into linebuf, neither the character '\n'. And the function strchr(linebuf, '\n') returns false, causing program returnd. 
>  The function struct mntent *getmntent(FILE *f) is a good chioce to deal this. But it can not be used in multiple threads, right?

Correct, getmntent isn't thread safe.

>  Maybe the implementation of GNU libc struct mntent *__getmntent_r (FILE *stream, struct mntent *mp, char *buffer, int bufsiz) can be referenced.

From what I can see, glibc silently throws away any and all chars that
don't fit in the provided buffer until it finds a newline. getmntent_r
isn't actually specified, so I guess its behavior is a bit up to the
implementation. Anyhow, musl's reports ERANGE properly (maybe the man
page can be fixed to mention it?) and you should use a dynamic buffer in
your program if you expect to deal with huge entries, and resize it if
getmntent_r fails with ERANGE.

>
>  thanks!

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [musl] What if the line in /proc/mounts is too long when calling getmntent_r?
@ 2021-08-27  4:48 care
  2021-08-27 13:05 ` Érico Nogueira
  0 siblings, 1 reply; 6+ messages in thread
From: care @ 2021-08-27  4:48 UTC (permalink / raw)
  To: musl

[-- Attachment #1: Type: text/plain, Size: 3708 bytes --]

Hi!
&nbsp; I want to get cgroups mount information from /proc/mounts, but when i calling&nbsp;struct mntent *getmntent_r(FILE *f, struct mntent *mnt, char *linebuf, int buflen), i got nothing...
&nbsp; I run the program in a container.

&nbsp; alpine docker image:&nbsp; amd64/alpine:3.14
&nbsp; musl: 1.2.2
&nbsp; program:&nbsp;&nbsp;
#include <stdio.h&gt;#include <stdlib.h&gt;#include <mntent.h&gt;
#define CGROUP_MAX_VAL 512
int main(void){&nbsp; struct mntent ent;&nbsp; FILE *f;&nbsp; char buf[CGROUP_MAX_VAL];
&nbsp; f = setmntent("/proc/mounts", "r");&nbsp; if (f == NULL) {&nbsp; &nbsp; perror("setmntent");&nbsp; &nbsp; exit(1);&nbsp; }
&nbsp; while (getmntent_r(f, &amp;ent, buf, sizeof(buf)) != NULL) {&nbsp; &nbsp; printf("%s %s\n", ent.mnt_type, ent.mnt_opts);&nbsp; }
&nbsp; endmntent(f);}&nbsp; contents of file "/proc/mounts"
overlay / overlay rw,relatime,lowerdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/955/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/954/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/953/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/952/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/941/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/940/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/879/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/325/fs,upperdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/956/fs,workdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/956/work 0 0proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0tmpfs /dev tmpfs rw,nosuid,size=65536k,mode=755 0 0devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666 0 0mqueue /dev/mqueue mqueue rw,nosuid,nodev,noexec,relatime 0 0sysfs /sys sysfs ro,nosuid,nodev,noexec,relatime 0 0tmpfs /sys/fs/cgroup tmpfs rw,nosuid,nodev,noexec,relatime,mode=755 0 0cgroup /sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd 0 0cgroup /sys/fs/cgroup/net_cls,net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_prio,net_cls 0 0cgroup /sys/fs/cgroup/pids cgroup rw,nosuid,nodev,noexec,relatime,pids 0 0cgroup /sys/fs/cgroup/hugetlb cgroup rw,nosuid,nodev,noexec,relatime,hugetlb 0 0cgroup /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0cgroup /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0cgroup /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0cgroup /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpuacct,cpu 0 0cgroup /sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0cgroup /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0...

&nbsp; I find the first line of the file /proc/mounts has 822 characters(In theory the 'overlay' could be even longer), more than CGROUP_MAX_VAL(512) defined in the proagram. Function fget in&nbsp;getmntent_r&nbsp;cann't get the whole line into linebuf, neither the character '\n'. And the function strchr(linebuf, '\n') returns false, causing program returnd.&nbsp;
&nbsp; The function&nbsp;struct mntent *getmntent(FILE *f)&nbsp;is a good chioce to deal this. But it can not be used in multiple threads, right?
&nbsp; Maybe the implementation of GNU libc&nbsp;struct mntent *__getmntent_r (FILE *stream, struct mntent *mp, char *buffer, int bufsiz)&nbsp;can be referenced.


&nbsp; thanks!

[-- Attachment #2: Type: text/html, Size: 10702 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-08-28  6:17 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-27 13:26 [musl] What if the line in /proc/mounts is too long when calling getmntent_r? Érico Nogueira
2021-08-27 13:43 ` Rich Felker
2021-08-28  2:58   ` Érico Nogueira
2021-08-28  6:17     ` Markus Wichmann
  -- strict thread matches above, loose matches on Subject: below --
2021-08-27  4:48 care
2021-08-27 13:05 ` Érico Nogueira

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).