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