~ubuntu-branches/ubuntu/vivid/util-linux/vivid

« back to all changes in this revision

Viewing changes to sys-utils/prlimit.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2014-08-18 15:43:56 UTC
  • mfrom: (1.6.5) (4.1.16 experimental)
  • Revision ID: package-import@ubuntu.com-20140818154356-sqn436j3vndc62qb
Tags: 2.25-8ubuntu1
* Merge with Debian experimental.
  - This is now a non-ancient version. (LP: #1012081)
  - No longer uses /etc/blkid.tab by default, but a file in /run/.
    (LP: #1244595)
  - mkswap wipes fs signatures (LP: #1047666)
  - Fix "reatime" manpage typo (LP: #1047666)
  - wipefs properly cleans up fs signatures (LP: #1059872)
  Remaining Ubuntu changes:
  - Regularly trim SSDs automatically (core-1311-ssd-trimming):
    + Add debian/fstrim-all: Script to detect which mounted partitions
      need/support trimming, and call fstrim(8) on all of them.
      Install into /usr/sbin/.
    + Add debian/fstrim-all.8: Manpage for the above.
    + Add debian/fstrim-all.cron: Trivial shell script to call fstrim-all,
      so that admins can easily adjust/disable it. Installed as
      /etc/cron.weekly/fstrim.
  - Upstart support:
    + Add hwclock{-save}.upstart, and install them in debian/rules.
    + Drop initscripts dependency.
    + Drop debian/hwclock.rules and hwclock.default.
  - Add mountall-options.patch, see patch header.
  - uuid-runtime.postinst: Due to the way the uuidd account is created, it
    will get a uid/gid allocation for userns use. This isn't needed and is a
    waste of uid/gid so always clear uuidd from subuid/subgid.
* Drop /lib/init/fstab parsing fallback in mount. Patch does not apply at
  all any more, is specific to mountall (and thus should not be relied
  upon), and not very useful; all init systems, schroot, debootstrap etc.
  mount /sys, /proc/ and friends by themselves already.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  prlimit - get/set process resource limits.
 
3
 *
 
4
 *  Copyright (C) 2011 Davidlohr Bueso <dave@gnu.org>
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; either version 2 of the License, or
 
9
 *  (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 along
 
17
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 
18
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
19
 */
 
20
 
 
21
#include <errno.h>
 
22
#include <getopt.h>
 
23
#include <stdio.h>
 
24
#include <stdlib.h>
 
25
#include <ctype.h>
 
26
#include <assert.h>
 
27
#include <unistd.h>
 
28
#include <sys/resource.h>
 
29
 
 
30
#include <libsmartcols.h>
 
31
 
 
32
#include "c.h"
 
33
#include "nls.h"
 
34
#include "xalloc.h"
 
35
#include "strutils.h"
 
36
#include "list.h"
 
37
#include "closestream.h"
 
38
 
 
39
#ifndef RLIMIT_RTTIME
 
40
# define RLIMIT_RTTIME 15
 
41
#endif
 
42
 
 
43
enum {
 
44
        AS,
 
45
        CORE,
 
46
        CPU,
 
47
        DATA,
 
48
        FSIZE,
 
49
        LOCKS,
 
50
        MEMLOCK,
 
51
        MSGQUEUE,
 
52
        NICE,
 
53
        NOFILE,
 
54
        NPROC,
 
55
        RSS,
 
56
        RTPRIO,
 
57
        RTTIME,
 
58
        SIGPENDING,
 
59
        STACK
 
60
};
 
61
 
 
62
/* basic output flags */
 
63
static int no_headings;
 
64
static int raw;
 
65
 
 
66
struct prlimit_desc {
 
67
        const char *name;
 
68
        const char *help;
 
69
        const char *unit;
 
70
        int resource;
 
71
};
 
72
 
 
73
static struct prlimit_desc prlimit_desc[] =
 
74
{
 
75
        [AS]         = { "AS",         N_("address space limit"),                N_("bytes"),     RLIMIT_AS },
 
76
        [CORE]       = { "CORE",       N_("max core file size"),                 N_("blocks"),    RLIMIT_CORE },
 
77
        [CPU]        = { "CPU",        N_("CPU time"),                           N_("seconds"),   RLIMIT_CPU },
 
78
        [DATA]       = { "DATA",       N_("max data size"),                      N_("bytes"),     RLIMIT_DATA },
 
79
        [FSIZE]      = { "FSIZE",      N_("max file size"),                      N_("blocks"),    RLIMIT_FSIZE },
 
80
        [LOCKS]      = { "LOCKS",      N_("max number of file locks held"),      NULL,            RLIMIT_LOCKS },
 
81
        [MEMLOCK]    = { "MEMLOCK",    N_("max locked-in-memory address space"), N_("bytes"),     RLIMIT_MEMLOCK },
 
82
        [MSGQUEUE]   = { "MSGQUEUE",   N_("max bytes in POSIX mqueues"),         N_("bytes"),     RLIMIT_MSGQUEUE },
 
83
        [NICE]       = { "NICE",       N_("max nice prio allowed to raise"),     NULL,            RLIMIT_NICE },
 
84
        [NOFILE]     = { "NOFILE",     N_("max number of open files"),           NULL,            RLIMIT_NOFILE },
 
85
        [NPROC]      = { "NPROC",      N_("max number of processes"),            NULL,            RLIMIT_NPROC },
 
86
        [RSS]        = { "RSS",        N_("max resident set size"),              N_("pages"),     RLIMIT_RSS },
 
87
        [RTPRIO]     = { "RTPRIO",     N_("max real-time priority"),             NULL,            RLIMIT_RTPRIO },
 
88
        [RTTIME]     = { "RTTIME",     N_("timeout for real-time tasks"),        N_("microsecs"), RLIMIT_RTTIME },
 
89
        [SIGPENDING] = { "SIGPENDING", N_("max number of pending signals"),      NULL,            RLIMIT_SIGPENDING },
 
90
        [STACK]      = { "STACK",      N_("max stack size"),                     N_("bytes"),     RLIMIT_STACK }
 
91
};
 
92
 
 
93
#define MAX_RESOURCES ARRAY_SIZE(prlimit_desc)
 
94
 
 
95
struct prlimit {
 
96
        struct list_head lims;
 
97
 
 
98
        struct rlimit rlim;
 
99
        struct prlimit_desc *desc;
 
100
        int modify;                     /* PRLIMIT_{SOFT,HARD} mask */
 
101
};
 
102
 
 
103
#define PRLIMIT_EMPTY_LIMIT     {{ 0, 0, }, NULL, 0 }
 
104
 
 
105
enum {
 
106
        COL_HELP,
 
107
        COL_RES,
 
108
        COL_SOFT,
 
109
        COL_HARD,
 
110
        COL_UNITS,
 
111
};
 
112
 
 
113
/* column names */
 
114
struct colinfo {
 
115
        const char      *name;  /* header */
 
116
        double          whint;  /* width hint (N < 1 is in percent of termwidth) */
 
117
        int             flags;  /* SCOLS_FL_* */
 
118
        const char      *help;
 
119
};
 
120
 
 
121
/* columns descriptions */
 
122
struct colinfo infos[] = {
 
123
        [COL_RES]     = { "RESOURCE",    0.25, SCOLS_FL_TRUNC, N_("resource name") },
 
124
        [COL_HELP]    = { "DESCRIPTION", 0.1,  SCOLS_FL_TRUNC, N_("resource description")},
 
125
        [COL_SOFT]    = { "SOFT",        0.1,  SCOLS_FL_RIGHT, N_("soft limit")},
 
126
        [COL_HARD]    = { "HARD",        1,    SCOLS_FL_RIGHT, N_("hard limit (ceiling)")},
 
127
        [COL_UNITS]   = { "UNITS",       0.1,  SCOLS_FL_TRUNC, N_("units")},
 
128
};
 
129
 
 
130
static int columns[ARRAY_SIZE(infos) * 2];
 
131
static int ncolumns;
 
132
 
 
133
 
 
134
 
 
135
#define INFINITY_STR    "unlimited"
 
136
#define INFINITY_STRLEN (sizeof(INFINITY_STR) - 1)
 
137
 
 
138
#define PRLIMIT_SOFT    (1 << 1)
 
139
#define PRLIMIT_HARD    (1 << 2)
 
140
 
 
141
static pid_t pid; /* calling process (default) */
 
142
static int verbose;
 
143
 
 
144
#ifndef HAVE_PRLIMIT
 
145
# include <sys/syscall.h>
 
146
static int prlimit(pid_t p, int resource,
 
147
                   const struct rlimit *new_limit,
 
148
                   struct rlimit *old_limit)
 
149
{
 
150
        return syscall(SYS_prlimit64, p, resource, new_limit, old_limit);
 
151
}
 
152
#endif
 
153
 
 
154
static void __attribute__ ((__noreturn__)) usage(FILE * out)
 
155
{
 
156
        size_t i;
 
157
 
 
158
        fputs(USAGE_HEADER, out);
 
159
 
 
160
        fprintf(out,
 
161
                _(" %s [options] [-p PID]\n"), program_invocation_short_name);
 
162
        fprintf(out,
 
163
                _(" %s [options] COMMAND\n"), program_invocation_short_name);
 
164
 
 
165
        fputs(_("\nGeneral Options:\n"), out);
 
166
        fputs(_(" -p, --pid <pid>        process id\n"
 
167
                " -o, --output <list>    define which output columns to use\n"
 
168
                "     --noheadings       don't print headings\n"
 
169
                "     --raw              use the raw output format\n"
 
170
                "     --verbose          verbose output\n"
 
171
                " -h, --help             display this help and exit\n"
 
172
                " -V, --version          output version information and exit\n"), out);
 
173
 
 
174
        fputs(_("\nResources Options:\n"), out);
 
175
        fputs(_(" -c, --core             maximum size of core files created\n"
 
176
                " -d, --data             maximum size of a process's data segment\n"
 
177
                " -e, --nice             maximum nice priority allowed to raise\n"
 
178
                " -f, --fsize            maximum size of files written by the process\n"
 
179
                " -i, --sigpending       maximum number of pending signals\n"
 
180
                " -l, --memlock          maximum size a process may lock into memory\n"
 
181
                " -m, --rss              maximum resident set size\n"
 
182
                " -n, --nofile           maximum number of open files\n"
 
183
                " -q, --msgqueue         maximum bytes in POSIX message queues\n"
 
184
                " -r, --rtprio           maximum real-time scheduling priority\n"
 
185
                " -s, --stack            maximum stack size\n"
 
186
                " -t, --cpu              maximum amount of CPU time in seconds\n"
 
187
                " -u, --nproc            maximum number of user processes\n"
 
188
                " -v, --as               size of virtual memory\n"
 
189
                " -x, --locks            maximum number of file locks\n"
 
190
                " -y, --rttime           CPU time in microseconds a process scheduled\n"
 
191
                "                        under real-time scheduling\n"), out);
 
192
 
 
193
        fputs(_("\nAvailable columns (for --output):\n"), out);
 
194
 
 
195
        for (i = 0; i < ARRAY_SIZE(infos); i++)
 
196
                fprintf(out, " %11s  %s\n", infos[i].name, _(infos[i].help));
 
197
 
 
198
        fprintf(out, USAGE_MAN_TAIL("prlimit(1)"));
 
199
 
 
200
        exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
 
201
}
 
202
 
 
203
static inline int get_column_id(int num)
 
204
{
 
205
        assert(num < ncolumns);
 
206
        assert(columns[num] < (int) ARRAY_SIZE(infos));
 
207
 
 
208
        return columns[num];
 
209
}
 
210
 
 
211
static inline struct colinfo *get_column_info(unsigned num)
 
212
{
 
213
        return &infos[ get_column_id(num) ];
 
214
}
 
215
 
 
216
static void add_scols_line(struct libscols_table *table, struct prlimit *l)
 
217
{
 
218
        int i;
 
219
        struct libscols_line *line;
 
220
 
 
221
        assert(table);
 
222
        assert(l);
 
223
 
 
224
        line = scols_table_new_line(table, NULL);
 
225
        if (!line)
 
226
                err(EXIT_FAILURE, _("failed to initialize output line"));
 
227
 
 
228
        for (i = 0; i < ncolumns; i++) {
 
229
                char *str = NULL;
 
230
 
 
231
                switch (get_column_id(i)) {
 
232
                case COL_RES:
 
233
                        str = xstrdup(l->desc->name);
 
234
                        break;
 
235
                case COL_HELP:
 
236
                        str = xstrdup(l->desc->help);
 
237
                        break;
 
238
                case COL_SOFT:
 
239
                        if (l->rlim.rlim_cur == RLIM_INFINITY)
 
240
                                str = xstrdup(_("unlimited"));
 
241
                        else
 
242
                                xasprintf(&str, "%llu", (unsigned long long) l->rlim.rlim_cur);
 
243
                        break;
 
244
                case COL_HARD:
 
245
                        if (l->rlim.rlim_max == RLIM_INFINITY)
 
246
                                str = xstrdup(_("unlimited"));
 
247
                        else
 
248
                                xasprintf(&str, "%llu", (unsigned long long) l->rlim.rlim_max);
 
249
                        break;
 
250
                case COL_UNITS:
 
251
                        str = l->desc->unit ? xstrdup(_(l->desc->unit)) : NULL;
 
252
                        break;
 
253
                default:
 
254
                        break;
 
255
                }
 
256
 
 
257
                if (str)
 
258
                        scols_line_refer_data(line, i, str);
 
259
        }
 
260
}
 
261
 
 
262
static int column_name_to_id(const char *name, size_t namesz)
 
263
{
 
264
        size_t i;
 
265
 
 
266
        assert(name);
 
267
 
 
268
        for (i = 0; i < ARRAY_SIZE(infos); i++) {
 
269
                const char *cn = infos[i].name;
 
270
 
 
271
                if (!strncasecmp(name, cn, namesz) && !*(cn + namesz))
 
272
                        return i;
 
273
        }
 
274
        warnx(_("unknown column: %s"), name);
 
275
        return -1;
 
276
}
 
277
 
 
278
static void rem_prlim(struct prlimit *lim)
 
279
{
 
280
        if (!lim)
 
281
                return;
 
282
        list_del(&lim->lims);
 
283
        free(lim);
 
284
}
 
285
 
 
286
static int show_limits(struct list_head *lims)
 
287
{
 
288
        int i;
 
289
        struct list_head *p, *pnext;
 
290
        struct libscols_table *table;
 
291
 
 
292
        table = scols_new_table();
 
293
        if (!table)
 
294
                err(EXIT_FAILURE, _("failed to initialize output table"));
 
295
 
 
296
        scols_table_enable_raw(table, raw);
 
297
        scols_table_enable_noheadings(table, no_headings);
 
298
 
 
299
        for (i = 0; i < ncolumns; i++) {
 
300
                struct colinfo *col = get_column_info(i);
 
301
 
 
302
                if (!scols_table_new_column(table, col->name, col->whint, col->flags))
 
303
                        err(EXIT_FAILURE, _("failed to initialize output column"));
 
304
        }
 
305
 
 
306
 
 
307
        list_for_each_safe(p, pnext, lims) {
 
308
                struct prlimit *lim = list_entry(p, struct prlimit, lims);
 
309
 
 
310
                add_scols_line(table, lim);
 
311
                rem_prlim(lim);
 
312
        }
 
313
 
 
314
        scols_print_table(table);
 
315
        scols_unref_table(table);
 
316
        return 0;
 
317
}
 
318
 
 
319
/*
 
320
 * If one of the limits is unknown (default value for not being passed), we
 
321
 * need to get the current limit and use it.  I see no other way other than
 
322
 * using prlimit(2).
 
323
 */
 
324
static void get_unknown_hardsoft(struct prlimit *lim)
 
325
{
 
326
        struct rlimit old;
 
327
 
 
328
        if (prlimit(pid, lim->desc->resource, NULL, &old) == -1)
 
329
                err(EXIT_FAILURE, _("failed to get old %s limit"),
 
330
                                lim->desc->name);
 
331
 
 
332
        if (!(lim->modify & PRLIMIT_SOFT))
 
333
                lim->rlim.rlim_cur = old.rlim_cur;
 
334
        else if (!(lim->modify & PRLIMIT_HARD))
 
335
                lim->rlim.rlim_max = old.rlim_max;
 
336
}
 
337
 
 
338
static void do_prlimit(struct list_head *lims)
 
339
{
 
340
        struct list_head *p, *pnext;
 
341
 
 
342
        list_for_each_safe(p, pnext, lims) {
 
343
                struct rlimit *new = NULL, *old = NULL;
 
344
                struct prlimit *lim = list_entry(p, struct prlimit, lims);
 
345
 
 
346
                if (lim->modify) {
 
347
                        if (lim->modify != (PRLIMIT_HARD | PRLIMIT_SOFT))
 
348
                                get_unknown_hardsoft(lim);
 
349
 
 
350
                        if ((lim->rlim.rlim_cur > lim->rlim.rlim_max) &&
 
351
                                (lim->rlim.rlim_cur != RLIM_INFINITY ||
 
352
                                 lim->rlim.rlim_max != RLIM_INFINITY))
 
353
                                errx(EXIT_FAILURE, _("the soft limit %s cannot exceed the hard limit"),
 
354
                                                lim->desc->name);
 
355
                        new = &lim->rlim;
 
356
                } else
 
357
                        old = &lim->rlim;
 
358
 
 
359
                if (verbose && new) {
 
360
                        printf(_("New %s limit: "), lim->desc->name);
 
361
                        if (new->rlim_cur == RLIM_INFINITY)
 
362
                                printf("<%s", _("unlimited"));
 
363
                        else
 
364
                                printf("<%ju", new->rlim_cur);
 
365
 
 
366
                        if (new->rlim_max == RLIM_INFINITY)
 
367
                                printf(":%s>\n", _("unlimited"));
 
368
                        else
 
369
                                printf(":%ju>\n", new->rlim_max);
 
370
                }
 
371
 
 
372
                if (prlimit(pid, lim->desc->resource, new, old) == -1)
 
373
                        err(EXIT_FAILURE, lim->modify ?
 
374
                                _("failed to set the %s resource limit") :
 
375
                                _("failed to get the %s resource limit"),
 
376
                                lim->desc->name);
 
377
 
 
378
                if (lim->modify)
 
379
                        rem_prlim(lim);         /* modify only; don't show */
 
380
        }
 
381
}
 
382
 
 
383
static int get_range(char *str, rlim_t *soft, rlim_t *hard, int *found)
 
384
{
 
385
        char *end = NULL;
 
386
 
 
387
        if (!str)
 
388
                return 0;
 
389
 
 
390
        *found = errno = 0;
 
391
        *soft = *hard = RLIM_INFINITY;
 
392
 
 
393
        if (!strcmp(str, INFINITY_STR)) {               /* <unlimited> */
 
394
                *found |= PRLIMIT_SOFT | PRLIMIT_HARD;
 
395
                return 0;
 
396
 
 
397
        } else if (*str == ':') {                       /* <:hard> */
 
398
                str++;
 
399
 
 
400
                if (strcmp(str, INFINITY_STR) != 0) {
 
401
                        *hard = strtoull(str, &end, 10);
 
402
 
 
403
                        if (errno || !end || *end || end == str)
 
404
                                return -1;
 
405
                }
 
406
                *found |= PRLIMIT_HARD;
 
407
                return 0;
 
408
 
 
409
        }
 
410
 
 
411
        if (strncmp(str, INFINITY_STR, INFINITY_STRLEN) == 0) {
 
412
                /* <unlimited> or <unlimited:> */
 
413
                end = str + INFINITY_STRLEN;
 
414
        } else {
 
415
                /* <value> or <soft:> */
 
416
                *hard = *soft = strtoull(str, &end, 10);
 
417
                if (errno || !end || end == str)
 
418
                        return -1;
 
419
        }
 
420
 
 
421
        if (*end == ':' && !*(end + 1))                 /* <soft:> */
 
422
                *found |= PRLIMIT_SOFT;
 
423
 
 
424
        else if (*end == ':') {                         /* <soft:hard> */
 
425
                str = end + 1;
 
426
 
 
427
                if (!strcmp(str, INFINITY_STR))
 
428
                        *hard =  RLIM_INFINITY;
 
429
                else {
 
430
                        end = NULL;
 
431
                        errno = 0;
 
432
                        *hard = strtoull(str, &end, 10);
 
433
 
 
434
                        if (errno || !end || *end || end == str)
 
435
                                return -1;
 
436
                }
 
437
                *found |= PRLIMIT_SOFT | PRLIMIT_HARD;
 
438
 
 
439
        } else                                          /* <value> */
 
440
                *found |= PRLIMIT_SOFT | PRLIMIT_HARD;
 
441
 
 
442
        return 0;
 
443
}
 
444
 
 
445
 
 
446
static int parse_prlim(struct rlimit *lim, char *ops, size_t id)
 
447
{
 
448
        rlim_t soft, hard;
 
449
        int found = 0;
 
450
 
 
451
        if (get_range(ops, &soft, &hard, &found))
 
452
                errx(EXIT_FAILURE, _("failed to parse %s limit"),
 
453
                     prlimit_desc[id].name);
 
454
 
 
455
        lim->rlim_cur = soft;
 
456
        lim->rlim_max = hard;
 
457
 
 
458
        return found;
 
459
}
 
460
 
 
461
static int add_prlim(char *ops, struct list_head *lims, size_t id)
 
462
{
 
463
        struct prlimit *lim = xcalloc(1, sizeof(*lim));
 
464
 
 
465
        INIT_LIST_HEAD(&lim->lims);
 
466
        lim->desc = &prlimit_desc[id];
 
467
 
 
468
        if (ops)
 
469
                lim->modify = parse_prlim(&lim->rlim, ops, id);
 
470
 
 
471
        list_add_tail(&lim->lims, lims);
 
472
        return 0;
 
473
}
 
474
 
 
475
int main(int argc, char **argv)
 
476
{
 
477
        int opt;
 
478
        struct list_head lims;
 
479
 
 
480
        enum {
 
481
                VERBOSE_OPTION = CHAR_MAX + 1,
 
482
                RAW_OPTION,
 
483
                NOHEADINGS_OPTION
 
484
        };
 
485
 
 
486
        static const struct option longopts[] = {
 
487
                { "pid",        required_argument, NULL, 'p' },
 
488
                { "output",     required_argument, NULL, 'o' },
 
489
                { "as",         optional_argument, NULL, 'v' },
 
490
                { "core",       optional_argument, NULL, 'c' },
 
491
                { "cpu",        optional_argument, NULL, 't' },
 
492
                { "data",       optional_argument, NULL, 'd' },
 
493
                { "fsize",      optional_argument, NULL, 'f' },
 
494
                { "locks",      optional_argument, NULL, 'x' },
 
495
                { "memlock",    optional_argument, NULL, 'l' },
 
496
                { "msgqueue",   optional_argument, NULL, 'q' },
 
497
                { "nice",       optional_argument, NULL, 'e' },
 
498
                { "nofile",     optional_argument, NULL, 'n' },
 
499
                { "nproc",      optional_argument, NULL, 'u' },
 
500
                { "rss",        optional_argument, NULL, 'm' },
 
501
                { "rtprio",     optional_argument, NULL, 'r' },
 
502
                { "rttime",     optional_argument, NULL, 'y' },
 
503
                { "sigpending", optional_argument, NULL, 'i' },
 
504
                { "stack",      optional_argument, NULL, 's' },
 
505
                { "version",    no_argument, NULL, 'V' },
 
506
                { "help",       no_argument, NULL, 'h' },
 
507
                { "noheadings", no_argument, NULL, NOHEADINGS_OPTION },
 
508
                { "raw",        no_argument, NULL, RAW_OPTION },
 
509
                { "verbose",    no_argument, NULL, VERBOSE_OPTION },
 
510
                { NULL, 0, NULL, 0 }
 
511
        };
 
512
 
 
513
        setlocale(LC_ALL, "");
 
514
        bindtextdomain(PACKAGE, LOCALEDIR);
 
515
        textdomain(PACKAGE);
 
516
        atexit(close_stdout);
 
517
 
 
518
        INIT_LIST_HEAD(&lims);
 
519
 
 
520
        /*
 
521
         * Something is very wrong if this doesn't succeed,
 
522
         * assuming STACK is the last resource, of course.
 
523
         */
 
524
        assert(MAX_RESOURCES == STACK + 1);
 
525
 
 
526
        while((opt = getopt_long(argc, argv,
 
527
                                 "+c::d::e::f::i::l::m::n::q::r::s::t::u::v::x::y::p:o:vVh",
 
528
                                 longopts, NULL)) != -1) {
 
529
                switch(opt) {
 
530
                case 'c':
 
531
                        add_prlim(optarg, &lims, CORE);
 
532
                        break;
 
533
                case 'd':
 
534
                        add_prlim(optarg, &lims, DATA);
 
535
                        break;
 
536
                case 'e':
 
537
                        add_prlim(optarg, &lims, NICE);
 
538
                        break;
 
539
                case 'f':
 
540
                        add_prlim(optarg, &lims, FSIZE);
 
541
                        break;
 
542
                case 'i':
 
543
                        add_prlim(optarg, &lims, SIGPENDING);
 
544
                        break;
 
545
                case 'l':
 
546
                        add_prlim(optarg, &lims, MEMLOCK);
 
547
                        break;
 
548
                case 'm':
 
549
                        add_prlim(optarg, &lims, RSS);
 
550
                        break;
 
551
                case 'n':
 
552
                        add_prlim(optarg, &lims, NOFILE);
 
553
                        break;
 
554
                case 'q':
 
555
                        add_prlim(optarg, &lims, MSGQUEUE);
 
556
                        break;
 
557
                case 'r':
 
558
                        add_prlim(optarg, &lims, RTPRIO);
 
559
                        break;
 
560
                case 's':
 
561
                        add_prlim(optarg, &lims, STACK);
 
562
                        break;
 
563
                case 't':
 
564
                        add_prlim(optarg, &lims, CPU);
 
565
                        break;
 
566
                case 'u':
 
567
                        add_prlim(optarg, &lims, NPROC);
 
568
                        break;
 
569
                case 'v':
 
570
                        add_prlim(optarg, &lims, AS);
 
571
                        break;
 
572
                case 'x':
 
573
                        add_prlim(optarg, &lims, LOCKS);
 
574
                        break;
 
575
                case 'y':
 
576
                        add_prlim(optarg, &lims, RTTIME);
 
577
                        break;
 
578
 
 
579
                case 'p':
 
580
                        if (pid)
 
581
                                errx(EXIT_FAILURE, _("option --pid may be specified only once"));
 
582
                        pid = strtos32_or_err(optarg, _("invalid PID argument"));
 
583
                        break;
 
584
                case 'h':
 
585
                        usage(stdout);
 
586
                case 'o':
 
587
                        ncolumns = string_to_idarray(optarg,
 
588
                                                     columns, ARRAY_SIZE(columns),
 
589
                                                     column_name_to_id);
 
590
                        if (ncolumns < 0)
 
591
                                return EXIT_FAILURE;
 
592
                        break;
 
593
                case 'V':
 
594
                        printf(UTIL_LINUX_VERSION);
 
595
                        return EXIT_SUCCESS;
 
596
 
 
597
                case NOHEADINGS_OPTION:
 
598
                        no_headings = 1;
 
599
                        break;
 
600
                case VERBOSE_OPTION:
 
601
                        verbose++;
 
602
                        break;
 
603
                case RAW_OPTION:
 
604
                        raw = 1;
 
605
                        break;
 
606
 
 
607
                default:
 
608
                        usage(stderr);
 
609
                }
 
610
        }
 
611
        if (argc > optind && pid)
 
612
                errx(EXIT_FAILURE, _("options --pid and COMMAND are mutually exclusive"));
 
613
        if (!ncolumns) {
 
614
                /* default columns */
 
615
                columns[ncolumns++] = COL_RES;
 
616
                columns[ncolumns++] = COL_HELP;
 
617
                columns[ncolumns++] = COL_SOFT;
 
618
                columns[ncolumns++] = COL_HARD;
 
619
                columns[ncolumns++] = COL_UNITS;
 
620
        }
 
621
 
 
622
        scols_init_debug(0);
 
623
 
 
624
        if (list_empty(&lims)) {
 
625
                /* default is to print all resources */
 
626
                size_t n;
 
627
 
 
628
                for (n = 0; n < MAX_RESOURCES; n++)
 
629
                        add_prlim(NULL, &lims, n);
 
630
        }
 
631
 
 
632
        do_prlimit(&lims);
 
633
 
 
634
        if (!list_empty(&lims))
 
635
                show_limits(&lims);
 
636
 
 
637
        if (argc > optind) {
 
638
                /* prlimit [options] COMMAND */
 
639
                execvp(argv[optind], &argv[optind]);
 
640
                err(EXIT_FAILURE, _("failed to execute %s"), argv[optind]);
 
641
        }
 
642
 
 
643
        return EXIT_SUCCESS;
 
644
}