dcf3a71079bed60bc0765d26b2fc67cb2db06d05
[platform/upstream/procps-ng.git] / sysctl.c
1 /*
2  * Sysctl 1.01 - A utility to read and manipulate the sysctl parameters
3  *
4  * "Copyright 1999 George Staikos
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  *
20  * Changelog:
21  *            v1.01:
22  *                   - added -p <preload> to preload values from a file
23  *            Horms:
24  *                   - added -q to be quiet when modifying values
25  *
26  * Changes by Albert Cahalan, 2002.
27  */
28
29 #include <dirent.h>
30 #include <errno.h>
31 #include <getopt.h>
32 #include <glob.h>
33 #include <libgen.h>
34 #include <limits.h>
35 #include <regex.h>
36 #include <stdbool.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 #include <unistd.h>
43
44 #include "c.h"
45 #include "fileutils.h"
46 #include "nls.h"
47 #include "xalloc.h"
48 #include "proc/procps.h"
49 #include "proc/version.h"
50
51 /*
52  *    Globals...
53  */
54 static const char PROC_PATH[] = "/proc/sys/";
55 static const char DEFAULT_PRELOAD[] = "/etc/sysctl.conf";
56 static const char *DEPRECATED[] = {
57         "base_reachable_time",
58         "retrans_time",
59         ""
60 };
61 static bool IgnoreDeprecated;
62 static bool NameOnly;
63 static bool PrintName;
64 static bool PrintNewline;
65 static bool IgnoreError;
66 static bool Quiet;
67 static char *pattern;
68
69 /* Function prototypes. */
70 static int pattern_match(const char *string, const char *pat);
71 static int DisplayAll(const char *restrict const path);
72
73 static void slashdot(char *restrict p, char old, char new)
74 {
75         int warned = 1;
76         p = strpbrk(p, "/.");
77         if (!p)
78                 /* nothing -- can't be, but oh well */
79                 return;
80         if (*p == new)
81                 /* already in desired format */
82                 return;
83         while (p) {
84                 char c = *p;
85                 if ((*(p + 1) == '/' || *(p + 1) == '.') && warned) {
86                         xwarnx(_("separators should not be repeated: %s"), p);
87                         warned = 0;
88                 }
89                 if (c == old)
90                         *p = new;
91                 if (c == new)
92                         *p = old;
93                 p = strpbrk(p + 1, "/.");
94         }
95 }
96
97 /*
98  * Display the usage format
99  */
100 static void __attribute__ ((__noreturn__))
101     Usage(FILE * out)
102 {
103         fputs(USAGE_HEADER, out);
104         fprintf(out,
105               _(" %s [options] [variable[=value] ...]\n"),
106                 program_invocation_short_name);
107         fputs(USAGE_OPTIONS, out);
108         fputs(_("  -a, --all            display all variables\n"), out);
109         fputs(_("  -A                   alias of -a\n"), out);
110         fputs(_("  -X                   alias of -a\n"), out);
111         fputs(_("      --deprecated     include deprecated parameters to listing\n"), out);
112         fputs(_("  -b, --binary         print value without new line\n"), out);
113         fputs(_("  -e, --ignore         ignore unknown variables errors\n"), out);
114         fputs(_("  -N, --names          print variable names without values\n"), out);
115         fputs(_("  -n, --values         print only values of a variables\n"), out);
116         fputs(_("  -p, --load[=<file>]  read values from file\n"), out);
117         fputs(_("  -f                   alias of -p\n"), out);
118         fputs(_("      --system         read values from all system directories\n"), out);
119         fputs(_("  -r, --pattern <expression>\n"
120                 "                       select setting that match expression\n"), out);
121         fputs(_("  -q, --quiet          do not echo variable set\n"), out);
122         fputs(_("  -w, --write          enable writing a value to variable\n"), out);
123         fputs(_("  -o                   does nothing\n"), out);
124         fputs(_("  -x                   does nothing\n"), out);
125         fputs(_("  -d                   alias of -h\n"), out);
126         fputs(USAGE_SEPARATOR, out);
127         fputs(USAGE_HELP, out);
128         fputs(USAGE_VERSION, out);
129         fprintf(out, USAGE_MAN_TAIL("sysctl(8)"));
130
131         exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
132 }
133
134 /*
135  * Strip the leading and trailing spaces from a string
136  */
137 static char *StripLeadingAndTrailingSpaces(char *oneline)
138 {
139         char *t;
140
141         if (!oneline || !*oneline)
142                 return oneline;
143
144         t = oneline;
145         t += strlen(oneline) - 1;
146
147         while ((*t == ' ' || *t == '\t' || *t == '\n' || *t == '\r') && t != oneline)
148                 *t-- = 0;
149
150         t = oneline;
151
152         while ((*t == ' ' || *t == '\t') && *t != 0)
153                 t++;
154
155         return t;
156 }
157
158 /*
159  * Read a sysctl setting
160  */
161 static int ReadSetting(const char *restrict const name)
162 {
163         int rc = 0;
164         char *restrict tmpname;
165         char *restrict outname;
166         char inbuf[1025];
167         FILE *restrict fp;
168         struct stat ts;
169
170         if (!name || !*name) {
171                 xwarnx(_("\"%s\" is an unknown key"), name);
172                 return -1;
173         }
174
175         /* used to display the output */
176         outname = xstrdup(name);
177         /* change / to . */
178         slashdot(outname, '/', '.');
179
180         /* used to open the file */
181         tmpname = xmalloc(strlen(name) + strlen(PROC_PATH) + 2);
182         strcpy(tmpname, PROC_PATH);
183         strcat(tmpname, name);
184         /* change . to / */
185         slashdot(tmpname + strlen(PROC_PATH), '.', '/');
186
187         /* used to display the output */
188         outname = xstrdup(name);
189         /* change / to . */
190         slashdot(outname, '/', '.');
191
192         if (stat(tmpname, &ts) < 0) {
193                 if (!IgnoreError) {
194                         xwarn(_("cannot stat %s"), tmpname);
195                         rc = -1;
196                 }
197                 goto out;
198         }
199         if ((ts.st_mode & S_IRUSR) == 0)
200                 goto out;
201
202         if (S_ISDIR(ts.st_mode)) {
203                 size_t len;
204                 len = strlen(tmpname);
205                 tmpname[len] = '/';
206                 tmpname[len + 1] = '\0';
207                 rc = DisplayAll(tmpname);
208                 goto out;
209         }
210
211         if (pattern && !pattern_match(outname, pattern)) {
212                 free(outname);
213                 return 0;
214         }
215
216         fp = fopen(tmpname, "r");
217
218         if (!fp) {
219                 switch (errno) {
220                 case ENOENT:
221                         if (!IgnoreError) {
222                                 xwarnx(_("\"%s\" is an unknown key"), outname);
223                                 rc = -1;
224                         }
225                         break;
226                 case EACCES:
227                         xwarnx(_("permission denied on key '%s'"), outname);
228                         rc = -1;
229                         break;
230                 default:
231                         xwarn(_("reading key \"%s\""), outname);
232                         rc = -1;
233                         break;
234                 }
235         } else {
236                 errno = 0;
237                 if (fgets(inbuf, sizeof inbuf - 1, fp)) {
238                         /* this loop is required, see
239                          * /sbin/sysctl -a | egrep -6 dev.cdrom.info
240                          */
241                         do {
242                                 if (NameOnly) {
243                                         fprintf(stdout, "%s\n", outname);
244                                 } else {
245                                         /* already has the \n in it */
246                                         if (PrintName) {
247                                                 fprintf(stdout, "%s = %s",
248                                                         outname, inbuf);
249                                                 if (inbuf[strlen(inbuf) - 1] != '\n')
250                                                         putchar('\n');
251                                         } else {
252                                                 if (!PrintNewline) {
253                                                         char *nlptr =
254                                                             strchr(inbuf, '\n');
255                                                         if (nlptr)
256                                                                 *nlptr = '\0';
257                                                 }
258                                                 fprintf(stdout, "%s", inbuf);
259                                         }
260                                 }
261                         } while (fgets(inbuf, sizeof inbuf - 1, fp));
262                 } else {
263                         switch (errno) {
264                         case EACCES:
265                                 xwarnx(_("permission denied on key '%s'"),
266                                        outname);
267                                 rc = -1;
268                                 break;
269                         case EISDIR: {
270                                         size_t len;
271                                         len = strlen(tmpname);
272                                         tmpname[len] = '/';
273                                         tmpname[len + 1] = '\0';
274                                         fclose(fp);
275                                         rc = DisplayAll(tmpname);
276                                         goto out;
277                                 }
278                         default:
279                                 xwarnx(_("reading key \"%s\""), outname);
280                                 rc = -1;
281                         case 0:
282                                 break;
283                         }
284                 }
285                 fclose(fp);
286         }
287       out:
288         free(tmpname);
289         free(outname);
290         return rc;
291 }
292
293 static int is_deprecated(char *filename)
294 {
295         int i;
296         for (i = 0; strlen(DEPRECATED[i]); i++) {
297                 if (strcmp(DEPRECATED[i], filename) == 0)
298                         return 1;
299         }
300         return 0;
301 }
302
303 /*
304  * Display all the sysctl settings
305  */
306 static int DisplayAll(const char *restrict const path)
307 {
308         int rc = 0;
309         int rc2;
310         DIR *restrict dp;
311         struct dirent *restrict de;
312         struct stat ts;
313
314         dp = opendir(path);
315
316         if (!dp) {
317                 xwarnx(_("unable to open directory \"%s\""), path);
318                 rc = -1;
319         } else {
320                 readdir(dp);    /* skip .  */
321                 readdir(dp);    /* skip .. */
322                 while ((de = readdir(dp))) {
323                         char *restrict tmpdir;
324                         if (IgnoreDeprecated && is_deprecated(de->d_name))
325                                 continue;
326                         tmpdir =
327                             (char *restrict) xmalloc(strlen(path) +
328                                                      strlen(de->d_name) +
329                                                      2);
330                         sprintf(tmpdir, "%s%s", path, de->d_name);
331                         rc2 = stat(tmpdir, &ts);
332                         if (rc2 != 0) {
333                                 xwarn(_("cannot stat %s"), tmpdir);
334                         } else {
335                                 if (S_ISDIR(ts.st_mode)) {
336                                         strcat(tmpdir, "/");
337                                         DisplayAll(tmpdir);
338                                 } else {
339                                         rc |=
340                                             ReadSetting(tmpdir +
341                                                         strlen(PROC_PATH));
342                                 }
343                         }
344                         free(tmpdir);
345                 }
346                 closedir(dp);
347         }
348         return rc;
349 }
350
351 /*
352  * Write a sysctl setting
353  */
354 static int WriteSetting(const char *setting)
355 {
356         int rc = 0;
357         const char *name = setting;
358         const char *value;
359         const char *equals;
360         char *tmpname;
361         char *outname;
362         char *last_dot;
363
364         FILE *fp;
365         struct stat ts;
366
367         if (!name)
368                 /* probably don't want to display this err */
369                 return 0;
370
371         equals = strchr(setting, '=');
372
373         if (!equals) {
374                 xwarnx(_("\"%s\" must be of the form name=value"),
375                        setting);
376                 return -1;
377         }
378
379         /* point to the value in name=value */
380         value = equals + 1;
381
382         if (!*name || !*value || name == equals) {
383                 xwarnx(_("malformed setting \"%s\""), setting);
384                 return -2;
385         }
386
387         /* used to open the file */
388         tmpname = xmalloc(equals - name + 1 + strlen(PROC_PATH));
389         strcpy(tmpname, PROC_PATH);
390         strncat(tmpname, name, (int) (equals - name));
391         tmpname[equals - name + strlen(PROC_PATH)] = 0;
392         /* change . to / */
393         slashdot(tmpname + strlen(PROC_PATH), '.', '/');
394
395         /* used to display the output */
396         outname = xmalloc(equals - name + 1);
397         strncpy(outname, name, (int) (equals - name));
398         outname[equals - name] = 0;
399         /* change / to . */
400         slashdot(outname, '/', '.');
401         last_dot = strrchr(outname, '.');
402         if (last_dot != NULL && is_deprecated(last_dot + 1)) {
403                 xwarnx(_("%s is deprecated, value not set"), outname);
404                 goto out;
405         }
406
407         if (stat(tmpname, &ts) < 0) {
408                 if (!IgnoreError) {
409                         xwarn(_("cannot stat %s"), tmpname);
410                         rc = -1;
411                 }
412                 goto out;
413         }
414
415         if ((ts.st_mode & S_IWUSR) == 0) {
416                 xwarn(_("setting key \"%s\""), outname);
417                 goto out;
418         }
419
420         if (S_ISDIR(ts.st_mode)) {
421                 xwarn(_("setting key \"%s\""), outname);
422                 goto out;
423         }
424
425         fp = fopen(tmpname, "w");
426
427         if (!fp) {
428                 switch (errno) {
429                 case ENOENT:
430                         if (!IgnoreError) {
431                                 xwarnx(_("\"%s\" is an unknown key"), outname);
432                                 rc = -1;
433                         }
434                         break;
435                 case EACCES:
436                         xwarnx(_("permission denied on key '%s'"), outname);
437                         rc = -1;
438                         break;
439                 default:
440                         xwarn(_("setting key \"%s\""), outname);
441                         rc = -1;
442                         break;
443                 }
444         } else {
445                 rc = fprintf(fp, "%s\n", value);
446                 if (0 < rc)
447                         rc = 0;
448                 if (close_stream(fp) != 0)
449                         xwarn(_("setting key \"%s\""), outname);
450                 if (rc == 0 && !Quiet) {
451                         if (NameOnly) {
452                                 fprintf(stdout, "%s\n", outname);
453                         } else {
454                                 if (PrintName) {
455                                         fprintf(stdout, "%s = %s\n",
456                                                 outname, value);
457                                 } else {
458                                         if (PrintNewline)
459                                                 fprintf(stdout, "%s\n", value);
460                                         else
461                                                 fprintf(stdout, "%s", value);
462                                 }
463                         }
464                 }
465         }
466       out:
467         free(tmpname);
468         free(outname);
469         return rc;
470 }
471
472 static int pattern_match(const char *string, const char *pat)
473 {
474         int status;
475         regex_t re;
476
477         if (regcomp(&re, pat, REG_EXTENDED | REG_NOSUB) != 0)
478                 return (0);
479         status = regexec(&re, string, (size_t) 0, NULL, 0);
480         regfree(&re);
481         if (status != 0)
482                 return (0);
483         return (1);
484 }
485
486 #define LINELEN 4096
487
488 /*
489  * Preload the sysctl's from the conf file.  We parse the file and then
490  * reform it (strip out whitespace).
491  */
492 static int Preload(const char *restrict const filename)
493 {
494         char oneline[LINELEN];
495         char buffer[LINELEN];
496         FILE *fp;
497         char *t;
498         int n = 0;
499         int rc = 0;
500         char *name, *value;
501         glob_t globbuf;
502         int globerr;
503         int globflg;
504         int j;
505
506         globflg = GLOB_NOCHECK;
507 #ifdef GLOB_BRACE
508         globflg |= GLOB_BRACE;
509 #endif
510 #ifdef GLOB_TILDE
511         globflg |= GLOB_TILDE;
512 #else
513         if (filename[0] == '~')
514                 xwarnx(_("GLOB_TILDE is not supported on your platform, "
515                          "the tilde in \"%s\" won't be expanded."), filename);
516 #endif
517         globerr = glob(filename, globflg, NULL, &globbuf);
518
519         if (globerr != 0 && globerr != GLOB_NOMATCH)
520                 xerr(EXIT_FAILURE, _("glob failed"));
521
522         for (j = 0; j < globbuf.gl_pathc; j++) {
523                 fp = (globbuf.gl_pathv[j][0] == '-' && !globbuf.gl_pathv[j][1])
524                     ? stdin : fopen(globbuf.gl_pathv[j], "r");
525                 if (!fp) {
526                         xwarn(_("cannot open \"%s\""), globbuf.gl_pathv[j]);
527                         return -1;
528                 }
529
530                 while (fgets(oneline, sizeof oneline, fp)) {
531                         n++;
532                         t = StripLeadingAndTrailingSpaces(oneline);
533
534                         if (strlen(t) < 2)
535                                 continue;
536
537                         if (*t == '#' || *t == ';')
538                                 continue;
539
540                         name = strtok(t, "=");
541                         if (!name || !*name) {
542                                 xwarnx(_("%s(%d): invalid syntax, continuing..."),
543                                        globbuf.gl_pathv[j], n);
544                                 continue;
545                         }
546
547                         StripLeadingAndTrailingSpaces(name);
548
549                         if (pattern && !pattern_match(name, pattern))
550                                 continue;
551
552                         value = strtok(NULL, "\n\r");
553                         if (!value || !*value) {
554                                 xwarnx(_("%s(%d): invalid syntax, continuing..."),
555                                        globbuf.gl_pathv[j], n);
556                                 continue;
557                         }
558
559                         while ((*value == ' ' || *value == '\t') && *value != 0)
560                                 value++;
561
562                         /* should NameOnly affect this? */
563                         sprintf(buffer, "%s=%s", name, value);
564                         rc |= WriteSetting(buffer);
565                 }
566
567                 fclose(fp);
568         }
569         return rc;
570 }
571
572 struct pair {
573         char *name;
574         char *value;
575 };
576
577 static int sortpairs(const void *A, const void *B)
578 {
579         const struct pair *a = *(struct pair * const *) A;
580         const struct pair *b = *(struct pair * const *) B;
581         return strcmp(a->name, b->name);
582 }
583
584 static int PreloadSystem(void)
585 {
586         unsigned di, i;
587         const char *dirs[] = {
588                 "/run/sysctl.d",
589                 "/etc/sysctl.d",
590                 "/usr/local/lib/sysctl.d",
591                 "/usr/lib/sysctl.d",
592                 "/lib/sysctl.d",
593         };
594         struct pair **cfgs = NULL;
595         unsigned ncfgs = 0;
596         int rc = 0;
597         struct stat ts;
598         enum { nprealloc = 16 };
599
600         for (di = 0; di < sizeof(dirs) / sizeof(dirs[0]); ++di) {
601                 struct dirent *de;
602                 DIR *dp = opendir(dirs[di]);
603                 if (!dp)
604                         continue;
605
606                 while ((de = readdir(dp))) {
607                         if (!strcmp(de->d_name, ".")
608                             || !strcmp(de->d_name, ".."))
609                                 continue;
610                         if (strlen(de->d_name) < 5
611                             || strcmp(de->d_name + strlen(de->d_name) - 5, ".conf"))
612                                 continue;
613                         /* check if config already known */
614                         for (i = 0; i < ncfgs; ++i) {
615                                 if (cfgs && !strcmp(cfgs[i]->name, de->d_name))
616                                         break;
617                         }
618                         if (i < ncfgs)
619                                 /* already in */
620                                 continue;
621
622                         if (ncfgs % nprealloc == 0)
623                                 cfgs =
624                                     xrealloc(cfgs,
625                                              sizeof(struct pair *) * (ncfgs +
626                                                                       nprealloc));
627
628                         if (cfgs) {
629                                 cfgs[ncfgs] =
630                                     xmalloc(sizeof(struct pair) +
631                                             strlen(de->d_name) * 2 + 2 +
632                                             strlen(dirs[di]) + 1);
633                                 cfgs[ncfgs]->name =
634                                     (char *)cfgs[ncfgs] + sizeof(struct pair);
635                                 strcpy(cfgs[ncfgs]->name, de->d_name);
636                                 cfgs[ncfgs]->value =
637                                     (char *)cfgs[ncfgs] + sizeof(struct pair) +
638                                     strlen(cfgs[ncfgs]->name) + 1;
639                                 sprintf(cfgs[ncfgs]->value, "%s/%s", dirs[di],
640                                         de->d_name);
641                                 ncfgs++;
642                         } else {
643                                 xerrx(EXIT_FAILURE, _("internal error"));
644                         }
645
646                 }
647                 closedir(dp);
648         }
649         qsort(cfgs, ncfgs, sizeof(struct cfg *), sortpairs);
650
651         for (i = 0; i < ncfgs; ++i) {
652                 if (!Quiet)
653                         printf(_("* Applying %s ...\n"), cfgs[i]->value);
654                 rc |= Preload(cfgs[i]->value);
655         }
656
657
658         if (stat(DEFAULT_PRELOAD, &ts) < 0 || S_ISREG(ts.st_mode)) {
659                 if (!Quiet)
660                         printf(_("* Applying %s ...\n"), DEFAULT_PRELOAD);
661                 rc |= Preload(DEFAULT_PRELOAD);
662         }
663
664         /* cleaning */
665         for (i = 0; i < ncfgs; ++i) {
666                 free(cfgs[i]);
667         }
668         if (cfgs) free(cfgs);
669
670         return rc;
671 }
672
673 /*
674  * Main...
675  */
676 int main(int argc, char *argv[])
677 {
678         bool WriteMode = false;
679         bool DisplayAllOpt = false;
680         bool preloadfileOpt = false;
681         int ReturnCode = 0;
682         int c;
683         const char *preloadfile = NULL;
684
685         enum {
686                 DEPRECATED_OPTION = CHAR_MAX + 1,
687                 SYSTEM_OPTION
688         };
689         static const struct option longopts[] = {
690                 {"all", no_argument, NULL, 'a'},
691                 {"deprecated", no_argument, NULL, DEPRECATED_OPTION},
692                 {"binary", no_argument, NULL, 'b'},
693                 {"ignore", no_argument, NULL, 'e'},
694                 {"names", no_argument, NULL, 'N'},
695                 {"values", no_argument, NULL, 'n'},
696                 {"load", optional_argument, NULL, 'p'},
697                 {"quiet", no_argument, NULL, 'q'},
698                 {"write", no_argument, NULL, 'w'},
699                 {"system", no_argument, NULL, SYSTEM_OPTION},
700                 {"pattern", required_argument, NULL, 'r'},
701                 {"help", no_argument, NULL, 'h'},
702                 {"version", no_argument, NULL, 'V'},
703                 {NULL, 0, NULL, 0}
704         };
705
706 #ifdef HAVE_PROGRAM_INVOCATION_NAME
707         program_invocation_name = program_invocation_short_name;
708 #endif
709         setlocale(LC_ALL, "");
710         bindtextdomain(PACKAGE, LOCALEDIR);
711         textdomain(PACKAGE);
712         atexit(close_stdout);
713
714         PrintName = true;
715         PrintNewline = true;
716         IgnoreError = false;
717         Quiet = false;
718         IgnoreDeprecated = true;
719
720         if (argc < 2)
721                 Usage(stderr);
722
723         while ((c =
724                 getopt_long(argc, argv, "bneNwfp::qoxaAXr:Vdh", longopts,
725                             NULL)) != -1) {
726                 switch (c) {
727                 case 'b':
728                         /* This is "binary" format, which means more for BSD. */
729                         PrintNewline = false;
730                         /* FALL THROUGH */
731                 case 'n':
732                         PrintName = false;
733                         break;
734                 case 'e':
735                         /*
736                          * For FreeBSD, -e means a "%s=%s\n" format.
737                          * ("%s: %s\n" default). We (and NetBSD) use
738                          * "%s = %s\n" always, and -e to ignore errors.
739                          */
740                         IgnoreError = true;
741                         break;
742                 case 'N':
743                         NameOnly = true;
744                         break;
745                 case 'w':
746                         WriteMode = true;
747                         break;
748                 case 'f':       /* the NetBSD way */
749                 case 'p':
750                         preloadfileOpt = true;
751                         if (optarg)
752                                 preloadfile = optarg;
753                         break;
754                 case 'q':
755                         Quiet = true;
756                         break;
757                 case 'o':       /* BSD: binary values too, 1st 16 bytes in hex */
758                 case 'x':       /* BSD: binary values too, whole thing in hex */
759                         /* does nothing */ ;
760                         break;
761                 case 'a':       /* string and integer values (for Linux, all of them) */
762                 case 'A':       /* same as -a -o */
763                 case 'X':       /* same as -a -x */
764                         DisplayAllOpt = true;
765                         break;
766                 case DEPRECATED_OPTION:
767                         IgnoreDeprecated = false;
768                         break;
769                 case SYSTEM_OPTION:
770                         IgnoreError = true;
771                         return PreloadSystem();
772                 case 'r':
773                         pattern = xstrdup(optarg);
774                         break;
775                 case 'V':
776                         printf(PROCPS_NG_VERSION);
777                         return EXIT_SUCCESS;
778                 case 'd':       /* BSD: print description ("vm.kvm_size: Size of KVM") */
779                 case 'h':       /* BSD: human-readable (did FreeBSD 5 make -e default?) */
780                 case '?':
781                         Usage(stdout);
782                 default:
783                         Usage(stderr);
784                 }
785         }
786
787         argc -= optind;
788         argv += optind;
789
790         if (DisplayAllOpt)
791                 return DisplayAll(PROC_PATH);
792
793         if (preloadfileOpt) {
794                 int ret = EXIT_SUCCESS, i;
795                 if (!preloadfile) {
796                         if (!argc) {
797                                 ret |= Preload(DEFAULT_PRELOAD);
798                         }
799                 } else {
800                         /* This happens when -pfile option is
801                          * used without space. */
802                         ret |= Preload(preloadfile);
803                 }
804                 for (i = 0; i < argc; i++)
805                         ret |= Preload(argv[i]);
806                 return ret;
807         }
808
809         if (argc < 1)
810                 xerrx(EXIT_FAILURE, _("no variables specified\n"
811                                       "Try `%s --help' for more information."),
812                       program_invocation_short_name);
813         if (NameOnly && Quiet)
814                 xerrx(EXIT_FAILURE, _("options -N and -q cannot coexist\n"
815                                       "Try `%s --help' for more information."),
816                       program_invocation_short_name);
817
818         for ( ; *argv; argv++) {
819                 if (WriteMode || index(*argv, '='))
820                         ReturnCode += WriteSetting(*argv);
821                 else
822                         ReturnCode += ReadSetting(*argv);
823         }
824         return ReturnCode;
825 }