chiark / gitweb /
3ce506b0c64f6265e173ab4af3dbf10899300835
[elogind.git] / util.c
1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
2
3 #include <assert.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <errno.h>
7 #include <stdlib.h>
8 #include <signal.h>
9 #include <stdio.h>
10 #include <syslog.h>
11 #include <sched.h>
12 #include <sys/resource.h>
13
14 #include "macro.h"
15 #include "util.h"
16 #include "ioprio.h"
17 #include "missing.h"
18
19 usec_t now(clockid_t clock) {
20         struct timespec ts;
21
22         assert_se(clock_gettime(clock, &ts) == 0);
23
24         return timespec_load(&ts);
25 }
26
27 usec_t timespec_load(const struct timespec *ts) {
28         assert(ts);
29
30         return
31                 (usec_t) ts->tv_sec * USEC_PER_SEC +
32                 (usec_t) ts->tv_nsec / NSEC_PER_USEC;
33 }
34
35 struct timespec *timespec_store(struct timespec *ts, usec_t u)  {
36         assert(ts);
37
38         ts->tv_sec = (time_t) (u / USEC_PER_SEC);
39         ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
40
41         return ts;
42 }
43
44 usec_t timeval_load(const struct timeval *tv) {
45         assert(tv);
46
47         return
48                 (usec_t) tv->tv_sec * USEC_PER_SEC +
49                 (usec_t) tv->tv_usec;
50 }
51
52 struct timeval *timeval_store(struct timeval *tv, usec_t u) {
53         assert(tv);
54
55         tv->tv_sec = (time_t) (u / USEC_PER_SEC);
56         tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
57
58         return tv;
59 }
60
61 bool endswith(const char *s, const char *postfix) {
62         size_t sl, pl;
63
64         assert(s);
65         assert(postfix);
66
67         sl = strlen(s);
68         pl = strlen(postfix);
69
70         if (sl < pl)
71                 return false;
72
73         return memcmp(s + sl - pl, postfix, pl) == 0;
74 }
75
76 bool startswith(const char *s, const char *prefix) {
77         size_t sl, pl;
78
79         assert(s);
80         assert(prefix);
81
82         sl = strlen(s);
83         pl = strlen(prefix);
84
85         if (sl < pl)
86                 return false;
87
88         return memcmp(s, prefix, pl) == 0;
89 }
90
91 int close_nointr(int fd) {
92         assert(fd >= 0);
93
94         for (;;) {
95                 int r;
96
97                 if ((r = close(fd)) >= 0)
98                         return r;
99
100                 if (errno != EINTR)
101                         return r;
102         }
103 }
104
105 void close_nointr_nofail(int fd) {
106
107         /* like close_nointr() but cannot fail, and guarantees errno
108          * is unchanged */
109
110         assert_se(close_nointr(fd) == 0);
111 }
112
113 int parse_boolean(const char *v) {
114         assert(v);
115
116         if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
117                 return 1;
118         else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
119                 return 0;
120
121         return -EINVAL;
122 }
123
124 int safe_atou(const char *s, unsigned *ret_u) {
125         char *x = NULL;
126         unsigned long l;
127
128         assert(s);
129         assert(ret_u);
130
131         errno = 0;
132         l = strtoul(s, &x, 0);
133
134         if (!x || *x || errno)
135                 return errno ? -errno : -EINVAL;
136
137         if ((unsigned long) (unsigned) l != l)
138                 return -ERANGE;
139
140         *ret_u = (unsigned) l;
141         return 0;
142 }
143
144 int safe_atoi(const char *s, int *ret_i) {
145         char *x = NULL;
146         long l;
147
148         assert(s);
149         assert(ret_i);
150
151         errno = 0;
152         l = strtol(s, &x, 0);
153
154         if (!x || *x || errno)
155                 return errno ? -errno : -EINVAL;
156
157         if ((long) (int) l != l)
158                 return -ERANGE;
159
160         *ret_i = (int) l;
161         return 0;
162 }
163
164 int safe_atolu(const char *s, long unsigned *ret_lu) {
165         char *x = NULL;
166         unsigned long l;
167
168         assert(s);
169         assert(ret_lu);
170
171         errno = 0;
172         l = strtoul(s, &x, 0);
173
174         if (!x || *x || errno)
175                 return errno ? -errno : -EINVAL;
176
177         *ret_lu = l;
178         return 0;
179 }
180
181 int safe_atoli(const char *s, long int *ret_li) {
182         char *x = NULL;
183         long l;
184
185         assert(s);
186         assert(ret_li);
187
188         errno = 0;
189         l = strtol(s, &x, 0);
190
191         if (!x || *x || errno)
192                 return errno ? -errno : -EINVAL;
193
194         *ret_li = l;
195         return 0;
196 }
197
198 int safe_atollu(const char *s, long long unsigned *ret_llu) {
199         char *x = NULL;
200         unsigned long long l;
201
202         assert(s);
203         assert(ret_llu);
204
205         errno = 0;
206         l = strtoull(s, &x, 0);
207
208         if (!x || *x || errno)
209                 return errno ? -errno : -EINVAL;
210
211         *ret_llu = l;
212         return 0;
213 }
214
215 int safe_atolli(const char *s, long long int *ret_lli) {
216         char *x = NULL;
217         long long l;
218
219         assert(s);
220         assert(ret_lli);
221
222         errno = 0;
223         l = strtoll(s, &x, 0);
224
225         if (!x || *x || errno)
226                 return errno ? -errno : -EINVAL;
227
228         *ret_lli = l;
229         return 0;
230 }
231
232 /* Split a string into words. */
233 char *split_spaces(const char *c, size_t *l, char **state) {
234         char *current;
235
236         current = *state ? *state : (char*) c;
237
238         if (!*current || *c == 0)
239                 return NULL;
240
241         current += strspn(current, WHITESPACE);
242         *l = strcspn(current, WHITESPACE);
243         *state = current+*l;
244
245         return (char*) current;
246 }
247
248 /* Split a string into words, but consider strings enclosed in '' and
249  * "" as words even if they include spaces. */
250 char *split_quoted(const char *c, size_t *l, char **state) {
251         char *current;
252
253         current = *state ? *state : (char*) c;
254
255         if (!*current || *c == 0)
256                 return NULL;
257
258         current += strspn(current, WHITESPACE);
259
260         if (*current == '\'') {
261                 current ++;
262                 *l = strcspn(current, "'");
263                 *state = current+*l;
264
265                 if (**state == '\'')
266                         (*state)++;
267         } else if (*current == '\"') {
268                 current ++;
269                 *l = strcspn(current, "\"");
270                 *state = current+*l;
271
272                 if (**state == '\"')
273                         (*state)++;
274         } else {
275                 *l = strcspn(current, WHITESPACE);
276                 *state = current+*l;
277         }
278
279         /* FIXME: Cannot deal with strings that have spaces AND ticks
280          * in them */
281
282         return (char*) current;
283 }
284
285 int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
286         int r;
287         FILE *f;
288         char fn[132], line[256], *p;
289         long long unsigned ppid;
290
291         assert(pid >= 0);
292         assert(_ppid);
293
294         assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%llu/stat", (unsigned long long) pid) < (int) (sizeof(fn)-1));
295         fn[sizeof(fn)-1] = 0;
296
297         if (!(f = fopen(fn, "r")))
298                 return -errno;
299
300         if (!(fgets(line, sizeof(line), f))) {
301                 r = -errno;
302                 fclose(f);
303                 return r;
304         }
305
306         fclose(f);
307
308         /* Let's skip the pid and comm fields. The latter is enclosed
309          * in () but does not escape any () in its value, so let's
310          * skip over it manually */
311
312         if (!(p = strrchr(line, ')')))
313                 return -EIO;
314
315         p++;
316
317         if (sscanf(p, " "
318                    "%*c "  /* state */
319                    "%llu ", /* ppid */
320                    &ppid) != 1)
321                 return -EIO;
322
323         if ((long long unsigned) (pid_t) ppid != ppid)
324                 return -ERANGE;
325
326         *_ppid = (pid_t) ppid;
327
328         return 0;
329 }
330
331 int write_one_line_file(const char *fn, const char *line) {
332         FILE *f;
333         int r;
334
335         assert(fn);
336         assert(line);
337
338         if (!(f = fopen(fn, "we")))
339                 return -errno;
340
341         if (fputs(line, f) < 0) {
342                 r = -errno;
343                 goto finish;
344         }
345
346         r = 0;
347 finish:
348         fclose(f);
349         return r;
350 }
351
352 int read_one_line_file(const char *fn, char **line) {
353         FILE *f;
354         int r;
355         char t[64], *c;
356
357         assert(fn);
358         assert(line);
359
360         if (!(f = fopen(fn, "re")))
361                 return -errno;
362
363         if (!(fgets(t, sizeof(t), f))) {
364                 r = -errno;
365                 goto finish;
366         }
367
368         if (!(c = strdup(t))) {
369                 r = -ENOMEM;
370                 goto finish;
371         }
372
373         *line = c;
374         r = 0;
375
376 finish:
377         fclose(f);
378         return r;
379 }
380
381 char *strappend(const char *s, const char *suffix) {
382         size_t a, b;
383         char *r;
384
385         assert(s);
386         assert(suffix);
387
388         a = strlen(s);
389         b = strlen(suffix);
390
391         if (!(r = new(char, a+b+1)))
392                 return NULL;
393
394         memcpy(r, s, a);
395         memcpy(r+a, suffix, b);
396         r[a+b] = 0;
397
398         return r;
399 }
400
401 int readlink_malloc(const char *p, char **r) {
402         size_t l = 100;
403
404         assert(p);
405         assert(r);
406
407         for (;;) {
408                 char *c;
409                 ssize_t n;
410
411                 if (!(c = new(char, l)))
412                         return -ENOMEM;
413
414                 if ((n = readlink(p, c, l-1)) < 0) {
415                         int ret = -errno;
416                         free(c);
417                         return ret;
418                 }
419
420                 if ((size_t) n < l-1) {
421                         c[n] = 0;
422                         *r = c;
423                         return 0;
424                 }
425
426                 free(c);
427                 l *= 2;
428         }
429 }
430
431 char *file_name_from_path(const char *p) {
432         char *r;
433
434         assert(p);
435
436         if ((r = strrchr(p, '/')))
437                 return r + 1;
438
439         return (char*) p;
440 }
441
442 bool path_is_absolute(const char *p) {
443         assert(p);
444
445         return p[0] == '/';
446 }
447
448 bool is_path(const char *p) {
449
450         return !!strchr(p, '/');
451 }
452
453 char *path_make_absolute(const char *p, const char *prefix) {
454         char *r;
455
456         assert(p);
457
458         if (path_is_absolute(p) || !prefix)
459                 return strdup(p);
460
461         if (asprintf(&r, "%s/%s", prefix, p) < 0)
462                 return NULL;
463
464         return r;
465 }
466
467 int reset_all_signal_handlers(void) {
468         int sig;
469
470         for (sig = 1; sig < _NSIG; sig++) {
471                 struct sigaction sa;
472
473                 if (sig == SIGKILL || sig == SIGSTOP)
474                         continue;
475
476                 zero(sa);
477                 sa.sa_handler = SIG_DFL;
478                 sa.sa_flags = SA_RESTART;
479
480                 /* On Linux the first two RT signals are reserved by
481                  * glibc, and sigaction() will return EINVAL for them. */
482                 if ((sigaction(sig, &sa, NULL) < 0))
483                         if (errno != EINVAL)
484                                 return -errno;
485         }
486
487     return 0;
488 }
489
490 char *strstrip(char *s) {
491         char *e, *l = NULL;
492
493         /* Drops trailing whitespace. Modifies the string in
494          * place. Returns pointer to first non-space character */
495
496         s += strspn(s, WHITESPACE);
497
498         for (e = s; *e; e++)
499                 if (!strchr(WHITESPACE, *e))
500                         l = e;
501
502         if (l)
503                 *(l+1) = 0;
504         else
505                 *s = 0;
506
507         return s;
508
509 }
510
511 char *file_in_same_dir(const char *path, const char *filename) {
512         char *e, *r;
513         size_t k;
514
515         assert(path);
516         assert(filename);
517
518         /* This removes the last component of path and appends
519          * filename, unless the latter is absolute anyway or the
520          * former isn't */
521
522         if (path_is_absolute(filename))
523                 return strdup(filename);
524
525         if (!(e = strrchr(path, '/')))
526                 return strdup(filename);
527
528         k = strlen(filename);
529         if (!(r = new(char, e-path+1+k+1)))
530                 return NULL;
531
532         memcpy(r, path, e-path+1);
533         memcpy(r+(e-path)+1, filename, k+1);
534
535         return r;
536 }
537
538 char hexchar(int x) {
539         static const char table[16] = "0123456789abcdef";
540
541         return table[x & 15];
542 }
543
544 int unhexchar(char c) {
545
546         if (c >= '0' && c <= '9')
547                 return c - '0';
548
549         if (c >= 'a' && c <= 'f')
550                 return c - 'a';
551
552         if (c >= 'A' && c <= 'F')
553                 return c - 'A';
554
555         return -1;
556 }
557
558 char octchar(int x) {
559         return '0' + (x & 7);
560 }
561
562 int unoctchar(char c) {
563
564         if (c >= '0' && c <= '7')
565                 return c - '0';
566
567         return -1;
568 }
569
570 char *cescape(const char *s) {
571         char *r, *t;
572         const char *f;
573
574         assert(s);
575
576         /* Does C style string escaping. */
577
578         if (!(r = new(char, strlen(s)*4 + 1)))
579                 return NULL;
580
581         for (f = s, t = r; *f; f++)
582
583                 switch (*f) {
584
585                 case '\a':
586                         *(t++) = '\\';
587                         *(t++) = 'a';
588                         break;
589                 case '\b':
590                         *(t++) = '\\';
591                         *(t++) = 'b';
592                         break;
593                 case '\f':
594                         *(t++) = '\\';
595                         *(t++) = 'f';
596                         break;
597                 case '\n':
598                         *(t++) = '\\';
599                         *(t++) = 'n';
600                         break;
601                 case '\r':
602                         *(t++) = '\\';
603                         *(t++) = 'r';
604                         break;
605                 case '\t':
606                         *(t++) = '\\';
607                         *(t++) = 't';
608                         break;
609                 case '\v':
610                         *(t++) = '\\';
611                         *(t++) = 'v';
612                         break;
613                 case '\\':
614                         *(t++) = '\\';
615                         *(t++) = '\\';
616                         break;
617                 case '"':
618                         *(t++) = '\\';
619                         *(t++) = '"';
620                         break;
621                 case '\'':
622                         *(t++) = '\\';
623                         *(t++) = '\'';
624                         break;
625
626                 default:
627                         /* For special chars we prefer octal over
628                          * hexadecimal encoding, simply because glib's
629                          * g_strescape() does the same */
630                         if ((*f < ' ') || (*f >= 127)) {
631                                 *(t++) = '\\';
632                                 *(t++) = octchar((unsigned char) *f >> 6);
633                                 *(t++) = octchar((unsigned char) *f >> 3);
634                                 *(t++) = octchar((unsigned char) *f);
635                         } else
636                                 *(t++) = *f;
637                         break;
638                 }
639
640         *t = 0;
641
642         return r;
643 }
644
645 char *cunescape(const char *s) {
646         char *r, *t;
647         const char *f;
648
649         assert(s);
650
651         /* Undoes C style string escaping */
652
653         if (!(r = new(char, strlen(s)+1)))
654                 return r;
655
656         for (f = s, t = r; *f; f++) {
657
658                 if (*f != '\\') {
659                         *(t++) = *f;
660                         continue;
661                 }
662
663                 f++;
664
665                 switch (*f) {
666
667                 case 'a':
668                         *(t++) = '\a';
669                         break;
670                 case 'b':
671                         *(t++) = '\b';
672                         break;
673                 case 'f':
674                         *(t++) = '\f';
675                         break;
676                 case 'n':
677                         *(t++) = '\n';
678                         break;
679                 case 'r':
680                         *(t++) = '\r';
681                         break;
682                 case 't':
683                         *(t++) = '\t';
684                         break;
685                 case 'v':
686                         *(t++) = '\v';
687                         break;
688                 case '\\':
689                         *(t++) = '\\';
690                         break;
691                 case '"':
692                         *(t++) = '"';
693                         break;
694                 case '\'':
695                         *(t++) = '\'';
696                         break;
697
698                 case 'x': {
699                         /* hexadecimal encoding */
700                         int a, b;
701
702                         if ((a = unhexchar(f[1])) < 0 ||
703                             (b = unhexchar(f[2])) < 0) {
704                                 /* Invalid escape code, let's take it literal then */
705                                 *(t++) = '\\';
706                                 *(t++) = 'x';
707                         } else {
708                                 *(t++) = (char) ((a << 4) | b);
709                                 f += 2;
710                         }
711
712                         break;
713                 }
714
715                 case '0':
716                 case '1':
717                 case '2':
718                 case '3':
719                 case '4':
720                 case '5':
721                 case '6':
722                 case '7': {
723                         /* octal encoding */
724                         int a, b, c;
725
726                         if ((a = unoctchar(f[0])) < 0 ||
727                             (b = unoctchar(f[1])) < 0 ||
728                             (c = unoctchar(f[2])) < 0) {
729                                 /* Invalid escape code, let's take it literal then */
730                                 *(t++) = '\\';
731                                 *(t++) = f[0];
732                         } else {
733                                 *(t++) = (char) ((a << 6) | (b << 3) | c);
734                                 f += 2;
735                         }
736
737                         break;
738                 }
739
740                 case 0:
741                         /* premature end of string.*/
742                         *(t++) = '\\';
743                         goto finish;
744
745                 default:
746                         /* Invalid escape code, let's take it literal then */
747                         *(t++) = '\\';
748                         *(t++) = 'f';
749                         break;
750                 }
751         }
752
753 finish:
754         *t = 0;
755         return r;
756 }
757
758
759 char *xescape(const char *s, const char *bad) {
760         char *r, *t;
761         const char *f;
762
763         /* Escapes all chars in bad, in addition to \ and all special
764          * chars, in \xFF style escaping. May be reversed with
765          * cunescape. */
766
767         if (!(r = new(char, strlen(s)*4+1)))
768                 return NULL;
769
770         for (f = s, t = r; *f; f++) {
771
772                 if (*f < ' ' || *f >= 127 ||
773                     *f == '\\' || strchr(bad, *f)) {
774                         *(t++) = '\\';
775                         *(t++) = 'x';
776                         *(t++) = hexchar(*f >> 4);
777                         *(t++) = hexchar(*f);
778                 } else
779                         *(t++) = *f;
780         }
781
782         *t = 0;
783
784         return r;
785 }
786
787 char *path_kill_slashes(char *path) {
788         char *f, *t;
789         bool slash = false;
790
791         /* Removes redundant inner and trailing slashes. Modifies the
792          * passed string in-place.
793          *
794          * ///foo///bar/ becomes /foo/bar
795          */
796
797         for (f = path, t = path; *f; f++) {
798
799                 if (*f == '/') {
800                         slash = true;
801                         continue;
802                 }
803
804                 if (slash) {
805                         slash = false;
806                         *(t++) = '/';
807                 }
808
809                 *(t++) = *f;
810         }
811
812         /* Special rule, if we are talking of the root directory, a
813         trailing slash is good */
814
815         if (t == path && slash)
816                 *(t++) = '/';
817
818         *t = 0;
819         return path;
820 }
821
822 bool path_startswith(const char *path, const char *prefix) {
823         assert(path);
824         assert(prefix);
825
826         if ((path[0] == '/') != (prefix[0] == '/'))
827                 return false;
828
829         for (;;) {
830                 size_t a, b;
831
832                 path += strspn(path, "/");
833                 prefix += strspn(prefix, "/");
834
835                 if (*prefix == 0)
836                         return true;
837
838                 if (*path == 0)
839                         return false;
840
841                 a = strcspn(path, "/");
842                 b = strcspn(prefix, "/");
843
844                 if (a != b)
845                         return false;
846
847                 if (memcmp(path, prefix, a) != 0)
848                         return false;
849
850                 path += a;
851                 prefix += b;
852         }
853 }
854
855 char *ascii_strlower(char *path) {
856         char *p;
857
858         assert(path);
859
860         for (p = path; *p; p++)
861                 if (*p >= 'A' && *p <= 'Z')
862                         *p = *p - 'A' + 'a';
863
864         return p;
865 }
866
867 static const char *const ioprio_class_table[] = {
868         [IOPRIO_CLASS_NONE] = "none",
869         [IOPRIO_CLASS_RT] = "realtime",
870         [IOPRIO_CLASS_BE] = "best-effort",
871         [IOPRIO_CLASS_IDLE] = "idle"
872 };
873
874 DEFINE_STRING_TABLE_LOOKUP(ioprio_class, int);
875
876 static const char *const sigchld_code_table[] = {
877         [CLD_EXITED] = "exited",
878         [CLD_KILLED] = "killed",
879         [CLD_DUMPED] = "dumped",
880         [CLD_TRAPPED] = "trapped",
881         [CLD_STOPPED] = "stopped",
882         [CLD_CONTINUED] = "continued",
883 };
884
885 DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
886
887 static const char *const log_facility_table[LOG_NFACILITIES] = {
888         [LOG_FAC(LOG_KERN)] = "kern",
889         [LOG_FAC(LOG_USER)] = "user",
890         [LOG_FAC(LOG_MAIL)] = "mail",
891         [LOG_FAC(LOG_DAEMON)] = "daemon",
892         [LOG_FAC(LOG_AUTH)] = "auth",
893         [LOG_FAC(LOG_SYSLOG)] = "syslog",
894         [LOG_FAC(LOG_LPR)] = "lpr",
895         [LOG_FAC(LOG_NEWS)] = "news",
896         [LOG_FAC(LOG_UUCP)] = "uucp",
897         [LOG_FAC(LOG_CRON)] = "cron",
898         [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
899         [LOG_FAC(LOG_FTP)] = "ftp",
900         [LOG_FAC(LOG_LOCAL0)] = "local0",
901         [LOG_FAC(LOG_LOCAL1)] = "local1",
902         [LOG_FAC(LOG_LOCAL2)] = "local2",
903         [LOG_FAC(LOG_LOCAL3)] = "local3",
904         [LOG_FAC(LOG_LOCAL4)] = "local4",
905         [LOG_FAC(LOG_LOCAL5)] = "local5",
906         [LOG_FAC(LOG_LOCAL6)] = "local6",
907         [LOG_FAC(LOG_LOCAL7)] = "local7"
908 };
909
910 DEFINE_STRING_TABLE_LOOKUP(log_facility, int);
911
912 static const char *const log_level_table[] = {
913         [LOG_EMERG] = "emerg",
914         [LOG_ALERT] = "alert",
915         [LOG_CRIT] = "crit",
916         [LOG_ERR] = "err",
917         [LOG_WARNING] = "warning",
918         [LOG_NOTICE] = "notice",
919         [LOG_INFO] = "info",
920         [LOG_DEBUG] = "debug"
921 };
922
923 DEFINE_STRING_TABLE_LOOKUP(log_level, int);
924
925 static const char* const sched_policy_table[] = {
926         [SCHED_OTHER] = "other",
927         [SCHED_BATCH] = "batch",
928         [SCHED_IDLE] = "idle",
929         [SCHED_FIFO] = "fifo",
930         [SCHED_RR] = "rr"
931 };
932
933 DEFINE_STRING_TABLE_LOOKUP(sched_policy, int);
934
935 static const char* const rlimit_table[] = {
936         [RLIMIT_CPU] = "LimitCPU",
937         [RLIMIT_FSIZE] = "LimitFSIZE",
938         [RLIMIT_DATA] = "LimitDATA",
939         [RLIMIT_STACK] = "LimitSTACK",
940         [RLIMIT_CORE] = "LimitCORE",
941         [RLIMIT_RSS] = "LimitRSS",
942         [RLIMIT_NOFILE] = "LimitNOFILE",
943         [RLIMIT_AS] = "LimitAS",
944         [RLIMIT_NPROC] = "LimitNPROC",
945         [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
946         [RLIMIT_LOCKS] = "LimitLOCKS",
947         [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
948         [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
949         [RLIMIT_NICE] = "LimitNICE",
950         [RLIMIT_RTPRIO] = "LimitRTPRIO",
951         [RLIMIT_RTTIME] = "LimitRTTIME"
952 };
953
954 DEFINE_STRING_TABLE_LOOKUP(rlimit, int);