Merge branch 'bitstreamout/procps-procio'
References: procps-ng/procps!56
This commit is contained in:
commit
be6b048a41
@ -233,6 +233,8 @@ proc_libprocps_la_SOURCES = \
|
||||
proc/escape.h \
|
||||
proc/numa.c \
|
||||
proc/numa.h \
|
||||
proc/procio.c \
|
||||
proc/procio.h \
|
||||
proc/procps-private.h \
|
||||
proc/procps.h \
|
||||
proc/pwcache.c \
|
||||
@ -258,6 +260,7 @@ proc_libprocps_la_include_HEADERS = \
|
||||
proc/devname.h \
|
||||
proc/escape.h \
|
||||
proc/numa.h \
|
||||
proc/procio.h \
|
||||
proc/procps.h \
|
||||
proc/pwcache.h \
|
||||
proc/readproc.h \
|
||||
@ -269,6 +272,7 @@ proc_libprocps_la_include_HEADERS = \
|
||||
proc/whattime.h
|
||||
|
||||
dist_man_MANS += \
|
||||
proc/procio.3 \
|
||||
proc/openproc.3 \
|
||||
proc/readproc.3 \
|
||||
proc/readproctab.3
|
||||
|
@ -8,6 +8,7 @@ global:
|
||||
escape_str;
|
||||
escape_strlist;
|
||||
escaped_copy;
|
||||
fprocopen;
|
||||
free_slabinfo;
|
||||
freeproc;
|
||||
get_ns_id;
|
||||
|
80
proc/procio.3
Normal file
80
proc/procio.3
Normal file
@ -0,0 +1,80 @@
|
||||
'\" t -*- coding: UTF-8 -*-
|
||||
.\"
|
||||
.\" This file describes the readproc interface to the /proc filesystem
|
||||
.\"
|
||||
.\" Copyright 2018 Werner Fink <werner@suse.de>
|
||||
.\"
|
||||
.\" Permission is granted to make and distribute verbatim copies of this
|
||||
.\" manual provided the copyright notice and this permission notice are
|
||||
.\" preserved on all copies.
|
||||
.\"
|
||||
.\" Permission is granted to copy and distribute modified versions of this
|
||||
.\" manual under the conditions for verbatim copying, provided that the
|
||||
.\" entire resulting derived work is distributed under the terms of a
|
||||
.\" permission notice identical to this one
|
||||
.\"
|
||||
.\" Formatted or processed versions of this manual, if unaccompanied by
|
||||
.\" the source, must acknowledge the copyright and authors of this work.
|
||||
.\"
|
||||
.TH PROCIO 3 "16 January 2018" "Linux Manpage" "Linux Programmer's Manual"
|
||||
.SH NAME
|
||||
fprocopen \- stream open functions on files below /proc/##
|
||||
.SH SYNOPSIS
|
||||
.B #define _GNU_SOURCE
|
||||
.br
|
||||
.B #include <stdio.h>
|
||||
.br
|
||||
.B #include <proc/procio.h>
|
||||
.sp
|
||||
.BI "FILE *fprocopen(const char *path, const char *mode);
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
The
|
||||
.B fprocopen
|
||||
function opens files below
|
||||
.I /proc/##
|
||||
whose name is the string to by path and associates a stream with it.
|
||||
The argument
|
||||
.I mode
|
||||
points to a string beginning with one of the following sequences
|
||||
.TP
|
||||
.B r
|
||||
Open a file below
|
||||
.I /proc/##
|
||||
for reading even large buffers. The stream is positioned at
|
||||
the beginning of the file.
|
||||
.TP
|
||||
.BR w [ <del> ]
|
||||
Open a file below
|
||||
.I /proc/##
|
||||
for writing even large buffers. The optional delimeter character
|
||||
can be one of the follwoing
|
||||
.BR '\ ' ,\ ',' ,\ '.' ,\ and\ ':'
|
||||
where the default is the colon
|
||||
.BR ',' .
|
||||
This allows to split very large input lines into pieces at this
|
||||
delimeter and write each of them to the opened file below
|
||||
.IR /proc/## .
|
||||
.TP
|
||||
.B e
|
||||
The underlying file descriptor will be closed if you use any
|
||||
of the ‘exec...’ functions within your code.
|
||||
.PP
|
||||
The internal API allows to use stdio functions to read and write
|
||||
large buffers below
|
||||
.IR /proc/## .
|
||||
.PP
|
||||
.SH SEE ALSO
|
||||
.BR fopen (3),
|
||||
.br
|
||||
.BR fopencookie (3)
|
||||
.br
|
||||
.BR setvbuf (3)
|
||||
.br
|
||||
.BR lseek (3)
|
||||
.PP
|
||||
.SH COPYRIGHT
|
||||
2018 Werner Fink,
|
||||
.SH AUTHOR
|
||||
Werner Fink <werner@suse.de>
|
293
proc/procio.c
Normal file
293
proc/procio.c
Normal file
@ -0,0 +1,293 @@
|
||||
/*
|
||||
* procio.c -- Replace stdio for read and write on files below
|
||||
* proc to be able to read and write large buffers as well.
|
||||
*
|
||||
* Copyright (C) 2017 Werner Fink
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <libio.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef struct pcookie {
|
||||
char *buf;
|
||||
size_t count;
|
||||
size_t length;
|
||||
off_t offset;
|
||||
int fd;
|
||||
int delim;
|
||||
int final:1;
|
||||
} pcookie_t;
|
||||
|
||||
static ssize_t proc_read(void *, char *, size_t);
|
||||
static ssize_t proc_write(void *, const char *, size_t);
|
||||
static int proc_close(void *);
|
||||
|
||||
__extension__
|
||||
static cookie_io_functions_t procio = {
|
||||
.read = proc_read,
|
||||
.write = proc_write,
|
||||
.seek = NULL,
|
||||
.close = proc_close,
|
||||
};
|
||||
|
||||
FILE *fprocopen(const char *path, const char *mode)
|
||||
{
|
||||
pcookie_t *cookie = NULL;
|
||||
FILE *handle = NULL;
|
||||
mode_t flags = 0;
|
||||
size_t len = 0;
|
||||
int c, delim;
|
||||
|
||||
if (!mode || !(len = strlen(mode))) {
|
||||
errno = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* No append mode possible */
|
||||
switch (mode[0]) {
|
||||
case 'r':
|
||||
flags |= O_RDONLY;
|
||||
break;
|
||||
case 'w':
|
||||
flags |= O_WRONLY|O_TRUNC;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
delim = ','; /* default delimeter is the colon */
|
||||
for (c = 1; c < len; c++) {
|
||||
switch (mode[c]) {
|
||||
case '\0':
|
||||
break;
|
||||
case '+':
|
||||
errno = EINVAL;
|
||||
goto out;
|
||||
case 'e':
|
||||
flags |= O_CLOEXEC;
|
||||
continue;
|
||||
case 'b':
|
||||
case 'm':
|
||||
case 'x':
|
||||
/* ignore this */
|
||||
continue;
|
||||
default:
|
||||
if (mode[c] == ' ' || (mode[c] >= ',' && mode[c] <= '.') || mode[c] == ':')
|
||||
delim = mode[c];
|
||||
else {
|
||||
errno = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
cookie = (pcookie_t *)malloc(sizeof(pcookie_t));
|
||||
if (!cookie)
|
||||
goto out;
|
||||
cookie->count = BUFSIZ;
|
||||
cookie->buf = (char *)malloc(cookie->count);
|
||||
if (!cookie->buf) {
|
||||
int errsv = errno;
|
||||
free(cookie);
|
||||
errno = errsv;
|
||||
goto out;
|
||||
}
|
||||
cookie->final = 0;
|
||||
cookie->offset = 0;
|
||||
cookie->length = 0;
|
||||
cookie->delim = delim;
|
||||
|
||||
cookie->fd = openat(AT_FDCWD, path, flags);
|
||||
if (cookie->fd < 0) {
|
||||
int errsv = errno;
|
||||
free(cookie->buf);
|
||||
free(cookie);
|
||||
errno = errsv;
|
||||
goto out;
|
||||
}
|
||||
|
||||
handle = fopencookie(cookie, mode, procio);
|
||||
if (!handle) {
|
||||
int errsv = errno;
|
||||
close(cookie->fd);
|
||||
free(cookie->buf);
|
||||
free(cookie);
|
||||
errno = errsv;
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
return handle;
|
||||
}
|
||||
|
||||
static
|
||||
ssize_t proc_read(void *c, char *buf, size_t count)
|
||||
{
|
||||
pcookie_t *cookie = c;
|
||||
ssize_t len = -1;
|
||||
void *ptr;
|
||||
|
||||
if (cookie->count < count) {
|
||||
ptr = realloc(cookie->buf, count);
|
||||
if (!ptr)
|
||||
goto out;
|
||||
cookie->buf = ptr;
|
||||
cookie->count = count;
|
||||
}
|
||||
|
||||
while (!cookie->final) {
|
||||
len = read(cookie->fd, cookie->buf, cookie->count);
|
||||
|
||||
if (len <= 0) {
|
||||
if (len == 0) {
|
||||
/* EOF */
|
||||
cookie->final = 1;
|
||||
cookie->buf[cookie->length] = '\0';
|
||||
break;
|
||||
}
|
||||
goto out; /* error or done */
|
||||
}
|
||||
|
||||
cookie->length = len;
|
||||
|
||||
if (cookie->length < cookie->count)
|
||||
continue;
|
||||
|
||||
/* Likly to small buffer here */
|
||||
|
||||
lseek(cookie->fd, 0, SEEK_SET); /* reset for a retry */
|
||||
|
||||
ptr = realloc(cookie->buf, cookie->count += BUFSIZ);
|
||||
if (!ptr)
|
||||
goto out;
|
||||
cookie->buf = ptr;
|
||||
}
|
||||
|
||||
len = count;
|
||||
if (cookie->length - cookie->offset < len)
|
||||
len = cookie->length - cookie->offset;
|
||||
|
||||
if (len < 0)
|
||||
len = 0;
|
||||
|
||||
if (len) {
|
||||
(void)memcpy(buf, cookie->buf+cookie->offset, len);
|
||||
cookie->offset += len;
|
||||
} else
|
||||
len = EOF;
|
||||
out:
|
||||
return len;
|
||||
}
|
||||
|
||||
#define LINELEN 4096
|
||||
|
||||
static
|
||||
ssize_t proc_write(void *c, const char *buf, size_t count)
|
||||
{
|
||||
pcookie_t *cookie = c;
|
||||
ssize_t len = -1;
|
||||
void *ptr;
|
||||
|
||||
if (!count) {
|
||||
len = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* NL is the final input */
|
||||
cookie->final = memrchr(buf, '\n', count) ? 1 : 0;
|
||||
|
||||
while (cookie->count < cookie->offset + count) {
|
||||
ptr = realloc(cookie->buf, cookie->count += count);
|
||||
if (!ptr)
|
||||
goto out;
|
||||
cookie->buf = ptr;
|
||||
}
|
||||
|
||||
len = count;
|
||||
(void)memcpy(cookie->buf+cookie->offset, buf, count);
|
||||
cookie->offset += count;
|
||||
|
||||
if (cookie->final) {
|
||||
len = write(cookie->fd, cookie->buf, cookie->offset);
|
||||
if (len < 0 && errno == EINVAL) {
|
||||
size_t offset;
|
||||
off_t amount;
|
||||
char *token;
|
||||
/*
|
||||
* Oops buffer might be to large, split buffer into
|
||||
* pieces at delimeter if provided
|
||||
*/
|
||||
if (!cookie->delim)
|
||||
goto out; /* Hey dude?! */
|
||||
offset = 0;
|
||||
do {
|
||||
token = NULL;
|
||||
if (cookie->offset > LINELEN)
|
||||
token = (char*)memrchr(cookie->buf+offset, ',', LINELEN);
|
||||
else
|
||||
token = (char*)memrchr(cookie->buf+offset, '\n', LINELEN);
|
||||
if (token)
|
||||
*token = '\n';
|
||||
else {
|
||||
errno = EINVAL;
|
||||
len = -1;
|
||||
goto out; /* Wrong/Missing delimeter? */
|
||||
}
|
||||
if (offset > 0)
|
||||
lseek(cookie->fd, 1, SEEK_CUR);
|
||||
|
||||
amount = token-(cookie->buf+offset)+1;
|
||||
ptr = cookie->buf+offset;
|
||||
|
||||
len = write(cookie->fd, ptr, amount);
|
||||
if (len < 1 || len >= cookie->offset)
|
||||
break;
|
||||
|
||||
offset += len;
|
||||
cookie->offset -= len;
|
||||
|
||||
} while (cookie->offset > 0);
|
||||
}
|
||||
if (len > 0)
|
||||
len = count;
|
||||
}
|
||||
out:
|
||||
return len;
|
||||
}
|
||||
|
||||
static
|
||||
int proc_close(void *c)
|
||||
{
|
||||
pcookie_t *cookie = c;
|
||||
close(cookie->fd);
|
||||
free(cookie->buf);
|
||||
free(cookie);
|
||||
return 0;
|
||||
}
|
11
proc/procio.h
Normal file
11
proc/procio.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef PROCPS_PROC_PROCIO_H
|
||||
#define PROCPS_PROC_PROCIO_H
|
||||
|
||||
#include "procps.h"
|
||||
|
||||
EXTERN_C_BEGIN
|
||||
|
||||
extern FILE *fprocopen(const char *, const char *);
|
||||
|
||||
EXTERN_C_END
|
||||
#endif
|
66
sysctl.c
66
sysctl.c
@ -45,6 +45,7 @@
|
||||
#include "fileutils.h"
|
||||
#include "nls.h"
|
||||
#include "xalloc.h"
|
||||
#include "proc/procio.h"
|
||||
#include "proc/procps.h"
|
||||
#include "proc/version.h"
|
||||
|
||||
@ -66,6 +67,10 @@ static bool IgnoreError;
|
||||
static bool Quiet;
|
||||
static char *pattern;
|
||||
|
||||
#define LINELEN 4096
|
||||
static char *iobuf;
|
||||
static size_t iolen = LINELEN;
|
||||
|
||||
/* Function prototypes. */
|
||||
static int pattern_match(const char *string, const char *pat);
|
||||
static int DisplayAll(const char *restrict const path);
|
||||
@ -158,14 +163,12 @@ static char *StripLeadingAndTrailingSpaces(char *oneline)
|
||||
/*
|
||||
* Read a sysctl setting
|
||||
*/
|
||||
#define IOBUFSIZ (128<<10)
|
||||
static char *iobuf;
|
||||
static int ReadSetting(const char *restrict const name)
|
||||
{
|
||||
int rc = 0;
|
||||
char *restrict tmpname;
|
||||
char *restrict outname;
|
||||
char inbuf[1025];
|
||||
ssize_t rlen;
|
||||
FILE *restrict fp;
|
||||
struct stat ts;
|
||||
|
||||
@ -220,7 +223,7 @@ static int ReadSetting(const char *restrict const name)
|
||||
goto out;
|
||||
}
|
||||
|
||||
fp = fopen(tmpname, "r");
|
||||
fp = fprocopen(tmpname, "r");
|
||||
|
||||
if (!fp) {
|
||||
switch (errno) {
|
||||
@ -243,11 +246,8 @@ static int ReadSetting(const char *restrict const name)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (iobuf)
|
||||
setvbuf(fp, iobuf, _IOFBF, IOBUFSIZ);
|
||||
|
||||
errno = 0;
|
||||
if (fgets(inbuf, sizeof inbuf - 1, fp)) {
|
||||
if ((rlen = getline(&iobuf, &iolen, fp)) > 0) {
|
||||
/* this loop is required, see
|
||||
* /sbin/sysctl -a | egrep -6 dev.cdrom.info
|
||||
*/
|
||||
@ -256,23 +256,23 @@ static int ReadSetting(const char *restrict const name)
|
||||
if (PrintName) {
|
||||
fprintf(stdout, "%s = ", outname);
|
||||
do {
|
||||
fprintf(stdout, "%s", inbuf);
|
||||
nlptr = &inbuf[strlen(inbuf) - 1];
|
||||
fprintf(stdout, "%s", iobuf);
|
||||
nlptr = &iobuf[strlen(iobuf) - 1];
|
||||
/* already has the \n in it */
|
||||
if (*nlptr == '\n')
|
||||
break;
|
||||
} while (fgets(inbuf, sizeof inbuf - 1, fp));
|
||||
} while ((rlen = getline(&iobuf, &iolen, fp)) > 0);
|
||||
if (*nlptr != '\n')
|
||||
putchar('\n');
|
||||
} else {
|
||||
if (!PrintNewline) {
|
||||
nlptr = strchr(inbuf, '\n');
|
||||
nlptr = strchr(iobuf, '\n');
|
||||
if (nlptr)
|
||||
*nlptr = '\0';
|
||||
}
|
||||
fprintf(stdout, "%s", inbuf);
|
||||
fprintf(stdout, "%s", iobuf);
|
||||
}
|
||||
} while (fgets(inbuf, sizeof inbuf - 1, fp));
|
||||
} while ((rlen = getline(&iobuf, &iolen, fp)) > 0);
|
||||
} else {
|
||||
switch (errno) {
|
||||
case EACCES:
|
||||
@ -439,10 +439,7 @@ static int WriteSetting(const char *setting)
|
||||
goto out;
|
||||
}
|
||||
|
||||
fp = fopen(tmpname, "w");
|
||||
|
||||
if (iobuf)
|
||||
setvbuf(fp, iobuf, _IOFBF, IOBUFSIZ);
|
||||
fp = fprocopen(tmpname, "w");
|
||||
|
||||
if (!fp) {
|
||||
switch (errno) {
|
||||
@ -503,20 +500,17 @@ static int pattern_match(const char *string, const char *pat)
|
||||
return (1);
|
||||
}
|
||||
|
||||
#define LINELEN 4096
|
||||
|
||||
/*
|
||||
* Preload the sysctl's from the conf file. We parse the file and then
|
||||
* reform it (strip out whitespace).
|
||||
*/
|
||||
static int Preload(const char *restrict const filename)
|
||||
{
|
||||
char oneline[LINELEN];
|
||||
char buffer[LINELEN];
|
||||
FILE *fp;
|
||||
char *t;
|
||||
int n = 0;
|
||||
int rc = 0;
|
||||
ssize_t rlen;
|
||||
char *name, *value;
|
||||
glob_t globbuf;
|
||||
int globerr;
|
||||
@ -544,13 +538,19 @@ static int Preload(const char *restrict const filename)
|
||||
? stdin : fopen(globbuf.gl_pathv[j], "r");
|
||||
if (!fp) {
|
||||
xwarn(_("cannot open \"%s\""), globbuf.gl_pathv[j]);
|
||||
return -1;
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (fgets(oneline, sizeof oneline, fp)) {
|
||||
n++;
|
||||
t = StripLeadingAndTrailingSpaces(oneline);
|
||||
while ((rlen = getline(&iobuf, &iolen, fp)) > 0) {
|
||||
size_t offset;
|
||||
|
||||
n++;
|
||||
|
||||
if (rlen < 2)
|
||||
continue;
|
||||
|
||||
t = StripLeadingAndTrailingSpaces(iobuf);
|
||||
if (strlen(t) < 2)
|
||||
continue;
|
||||
|
||||
@ -569,6 +569,10 @@ static int Preload(const char *restrict const filename)
|
||||
if (pattern && !pattern_match(name, pattern))
|
||||
continue;
|
||||
|
||||
offset = strlen(name);
|
||||
memmove(&iobuf[0], name, offset);
|
||||
iobuf[offset++] = '=';
|
||||
|
||||
value = strtok(NULL, "\n\r");
|
||||
if (!value || !*value) {
|
||||
xwarnx(_("%s(%d): invalid syntax, continuing..."),
|
||||
@ -580,12 +584,16 @@ static int Preload(const char *restrict const filename)
|
||||
value++;
|
||||
|
||||
/* should NameOnly affect this? */
|
||||
sprintf(buffer, "%s=%s", name, value);
|
||||
rc |= WriteSetting(buffer);
|
||||
memmove(&iobuf[offset], value, strlen(value));
|
||||
offset += strlen(value);
|
||||
iobuf[offset] = '\0';
|
||||
|
||||
rc |= WriteSetting(iobuf);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -807,7 +815,7 @@ int main(int argc, char *argv[])
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
iobuf = (char*)malloc(IOBUFSIZ); /* Allow to fail */
|
||||
iobuf = xmalloc(iolen);
|
||||
|
||||
if (DisplayAllOpt)
|
||||
return DisplayAll(PROC_PATH);
|
||||
|
Loading…
Reference in New Issue
Block a user