Re: [PATCH v2 2/2] Use virProcessGetStat

2021-11-23 Thread Martin Kletzander

On Mon, Nov 22, 2021 at 09:59:07AM +, Daniel P. Berrangé wrote:

On Mon, Nov 22, 2021 at 10:34:38AM +0100, Martin Kletzander wrote:

On Mon, Nov 22, 2021 at 09:18:41AM +, Daniel P. Berrangé wrote:
> On Sun, Nov 21, 2021 at 12:04:26AM +0100, Martin Kletzander wrote:
> > This eliminates one incorrect parsing implementation.
>
> Please explain what was being done wrongly / what was the
> effect of the bug ?
>

One of the implementations was just looking for first closing
parenthesis to find the end of the command name, which should be done by
looking at the _last_ closing parenthesis.  This might fail in a very
small corner case which is tested for in the first patch.  But you are
right, I should add this to the commit message.  Will do in v3.

> >
> > Signed-off-by: Martin Kletzander 
> > ---
> >  src/qemu/qemu_driver.c | 33 ++---
> >  src/util/virprocess.c  | 48 ++
> >  2 files changed, 12 insertions(+), 69 deletions(-)
> >
> > diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> > index d954635dde2a..0468d6aaf314 100644
> > --- a/src/qemu/qemu_driver.c
> > +++ b/src/qemu/qemu_driver.c
> > @@ -1399,36 +1399,17 @@ qemuGetSchedInfo(unsigned long long *cpuWait,
> >
> >  static int
> >  qemuGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, long *vm_rss,
> > -   pid_t pid, int tid)
> > +   pid_t pid, pid_t tid)
> >  {
> > -g_autofree char *proc = NULL;
> > -FILE *pidinfo;
> > +g_auto(GStrv) proc_stat = virProcessGetStat(pid, tid);
> >  unsigned long long usertime = 0, systime = 0;
> >  long rss = 0;
> >  int cpu = 0;
> >
> > -/* In general, we cannot assume pid_t fits in int; but /proc parsing
> > - * is specific to Linux where int works fine.  */
> > -if (tid)
> > -proc = g_strdup_printf("/proc/%d/task/%d/stat", (int)pid, tid);
> > -else
> > -proc = g_strdup_printf("/proc/%d/stat", (int)pid);
> > -if (!proc)
> > -return -1;
> > -
> > -pidinfo = fopen(proc, "r");
> > -
> > -/* See 'man proc' for information about what all these fields are. 
We're
> > - * only interested in a very few of them */
> > -if (!pidinfo ||
> > -fscanf(pidinfo,
> > -   /* pid -> stime */
> > -   "%*d (%*[^)]) %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu 
%llu"
> > -   /* cutime -> endcode */
> > -   "%*d %*d %*d %*d %*d %*d %*u %*u %ld %*u %*u %*u"
> > -   /* startstack -> processor */
> > -   "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %d",
> > -   , , , ) != 4) {
> > +if (virStrToLong_ullp(proc_stat[13], NULL, 10, ) < 0 ||
> > +virStrToLong_ullp(proc_stat[14], NULL, 10, ) < 0 ||
> > +virStrToLong_l(proc_stat[23], NULL, 10, ) < 0 ||
> > +virStrToLong_i(proc_stat[38], NULL, 10, ) < 0) {
>
> Since you're adding a formal API, I think we'd benefit from
> constants for these array indexes in virprocess.h
>

I was thinking about that and also tried figuring out how to encode the
proper field types in the header file.  But since we are not doing lot
of /proc/*/stat parsing in our codebase I though that would be an
overkill.  I'll add at least the constants.


BTW ,didn't mean we need constants for all 40+ fields - just the ones
we actually use.



oops, too late, at least it is now complete =)


Regards,
Daniel
--
|: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o-https://fstop138.berrange.com :|
|: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|



signature.asc
Description: PGP signature


Re: [PATCH v2 2/2] Use virProcessGetStat

2021-11-22 Thread Daniel P . Berrangé
On Mon, Nov 22, 2021 at 10:34:38AM +0100, Martin Kletzander wrote:
> On Mon, Nov 22, 2021 at 09:18:41AM +, Daniel P. Berrangé wrote:
> > On Sun, Nov 21, 2021 at 12:04:26AM +0100, Martin Kletzander wrote:
> > > This eliminates one incorrect parsing implementation.
> > 
> > Please explain what was being done wrongly / what was the
> > effect of the bug ?
> > 
> 
> One of the implementations was just looking for first closing
> parenthesis to find the end of the command name, which should be done by
> looking at the _last_ closing parenthesis.  This might fail in a very
> small corner case which is tested for in the first patch.  But you are
> right, I should add this to the commit message.  Will do in v3.
> 
> > > 
> > > Signed-off-by: Martin Kletzander 
> > > ---
> > >  src/qemu/qemu_driver.c | 33 ++---
> > >  src/util/virprocess.c  | 48 ++
> > >  2 files changed, 12 insertions(+), 69 deletions(-)
> > > 
> > > diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> > > index d954635dde2a..0468d6aaf314 100644
> > > --- a/src/qemu/qemu_driver.c
> > > +++ b/src/qemu/qemu_driver.c
> > > @@ -1399,36 +1399,17 @@ qemuGetSchedInfo(unsigned long long *cpuWait,
> > > 
> > >  static int
> > >  qemuGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, long 
> > > *vm_rss,
> > > -   pid_t pid, int tid)
> > > +   pid_t pid, pid_t tid)
> > >  {
> > > -g_autofree char *proc = NULL;
> > > -FILE *pidinfo;
> > > +g_auto(GStrv) proc_stat = virProcessGetStat(pid, tid);
> > >  unsigned long long usertime = 0, systime = 0;
> > >  long rss = 0;
> > >  int cpu = 0;
> > > 
> > > -/* In general, we cannot assume pid_t fits in int; but /proc parsing
> > > - * is specific to Linux where int works fine.  */
> > > -if (tid)
> > > -proc = g_strdup_printf("/proc/%d/task/%d/stat", (int)pid, tid);
> > > -else
> > > -proc = g_strdup_printf("/proc/%d/stat", (int)pid);
> > > -if (!proc)
> > > -return -1;
> > > -
> > > -pidinfo = fopen(proc, "r");
> > > -
> > > -/* See 'man proc' for information about what all these fields are. 
> > > We're
> > > - * only interested in a very few of them */
> > > -if (!pidinfo ||
> > > -fscanf(pidinfo,
> > > -   /* pid -> stime */
> > > -   "%*d (%*[^)]) %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u 
> > > %llu %llu"
> > > -   /* cutime -> endcode */
> > > -   "%*d %*d %*d %*d %*d %*d %*u %*u %ld %*u %*u %*u"
> > > -   /* startstack -> processor */
> > > -   "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %d",
> > > -   , , , ) != 4) {
> > > +if (virStrToLong_ullp(proc_stat[13], NULL, 10, ) < 0 ||
> > > +virStrToLong_ullp(proc_stat[14], NULL, 10, ) < 0 ||
> > > +virStrToLong_l(proc_stat[23], NULL, 10, ) < 0 ||
> > > +virStrToLong_i(proc_stat[38], NULL, 10, ) < 0) {
> > 
> > Since you're adding a formal API, I think we'd benefit from
> > constants for these array indexes in virprocess.h
> > 
> 
> I was thinking about that and also tried figuring out how to encode the
> proper field types in the header file.  But since we are not doing lot
> of /proc/*/stat parsing in our codebase I though that would be an
> overkill.  I'll add at least the constants.

BTW ,didn't mean we need constants for all 40+ fields - just the ones
we actually use.

Regards,
Daniel
-- 
|: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o-https://fstop138.berrange.com :|
|: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|



Re: [PATCH v2 2/2] Use virProcessGetStat

2021-11-22 Thread Martin Kletzander

On Mon, Nov 22, 2021 at 09:18:41AM +, Daniel P. Berrangé wrote:

On Sun, Nov 21, 2021 at 12:04:26AM +0100, Martin Kletzander wrote:

This eliminates one incorrect parsing implementation.


Please explain what was being done wrongly / what was the
effect of the bug ?



One of the implementations was just looking for first closing
parenthesis to find the end of the command name, which should be done by
looking at the _last_ closing parenthesis.  This might fail in a very
small corner case which is tested for in the first patch.  But you are
right, I should add this to the commit message.  Will do in v3.



Signed-off-by: Martin Kletzander 
---
 src/qemu/qemu_driver.c | 33 ++---
 src/util/virprocess.c  | 48 ++
 2 files changed, 12 insertions(+), 69 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index d954635dde2a..0468d6aaf314 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1399,36 +1399,17 @@ qemuGetSchedInfo(unsigned long long *cpuWait,

 static int
 qemuGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, long *vm_rss,
-   pid_t pid, int tid)
+   pid_t pid, pid_t tid)
 {
-g_autofree char *proc = NULL;
-FILE *pidinfo;
+g_auto(GStrv) proc_stat = virProcessGetStat(pid, tid);
 unsigned long long usertime = 0, systime = 0;
 long rss = 0;
 int cpu = 0;

-/* In general, we cannot assume pid_t fits in int; but /proc parsing
- * is specific to Linux where int works fine.  */
-if (tid)
-proc = g_strdup_printf("/proc/%d/task/%d/stat", (int)pid, tid);
-else
-proc = g_strdup_printf("/proc/%d/stat", (int)pid);
-if (!proc)
-return -1;
-
-pidinfo = fopen(proc, "r");
-
-/* See 'man proc' for information about what all these fields are. We're
- * only interested in a very few of them */
-if (!pidinfo ||
-fscanf(pidinfo,
-   /* pid -> stime */
-   "%*d (%*[^)]) %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu 
%llu"
-   /* cutime -> endcode */
-   "%*d %*d %*d %*d %*d %*d %*u %*u %ld %*u %*u %*u"
-   /* startstack -> processor */
-   "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %d",
-   , , , ) != 4) {
+if (virStrToLong_ullp(proc_stat[13], NULL, 10, ) < 0 ||
+virStrToLong_ullp(proc_stat[14], NULL, 10, ) < 0 ||
+virStrToLong_l(proc_stat[23], NULL, 10, ) < 0 ||
+virStrToLong_i(proc_stat[38], NULL, 10, ) < 0) {


Since you're adding a formal API, I think we'd benefit from
constants for these array indexes in virprocess.h



I was thinking about that and also tried figuring out how to encode the
proper field types in the header file.  But since we are not doing lot
of /proc/*/stat parsing in our codebase I though that would be an
overkill.  I'll add at least the constants.

Thanks,
Martin



Regards,
Daniel
--
|: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o-https://fstop138.berrange.com :|
|: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|



signature.asc
Description: PGP signature


Re: [PATCH v2 2/2] Use virProcessGetStat

2021-11-22 Thread Daniel P . Berrangé
On Sun, Nov 21, 2021 at 12:04:26AM +0100, Martin Kletzander wrote:
> This eliminates one incorrect parsing implementation.

Please explain what was being done wrongly / what was the
effect of the bug ?

> 
> Signed-off-by: Martin Kletzander 
> ---
>  src/qemu/qemu_driver.c | 33 ++---
>  src/util/virprocess.c  | 48 ++
>  2 files changed, 12 insertions(+), 69 deletions(-)
> 
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index d954635dde2a..0468d6aaf314 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -1399,36 +1399,17 @@ qemuGetSchedInfo(unsigned long long *cpuWait,
>  
>  static int
>  qemuGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, long *vm_rss,
> -   pid_t pid, int tid)
> +   pid_t pid, pid_t tid)
>  {
> -g_autofree char *proc = NULL;
> -FILE *pidinfo;
> +g_auto(GStrv) proc_stat = virProcessGetStat(pid, tid);
>  unsigned long long usertime = 0, systime = 0;
>  long rss = 0;
>  int cpu = 0;
>  
> -/* In general, we cannot assume pid_t fits in int; but /proc parsing
> - * is specific to Linux where int works fine.  */
> -if (tid)
> -proc = g_strdup_printf("/proc/%d/task/%d/stat", (int)pid, tid);
> -else
> -proc = g_strdup_printf("/proc/%d/stat", (int)pid);
> -if (!proc)
> -return -1;
> -
> -pidinfo = fopen(proc, "r");
> -
> -/* See 'man proc' for information about what all these fields are. We're
> - * only interested in a very few of them */
> -if (!pidinfo ||
> -fscanf(pidinfo,
> -   /* pid -> stime */
> -   "%*d (%*[^)]) %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u 
> %llu %llu"
> -   /* cutime -> endcode */
> -   "%*d %*d %*d %*d %*d %*d %*u %*u %ld %*u %*u %*u"
> -   /* startstack -> processor */
> -   "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %d",
> -   , , , ) != 4) {
> +if (virStrToLong_ullp(proc_stat[13], NULL, 10, ) < 0 ||
> +virStrToLong_ullp(proc_stat[14], NULL, 10, ) < 0 ||
> +virStrToLong_l(proc_stat[23], NULL, 10, ) < 0 ||
> +virStrToLong_i(proc_stat[38], NULL, 10, ) < 0) {

Since you're adding a formal API, I think we'd benefit from
constants for these array indexes in virprocess.h


Regards,
Daniel
-- 
|: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org -o-https://fstop138.berrange.com :|
|: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|



[PATCH v2 2/2] Use virProcessGetStat

2021-11-20 Thread Martin Kletzander
This eliminates one incorrect parsing implementation.

Signed-off-by: Martin Kletzander 
---
 src/qemu/qemu_driver.c | 33 ++---
 src/util/virprocess.c  | 48 ++
 2 files changed, 12 insertions(+), 69 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index d954635dde2a..0468d6aaf314 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -1399,36 +1399,17 @@ qemuGetSchedInfo(unsigned long long *cpuWait,
 
 static int
 qemuGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, long *vm_rss,
-   pid_t pid, int tid)
+   pid_t pid, pid_t tid)
 {
-g_autofree char *proc = NULL;
-FILE *pidinfo;
+g_auto(GStrv) proc_stat = virProcessGetStat(pid, tid);
 unsigned long long usertime = 0, systime = 0;
 long rss = 0;
 int cpu = 0;
 
-/* In general, we cannot assume pid_t fits in int; but /proc parsing
- * is specific to Linux where int works fine.  */
-if (tid)
-proc = g_strdup_printf("/proc/%d/task/%d/stat", (int)pid, tid);
-else
-proc = g_strdup_printf("/proc/%d/stat", (int)pid);
-if (!proc)
-return -1;
-
-pidinfo = fopen(proc, "r");
-
-/* See 'man proc' for information about what all these fields are. We're
- * only interested in a very few of them */
-if (!pidinfo ||
-fscanf(pidinfo,
-   /* pid -> stime */
-   "%*d (%*[^)]) %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu 
%llu"
-   /* cutime -> endcode */
-   "%*d %*d %*d %*d %*d %*d %*u %*u %ld %*u %*u %*u"
-   /* startstack -> processor */
-   "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %d",
-   , , , ) != 4) {
+if (virStrToLong_ullp(proc_stat[13], NULL, 10, ) < 0 ||
+virStrToLong_ullp(proc_stat[14], NULL, 10, ) < 0 ||
+virStrToLong_l(proc_stat[23], NULL, 10, ) < 0 ||
+virStrToLong_i(proc_stat[38], NULL, 10, ) < 0) {
 VIR_WARN("cannot parse process status data");
 }
 
@@ -1450,8 +1431,6 @@ qemuGetProcessInfo(unsigned long long *cpuTime, int 
*lastCpu, long *vm_rss,
 VIR_DEBUG("Got status for %d/%d user=%llu sys=%llu cpu=%d rss=%ld",
   (int)pid, tid, usertime, systime, cpu, rss);
 
-VIR_FORCE_FCLOSE(pidinfo);
-
 return 0;
 }
 
diff --git a/src/util/virprocess.c b/src/util/virprocess.c
index 73ebcaae422f..4def5ecf5eb3 100644
--- a/src/util/virprocess.c
+++ b/src/util/virprocess.c
@@ -1153,56 +1153,20 @@ virProcessSetMaxCoreSize(pid_t pid G_GNUC_UNUSED,
 int virProcessGetStartTime(pid_t pid,
unsigned long long *timestamp)
 {
-char *tmp;
-int len;
-g_autofree char *filename = NULL;
-g_autofree char *buf = NULL;
-g_auto(GStrv) tokens = NULL;
-
-filename = g_strdup_printf("/proc/%llu/stat", (long long)pid);
-
-if ((len = virFileReadAll(filename, 1024, )) < 0)
-return -1;
+g_auto(GStrv) proc_stat = virProcessGetStat(pid, 0);
 
-/* start time is the token at index 19 after the '(process name)' entry - 
since only this
- * field can contain the ')' character, search backwards for this to avoid 
malicious
- * processes trying to fool us
- */
-
-if (!(tmp = strrchr(buf, ')'))) {
+if (!proc_stat || g_strv_length(proc_stat) < 22) {
 virReportError(VIR_ERR_INTERNAL_ERROR,
-   _("Cannot find start time in %s"),
-   filename);
+   _("Cannot find start time for pid %d"), (int)pid);
 return -1;
 }
-tmp += 2; /* skip ') ' */
-if ((tmp - buf) >= len) {
-virReportError(VIR_ERR_INTERNAL_ERROR,
-   _("Cannot find start time in %s"),
-   filename);
-return -1;
-}
-
-tokens = g_strsplit(tmp, " ", 0);
 
-if (!tokens ||
-g_strv_length(tokens) < 20) {
+if (virStrToLong_ull(proc_stat[21], NULL, 10, timestamp) < 0) {
 virReportError(VIR_ERR_INTERNAL_ERROR,
-   _("Cannot find start time in %s"),
-   filename);
+   _("Cannot parse start time %s for pid %d"),
+   proc_stat[21], (int)pid);
 return -1;
 }
-
-if (virStrToLong_ull(tokens[19],
- NULL,
- 10,
- timestamp) < 0) {
-virReportError(VIR_ERR_INTERNAL_ERROR,
-   _("Cannot parse start time %s in %s"),
-   tokens[19], filename);
-return -1;
-}
-
 return 0;
 }
 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-- 
2.34.0