master xplshn/aruu / cmd / linux / sysctl.c
  1/* See LICENSE file for copyright and license details. */
  2
  3#include <fcntl.h>
  4#include <limits.h>
  5#include <stdio.h>
  6#include <stdlib.h>
  7#include <string.h>
  8#include <unistd.h>
  9
 10#include "paths.h"
 11#include "text.h"
 12#include "util.h"
 13
 14static void
 15replacestr(char *s, int a, int b)
 16{
 17  for (; *s; s++)
 18    if (*s == a)
 19      *s = b;
 20}
 21
 22static int
 23getsysctl(char *variable, char **value)
 24{
 25  char    path[PATH_MAX];
 26  char   *p;
 27  char   *buf, *tmp, c;
 28  int     fd;
 29  ssize_t n;
 30  size_t  sz, i;
 31
 32  replacestr(variable, '.', '/');
 33
 34  strlcpy(path, ARUU_LINUX_PATH_PROC_SYS "/", sizeof(path));
 35  if (strlcat(path, variable, sizeof(path)) >= sizeof(path)) {
 36    replacestr(variable, '/', '.');
 37    return -1;
 38  }
 39
 40  replacestr(variable, '/', '.');
 41
 42  fd = open(path, O_RDONLY);
 43  if (fd < 0)
 44    return -1;
 45
 46  i   = 0;
 47  sz  = 1;
 48  buf = NULL;
 49  while (1) {
 50    n = read(fd, &c, 1);
 51    if (n < 0) {
 52      close(fd);
 53      free(buf);
 54      return -1;
 55    }
 56    if (n == 0)
 57      break;
 58    if (i == sz - 1) {
 59      sz *= 2;
 60      tmp = erealloc(buf, sz);
 61      buf = tmp;
 62    }
 63    buf[i++] = c;
 64  }
 65  buf[i] = '\0';
 66
 67  p = strrchr(buf, '\n');
 68  if (p)
 69    *p = '\0';
 70
 71  *value = buf;
 72
 73  close(fd);
 74
 75  return 0;
 76}
 77
 78static int
 79setsysctl(char *variable, char *value)
 80{
 81  char    path[PATH_MAX];
 82  int     fd;
 83  ssize_t n;
 84
 85  replacestr(variable, '.', '/');
 86
 87  strlcpy(path, ARUU_LINUX_PATH_PROC_SYS "/", sizeof(path));
 88  if (strlcat(path, variable, sizeof(path)) >= sizeof(path)) {
 89    replacestr(variable, '/', '.');
 90    return -1;
 91  }
 92
 93  replacestr(variable, '/', '.');
 94
 95  fd = open(path, O_WRONLY);
 96  if (fd < 0)
 97    return -1;
 98
 99  n = write(fd, value, strlen(value));
100  if ((size_t)n != strlen(value)) {
101    close(fd);
102    return -1;
103  }
104
105  close(fd);
106
107  return 0;
108}
109
110static int
111parsepair(char *pair)
112{
113  char *p;
114  char *variable;
115  char *value;
116
117  for (p = pair; *p; p++) {
118    if (p[0] == '.' && p[1] == '.') {
119      weprintf("malformed input: %s\n", pair);
120      return -1;
121    }
122  }
123  p = strchr(pair, '=');
124  if (p) {
125    if (p[1] == '\0') {
126      weprintf("malformed input: %s\n", pair);
127      return -1;
128    }
129    *p    = '\0';
130    value = &p[1];
131  } else {
132    value = NULL;
133  }
134  variable = pair;
135  if (value) {
136    if (setsysctl(variable, value) < 0) {
137      weprintf("failed to set sysctl for %s\n", variable);
138      return -1;
139    }
140  } else {
141    if (getsysctl(variable, &value) < 0) {
142      weprintf("failed to get sysctl for %s\n", variable);
143      return -1;
144    }
145    printf("%s = %s\n", variable, value);
146    free(value);
147  }
148
149  return 0;
150}
151
152static void
153usage(void)
154{
155  eprintf("usage: %s [-p file] variable[=value]...\n", argv0);
156}
157
158// ?man sysctl: configure kernel parameters
159// ?man arguments: variable[=value]...
160// ?man view and modify kernel parameters at runtime
161int
162main(int argc, char *argv[])
163{
164  FILE  *fp;
165  char  *buf  = NULL, *p;
166  char  *file = NULL;
167  size_t size = 0;
168  int    i;
169  int    r = 0;
170
171  ARGBEGIN
172  {
173    // ?man -p:file: preserve file attributes
174    case 'p':
175      file = EARGF(usage());
176      break;
177    default:
178      usage();
179  }
180  ARGEND;
181
182  if (!file && argc < 1)
183    usage();
184
185  if (!file) {
186    for (i = 0; i < argc; i++)
187      if (parsepair(argv[i]) < 0)
188        r = 1;
189  } else {
190    fp = fopen(file, "r");
191    if (!fp)
192      eprintf("fopen %s:", file);
193    while (agetline(&buf, &size, fp) != -1) {
194      p = buf;
195      for (p = buf; *p == ' ' || *p == '\t'; p++)
196        ;
197      if (*p == '#' || *p == '\n')
198        continue;
199      for (p = buf; *p; p++) {
200        if (*p == '\n') {
201          *p = '\0';
202          break;
203        }
204      }
205      p = buf;
206      if (parsepair(p) < 0)
207        r = 1;
208    }
209    if (ferror(fp))
210      eprintf("%s: read error:", file);
211    free(buf);
212    fclose(fp);
213  }
214
215  return r;
216}