~ubuntu-branches/ubuntu/quantal/psmisc/quantal

« back to all changes in this revision

Viewing changes to .pc/psmisc_strcpy_overflow/src/pstree.c

  • Committer: Package Import Robot
  • Author(s): Colin Watson
  • Date: 2012-05-02 12:57:02 UTC
  • mfrom: (1.1.16) (2.1.12 sid)
  • Revision ID: package-import@ubuntu.com-20120502125702-b9roee47eeb37p41
Tags: 22.16-1ubuntu1
* Resynchronise with Debian.  Remaining changes:
  - Build-depend on gettext:any, since we only need it to run tools at
    build-time.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * pstree.c - display process tree
3
 
 *
4
 
 * Copyright (C) 1993-2002 Werner Almesberger
5
 
 * Copyright (C) 2002-2009 Craig Small
6
 
 *
7
 
 * This program is free software; you can redistribute it and/or modify
8
 
 * it under the terms of the GNU General Public License as published by
9
 
 * the Free Software Foundation; either version 2 of the License, or
10
 
 * (at your option) any later version.
11
 
 *
12
 
 *  This program is distributed in the hope that it will be useful,
13
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
 *  GNU General Public License for more details.
16
 
 *
17
 
 *  You should have received a copy of the GNU General Public License
18
 
 *  along with this program; if not, write to the Free Software
19
 
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 
 */
21
 
 
22
 
 
23
 
#ifdef HAVE_CONFIG_H
24
 
#include <config.h>
25
 
#endif
26
 
 
27
 
#include <stdlib.h>
28
 
#include <stdio.h>
29
 
#include <string.h>
30
 
#include <ctype.h>
31
 
#include <unistd.h>
32
 
#include <fcntl.h>
33
 
#include <getopt.h>
34
 
#include <pwd.h>
35
 
#include <dirent.h>
36
 
#include <curses.h>
37
 
#include <term.h>
38
 
#include <termios.h>
39
 
#include <langinfo.h>
40
 
#include <assert.h>
41
 
#include <sys/types.h>
42
 
#include <sys/stat.h>
43
 
#include <sys/ioctl.h>
44
 
 
45
 
#include "i18n.h"
46
 
#include "comm.h"
47
 
 
48
 
#ifdef WITH_SELINUX
49
 
#include <selinux/selinux.h>
50
 
#endif                                /*WITH_SELINUX */
51
 
 
52
 
extern const char *__progname;
53
 
 
54
 
#define PROC_BASE    "/proc"
55
 
 
56
 
/* UTF-8 defines by Johan Myreen, updated by Ben Winslow */
57
 
#define UTF_V        "\342\224\202"        /* U+2502, Vertical line drawing char */
58
 
#define UTF_VR        "\342\224\234"        /* U+251C, Vertical and right */
59
 
#define UTF_H        "\342\224\200"        /* U+2500, Horizontal */
60
 
#define UTF_UR        "\342\224\224"        /* U+2514, Up and right */
61
 
#define UTF_HD        "\342\224\254"        /* U+252C, Horizontal and down */
62
 
 
63
 
#define VT_BEG        "\033(0\017"        /* use graphic chars */
64
 
#define VT_END        "\033(B"        /* back to normal char set */
65
 
#define VT_V        "x"                /* see UTF definitions above */
66
 
#define VT_VR        "t"
67
 
#define VT_H        "q"
68
 
#define VT_UR        "m"
69
 
#define        VT_HD        "w"
70
 
 
71
 
typedef struct _proc {
72
 
    char comm[COMM_LEN + 1];
73
 
    char **argv;                /* only used : argv[0] is 1st arg; undef if argc < 1 */
74
 
    int argc;                        /* with -a   : number of arguments, -1 if swapped    */
75
 
    pid_t pid;
76
 
    uid_t uid;
77
 
#ifdef WITH_SELINUX
78
 
    security_context_t scontext;
79
 
#endif                                /*WITH_SELINUX */
80
 
    char flags;
81
 
    struct _child *children;
82
 
    struct _proc *parent;
83
 
    struct _proc *next;
84
 
} PROC;
85
 
 
86
 
/* For flags above */
87
 
#define PFLAG_HILIGHT   0x01
88
 
#define PFLAG_THREAD    0x02
89
 
 
90
 
typedef struct _child {
91
 
    PROC *child;
92
 
    struct _child *next;
93
 
} CHILD;
94
 
 
95
 
static struct {
96
 
    const char *empty_2;        /*    */
97
 
    const char *branch_2;        /* |- */
98
 
    const char *vert_2;                /* |  */
99
 
    const char *last_2;                /* `- */
100
 
    const char *single_3;        /* --- */
101
 
    const char *first_3;        /* -+- */
102
 
} sym_ascii = {
103
 
"  ", "|-", "| ", "`-", "---", "-+-"}
104
 
 
105
 
, sym_utf = {
106
 
"  ",
107
 
        UTF_VR UTF_H,
108
 
        UTF_V " ",
109
 
        UTF_UR UTF_H, UTF_H UTF_H UTF_H, UTF_H UTF_HD UTF_H}, sym_vt100 = {
110
 
"  ",
111
 
        VT_BEG VT_VR VT_H VT_END,
112
 
        VT_BEG VT_V VT_END " ",
113
 
        VT_BEG VT_UR VT_H VT_END,
114
 
        VT_BEG VT_H VT_H VT_H VT_END, VT_BEG VT_H VT_HD VT_H VT_END}
115
 
 
116
 
, *sym = &sym_ascii;
117
 
 
118
 
static PROC *list = NULL;
119
 
 
120
 
/* The buffers will be dynamically increased in size as needed. */
121
 
static int capacity = 0;
122
 
static int *width = NULL;
123
 
static int *more = NULL;
124
 
 
125
 
static int print_args = 0, compact = 1, user_change = 0, pids = 0,
126
 
    show_parents = 0, by_pid = 0, trunc = 1, wait_end = 0;
127
 
#ifdef WITH_SELINUX
128
 
static int show_scontext = 0;
129
 
#endif                                /*WITH_SELINUX */
130
 
static int output_width = 132;
131
 
static int cur_x = 1;
132
 
static char last_char = 0;
133
 
static int dumped = 0;                /* used by dump_by_user */
134
 
static int charlen = 0;                /* length of character */
135
 
 
136
 
/*
137
 
 * Allocates additional buffer space for width and more as needed.
138
 
 * The first call will allocate the first buffer.
139
 
 *
140
 
 * index  the index that will be used after the call
141
 
 *        to this function.
142
 
 */
143
 
static void ensure_buffer_capacity(int index)
144
 
{
145
 
    if (index >= capacity) {
146
 
        if (capacity == 0)
147
 
            capacity = 100;
148
 
        else
149
 
            capacity *= 2;
150
 
        if (!(width = realloc(width, capacity * sizeof(int)))) {
151
 
            perror("realloc");
152
 
            exit(1);
153
 
        }
154
 
        if (!(more = realloc(more, capacity * sizeof(int)))) {
155
 
            perror("realloc");
156
 
            exit(1);
157
 
        }
158
 
    }
159
 
}
160
 
 
161
 
/*
162
 
 * Frees any buffers allocated by ensure_buffer_capacity.
163
 
 */
164
 
static void free_buffers()
165
 
{
166
 
    if (width != NULL) {
167
 
        free(width);
168
 
        width = NULL;
169
 
    }
170
 
    if (more != NULL) {
171
 
        free(more);
172
 
        more = NULL;
173
 
    }
174
 
    capacity = 0;
175
 
}
176
 
 
177
 
static void out_char(char c)
178
 
{
179
 
    if (charlen == 0) {                /* "new" character */
180
 
        if ((c & 0x80) == 0) {
181
 
            charlen = 1;        /* ASCII */
182
 
        } else if ((c & 0xe0) == 0xc0) {        /* 110.. 2 bytes */
183
 
            charlen = 2;
184
 
        } else if ((c & 0xf0) == 0xe0) {        /* 1110.. 3 bytes */
185
 
            charlen = 3;
186
 
        } else if ((c & 0xf8) == 0xf0) {        /* 11110.. 4 bytes */
187
 
            charlen = 4;
188
 
        } else {
189
 
            charlen = 1;
190
 
        }
191
 
        cur_x++;                /* count first byte of whatever it is only */
192
 
    }
193
 
    charlen--;
194
 
    if (!trunc || cur_x <= output_width)
195
 
        putchar(c);
196
 
    else {
197
 
        if (trunc && (cur_x == output_width + 1))
198
 
            putchar('+');
199
 
    }
200
 
}
201
 
 
202
 
 
203
 
static void out_string(const char *str)
204
 
{
205
 
    while (*str)
206
 
        out_char(*str++);
207
 
}
208
 
 
209
 
 
210
 
static int out_int(int x)
211
 
{                                /* non-negative integers only */
212
 
    int digits, div;
213
 
 
214
 
    digits = 0;
215
 
    for (div = 1; x / div; div *= 10)
216
 
        digits++;
217
 
    if (!digits)
218
 
        digits = 1;
219
 
    for (div /= 10; div; div /= 10)
220
 
        out_char('0' + (x / div) % 10);
221
 
    return digits;
222
 
}
223
 
 
224
 
#ifdef WITH_SELINUX
225
 
static void out_scontext(security_context_t scontext)
226
 
{
227
 
    out_string("`");
228
 
    out_string(scontext);
229
 
    out_string("'");
230
 
}
231
 
#endif                                /*WITH_SELINUX */
232
 
 
233
 
 
234
 
static void out_newline(void)
235
 
{
236
 
    if (last_char && cur_x == output_width)
237
 
        putchar(last_char);
238
 
    last_char = 0;
239
 
    putchar('\n');
240
 
    cur_x = 1;
241
 
}
242
 
 
243
 
 
244
 
static PROC *find_proc(pid_t pid)
245
 
{
246
 
    PROC *walk;
247
 
 
248
 
    for (walk = list; walk; walk = walk->next)
249
 
        if (walk->pid == pid)
250
 
            break;
251
 
    return walk;
252
 
}
253
 
 
254
 
#ifdef WITH_SELINUX
255
 
static PROC *new_proc(const char *comm, pid_t pid, uid_t uid,
256
 
                      security_context_t scontext)
257
 
#else                                /*WITH_SELINUX */
258
 
static PROC *new_proc(const char *comm, pid_t pid, uid_t uid)
259
 
#endif                                /*WITH_SELINUX */
260
 
{
261
 
    PROC *new;
262
 
 
263
 
    if (!(new = malloc(sizeof(PROC)))) {
264
 
        perror("malloc");
265
 
        exit(1);
266
 
    }
267
 
    strcpy(new->comm, comm);
268
 
    new->pid = pid;
269
 
    new->uid = uid;
270
 
    new->flags = 0;
271
 
    new->argc = 0;
272
 
    new->argv = NULL;
273
 
#ifdef WITH_SELINUX
274
 
    new->scontext = scontext;
275
 
#endif                                /*WITH_SELINUX */
276
 
    new->children = NULL;
277
 
    new->parent = NULL;
278
 
    new->next = list;
279
 
    return list = new;
280
 
}
281
 
 
282
 
 
283
 
static void add_child(PROC * parent, PROC * child)
284
 
{
285
 
    CHILD *new, **walk;
286
 
    int cmp;
287
 
 
288
 
    if (!(new = malloc(sizeof(CHILD)))) {
289
 
        perror("malloc");
290
 
        exit(1);
291
 
    }
292
 
    new->child = child;
293
 
    for (walk = &parent->children; *walk; walk = &(*walk)->next)
294
 
        if (by_pid) {
295
 
            if ((*walk)->child->pid > child->pid)
296
 
                break;
297
 
        } else if ((cmp = strcmp((*walk)->child->comm, child->comm)) > 0)
298
 
            break;
299
 
        else if (!cmp && (*walk)->child->uid > child->uid)
300
 
            break;
301
 
    new->next = *walk;
302
 
    *walk = new;
303
 
}
304
 
 
305
 
 
306
 
static void set_args(PROC * this, const char *args, int size)
307
 
{
308
 
    char *start;
309
 
    int i;
310
 
 
311
 
    if (!size) {
312
 
        this->argc = -1;
313
 
        return;
314
 
    }
315
 
    this->argc = 0;
316
 
    for (i = 0; i < size - 1; i++)
317
 
        if (!args[i])
318
 
            this->argc++;
319
 
    if (!this->argc)
320
 
        return;
321
 
    if (!(this->argv = malloc(sizeof(char *) * this->argc))) {
322
 
        perror("malloc");
323
 
        exit(1);
324
 
    }
325
 
    start = strchr(args, 0) + 1;
326
 
    size -= start - args;
327
 
    if (!(this->argv[0] = malloc((size_t) size))) {
328
 
        perror("malloc");
329
 
        exit(1);
330
 
    }
331
 
    start = memcpy(this->argv[0], start, (size_t) size);
332
 
    for (i = 1; i < this->argc; i++)
333
 
        this->argv[i] = start = strchr(start, 0) + 1;
334
 
}
335
 
 
336
 
#ifdef WITH_SELINUX
337
 
static void
338
 
add_proc(const char *comm, pid_t pid, pid_t ppid, uid_t uid,
339
 
         const char *args, int size, char isthread, security_context_t scontext)
340
 
#else                                /*WITH_SELINUX */
341
 
static void
342
 
add_proc(const char *comm, pid_t pid, pid_t ppid, uid_t uid,
343
 
         const char *args, int size, char isthread)
344
 
#endif                                /*WITH_SELINUX */
345
 
{
346
 
    PROC *this, *parent;
347
 
 
348
 
    if (!(this = find_proc(pid)))
349
 
#ifdef WITH_SELINUX
350
 
        this = new_proc(comm, pid, uid, scontext);
351
 
#else                                /*WITH_SELINUX */
352
 
        this = new_proc(comm, pid, uid);
353
 
#endif                                /*WITH_SELINUX */
354
 
    else {
355
 
        strcpy(this->comm, comm);
356
 
        this->uid = uid;
357
 
    }
358
 
    if (args)
359
 
        set_args(this, args, size);
360
 
    if (pid == ppid)
361
 
        ppid = 0;
362
 
    if (isthread)
363
 
      this->flags |= PFLAG_THREAD;
364
 
    if (!(parent = find_proc(ppid)))
365
 
#ifdef WITH_SELINUX
366
 
        parent = new_proc("?", ppid, 0, scontext);
367
 
#else                                /*WITH_SELINUX */
368
 
        parent = new_proc("?", ppid, 0);
369
 
#endif                                /*WITH_SELINUX */
370
 
    add_child(parent, this);
371
 
    this->parent = parent;
372
 
}
373
 
 
374
 
 
375
 
static int tree_equal(const PROC * a, const PROC * b)
376
 
{
377
 
    const CHILD *walk_a, *walk_b;
378
 
 
379
 
    if (strcmp(a->comm, b->comm))
380
 
        return 0;
381
 
    if (user_change && a->uid != b->uid)
382
 
        return 0;
383
 
    for (walk_a = a->children, walk_b = b->children; walk_a && walk_b;
384
 
         walk_a = walk_a->next, walk_b = walk_b->next)
385
 
        if (!tree_equal(walk_a->child, walk_b->child))
386
 
            return 0;
387
 
    return !(walk_a || walk_b);
388
 
}
389
 
 
390
 
static int
391
 
out_args(char *mystr)
392
 
{
393
 
  char *here;
394
 
  int strcount=0;
395
 
  char tmpstr[5];
396
 
 
397
 
  for (here = mystr; *here; here++) {
398
 
    if (*here == '\\') {
399
 
      out_string("\\\\");
400
 
      strcount += 2;
401
 
    } else if (*here >= ' ' && *here <= '~') {
402
 
      out_char(*here);
403
 
      strcount++;
404
 
    } else {
405
 
      sprintf(tmpstr, "\\%03o", (unsigned char) *here);
406
 
      out_string(tmpstr);
407
 
      strcount += 4;
408
 
    }
409
 
  } /* for */
410
 
  return strcount;
411
 
}
412
 
 
413
 
static void
414
 
dump_tree(PROC * current, int level, int rep, int leaf, int last,
415
 
          uid_t prev_uid, int closing)
416
 
{
417
 
    CHILD *walk, *next, **scan;
418
 
    const struct passwd *pw;
419
 
    int lvl, i, add, offset, len, swapped, info, count, comm_len, first;
420
 
    const char *tmp, *here;
421
 
 
422
 
    assert(closing >= 0);
423
 
    if (!current)
424
 
        return;
425
 
    if (!leaf)
426
 
        for (lvl = 0; lvl < level; lvl++) {
427
 
            for (i = width[lvl] + 1; i; i--)
428
 
                out_char(' ');
429
 
            out_string(lvl ==
430
 
                       level -
431
 
                       1 ? last ? sym->last_2 : sym->branch_2 : more[lvl +
432
 
                                                                     1] ?
433
 
                       sym->vert_2 : sym->empty_2);
434
 
        }
435
 
    if (rep < 2)
436
 
        add = 0;
437
 
    else {
438
 
        add = out_int(rep) + 2;
439
 
        out_string("*[");
440
 
    }
441
 
    if ((current->flags & PFLAG_HILIGHT) && (tmp = tgetstr("md", NULL)))
442
 
        tputs(tmp, 1, putchar);
443
 
    swapped = info = print_args;
444
 
    if (swapped && current->argc < 0)
445
 
        out_char('(');
446
 
    comm_len = out_args(current->comm);
447
 
    offset = cur_x;
448
 
    if (pids) {
449
 
        out_char(info++ ? ',' : '(');
450
 
        (void) out_int(current->pid);
451
 
    }
452
 
    if (user_change && prev_uid != current->uid) {
453
 
        out_char(info++ ? ',' : '(');
454
 
        if ((pw = getpwuid(current->uid)))
455
 
            out_string(pw->pw_name);
456
 
        else
457
 
            (void) out_int(current->uid);
458
 
    }
459
 
#ifdef WITH_SELINUX
460
 
    if (show_scontext) {
461
 
        out_char(info++ ? ',' : '(');
462
 
        out_scontext(current->scontext);
463
 
    }
464
 
#endif                                /*WITH_SELINUX */
465
 
    if ((swapped && print_args && current->argc < 0) || (!swapped && info))
466
 
        out_char(')');
467
 
    if ((current->flags & PFLAG_HILIGHT) && (tmp = tgetstr("me", NULL)))
468
 
        tputs(tmp, 1, putchar);
469
 
    if (print_args) {
470
 
        for (i = 0; i < current->argc; i++) {
471
 
            if (i < current->argc - 1)        /* Space between words but not at the end of last */
472
 
                out_char(' ');
473
 
            len = 0;
474
 
            for (here = current->argv[i]; *here; here++)
475
 
                len += *here >= ' ' && *here <= '~' ? 1 : 4;
476
 
            if (cur_x + len <=
477
 
                output_width - (i == current->argc - 1 ? 0 : 4) || !trunc)
478
 
              out_args(current->argv[i]);
479
 
            else {
480
 
                out_string("...");
481
 
                break;
482
 
            }
483
 
        }
484
 
    }
485
 
#ifdef WITH_SELINUX
486
 
    if (show_scontext || print_args || !current->children)
487
 
#else                                /*WITH_SELINUX */
488
 
    if (print_args || !current->children)
489
 
#endif                                /*WITH_SELINUX */
490
 
    {
491
 
        while (closing--)
492
 
            out_char(']');
493
 
        out_newline();
494
 
    }
495
 
    ensure_buffer_capacity(level);
496
 
    more[level] = !last;
497
 
 
498
 
#ifdef WITH_SELINUX
499
 
    if (show_scontext || print_args)
500
 
#else                                /*WITH_SELINUX */
501
 
    if (print_args)
502
 
#endif                                /*WITH_SELINUX */
503
 
    {
504
 
        width[level] = swapped + (comm_len > 1 ? 0 : -1);
505
 
        count=0;
506
 
        first=1;
507
 
        for (walk = current->children; walk; walk = next) {
508
 
          next = walk->next;
509
 
          count=0;
510
 
          if (compact && (walk->child->flags & PFLAG_THREAD)) {
511
 
            scan = &walk->next;
512
 
            while (*scan) {
513
 
              if (!tree_equal(walk->child, (*scan)->child)) {
514
 
                scan = &(*scan)->next;
515
 
              } else {
516
 
                if (next == *scan)
517
 
                  next = (*scan)->next;
518
 
                count++;
519
 
                *scan = (*scan)->next;
520
 
              }
521
 
            }
522
 
            dump_tree(walk->child, level + 1, count + 1,
523
 
                  0, !next, current->uid, closing+ (count ? 2 : 1));
524
 
                 //closing + (count ? 1 : 0));
525
 
          } else {
526
 
          dump_tree(walk->child, level + 1, 1, 0, !walk->next,
527
 
                      current->uid, 0);
528
 
          }
529
 
        }
530
 
        return;
531
 
    }
532
 
    width[level] = comm_len + cur_x - offset + add;
533
 
    if (cur_x >= output_width && trunc) {
534
 
        out_string(sym->first_3);
535
 
        out_string("+");
536
 
        out_newline();
537
 
        return;
538
 
    }
539
 
    first = 1;
540
 
    for (walk = current->children; walk; walk = next) {
541
 
        count = 0;
542
 
        next = walk->next;
543
 
        if (compact) {
544
 
            scan = &walk->next;
545
 
            while (*scan)
546
 
                if (!tree_equal(walk->child, (*scan)->child))
547
 
                    scan = &(*scan)->next;
548
 
                else {
549
 
                    if (next == *scan)
550
 
                        next = (*scan)->next;
551
 
                    count++;
552
 
                    *scan = (*scan)->next;
553
 
                }
554
 
        }
555
 
        if (first) {
556
 
            out_string(next ? sym->first_3 : sym->single_3);
557
 
            first = 0;
558
 
        }
559
 
        dump_tree(walk->child, level + 1, count + 1,
560
 
                  walk == current->children, !next, current->uid,
561
 
                  closing + (count ? 1 : 0));
562
 
    }
563
 
}
564
 
 
565
 
 
566
 
static void dump_by_user(PROC * current, uid_t uid)
567
 
{
568
 
    const CHILD *walk;
569
 
 
570
 
    if (!current)
571
 
        return;
572
 
 
573
 
    if (current->uid == uid) {
574
 
        if (dumped)
575
 
            putchar('\n');
576
 
        dump_tree(current, 0, 1, 1, 1, uid, 0);
577
 
        dumped = 1;
578
 
        return;
579
 
    }
580
 
    for (walk = current->children; walk; walk = walk->next)
581
 
        dump_by_user(walk->child, uid);
582
 
}
583
 
 
584
 
static void trim_tree_by_parent(PROC * current)
585
 
{
586
 
  if (!current)
587
 
    return;
588
 
 
589
 
  PROC * parent = current->parent;
590
 
 
591
 
  if (!parent)
592
 
    return;
593
 
 
594
 
  parent->children = NULL;
595
 
  add_child(parent, current);
596
 
  trim_tree_by_parent(parent);
597
 
}
598
 
 
599
 
 
600
 
/*
601
 
 * read_proc now uses a similar method as procps for finding the process
602
 
 * name in the /proc filesystem. My thanks to Albert and procps authors.
603
 
 */
604
 
static void read_proc(void)
605
 
{
606
 
  DIR *dir;
607
 
  struct dirent *de;
608
 
  FILE *file;
609
 
  struct stat st;
610
 
  char *path, *comm;
611
 
  char *buffer;
612
 
  size_t buffer_size;
613
 
  char readbuf[BUFSIZ + 1];
614
 
  char *tmpptr;
615
 
  pid_t pid, ppid;
616
 
  int fd, size;
617
 
  int empty;
618
 
#ifdef WITH_SELINUX
619
 
  security_context_t scontext = NULL;
620
 
  int selinux_enabled = is_selinux_enabled() > 0;
621
 
#endif                /*WITH_SELINUX */
622
 
 
623
 
  if (trunc)
624
 
    buffer_size = output_width + 1;
625
 
  else
626
 
    buffer_size = BUFSIZ + 1;
627
 
 
628
 
  if (!print_args)
629
 
    buffer = NULL;
630
 
  else if (!(buffer = malloc(buffer_size))) {
631
 
    perror("malloc");
632
 
    exit(1);
633
 
  }
634
 
  if (!(dir = opendir(PROC_BASE))) {
635
 
    perror(PROC_BASE);
636
 
    exit(1);
637
 
  }
638
 
  empty = 1;
639
 
  while ((de = readdir(dir)) != NULL)
640
 
    if ((pid = (pid_t) atoi(de->d_name)) != 0) {
641
 
      if (! (path = malloc(strlen(PROC_BASE) + strlen(de->d_name) + 10)))
642
 
        exit(2);
643
 
      sprintf(path, "%s/%d/stat", PROC_BASE, pid);
644
 
      if ((file = fopen(path, "r")) != NULL) {
645
 
        empty = 0;
646
 
        sprintf(path, "%s/%d", PROC_BASE, pid);
647
 
#ifdef WITH_SELINUX
648
 
        if (selinux_enabled)
649
 
          if (getpidcon(pid, &scontext) < 0) {
650
 
            perror(path);
651
 
            exit(1);
652
 
          }
653
 
#endif                /*WITH_SELINUX */
654
 
        if (stat(path, &st) < 0) {
655
 
          perror(path);
656
 
          exit(1);
657
 
        }
658
 
        size = fread(readbuf, 1, BUFSIZ, file);
659
 
        if (ferror(file) == 0) {
660
 
          readbuf[size] = 0;
661
 
          /* commands may have spaces or ) in them.
662
 
           * so don't trust anything from the ( to the last ) */
663
 
          if ((comm = strchr(readbuf, '('))
664
 
            && (tmpptr = strrchr(comm, ')'))) {
665
 
            ++comm;
666
 
            *tmpptr = 0;
667
 
            /* We now have readbuf with pid and cmd, and tmpptr+2
668
 
             * with the rest */
669
 
            /*printf("tmpptr: %s\n", tmpptr+2); */
670
 
            if (sscanf(tmpptr + 2, "%*c %d", &ppid) == 1) {
671
 
              DIR *taskdir;
672
 
              struct dirent *dt;
673
 
              char *taskpath;
674
 
              char *threadname;
675
 
              int thread;
676
 
 
677
 
              if (! (taskpath = malloc(strlen(path) + 10)))
678
 
                exit(2);
679
 
              sprintf(taskpath, "%s/task", path);
680
 
 
681
 
              if ((taskdir = opendir(taskpath)) != 0) {
682
 
                /* if we have this dir, we're on 2.6 */
683
 
                if (! (threadname = malloc(COMM_LEN + 2 + 1))) {
684
 
                    exit(2);
685
 
                }
686
 
                sprintf(threadname, "{%.*s}", COMM_LEN, comm);
687
 
                while ((dt = readdir(taskdir)) != NULL) {
688
 
                  if ((thread = atoi(dt->d_name)) != 0) {
689
 
                    if (thread != pid) {
690
 
#ifdef WITH_SELINUX
691
 
                      if (print_args)
692
 
                        add_proc(threadname, thread, pid, st.st_uid, 
693
 
                            threadname, strlen (threadname) + 1, 1,scontext);
694
 
                      else
695
 
                        add_proc(threadname, thread, pid, st.st_uid, 
696
 
                            NULL, 0, 1, scontext);
697
 
#else                /*WITH_SELINUX */
698
 
                      if (print_args)
699
 
                        add_proc(threadname, thread, pid, st.st_uid,
700
 
                            threadname, strlen (threadname) + 1, 1);
701
 
                      else
702
 
                        add_proc(threadname, thread, pid, st.st_uid,
703
 
                            NULL, 0, 1);
704
 
#endif                /*WITH_SELINUX */
705
 
                      }
706
 
                    }
707
 
                  }
708
 
                  free(threadname);
709
 
                  (void) closedir(taskdir);
710
 
                }
711
 
              free(taskpath);
712
 
              if (!print_args)
713
 
#ifdef WITH_SELINUX
714
 
                add_proc(comm, pid, ppid, st.st_uid, NULL, 0, 0, scontext);
715
 
#else                /*WITH_SELINUX */
716
 
                add_proc(comm, pid, ppid, st.st_uid, NULL, 0, 0);
717
 
#endif                /*WITH_SELINUX */
718
 
              else {
719
 
                sprintf(path, "%s/%d/cmdline", PROC_BASE, pid);
720
 
                if ((fd = open(path, O_RDONLY)) < 0) {
721
 
                  perror(path);
722
 
                  exit(1);
723
 
                }
724
 
                if ((size = read(fd, buffer, buffer_size)) < 0) {
725
 
                  perror(path);
726
 
                  exit(1);
727
 
                }
728
 
                (void) close(fd);
729
 
                /* If we have read the maximum screen length of args, bring it back by one to stop overflow */
730
 
                if (size >= buffer_size)
731
 
                  size--;
732
 
                if (size)
733
 
                  buffer[size++] = 0;
734
 
#ifdef WITH_SELINUX
735
 
                add_proc(comm, pid, ppid, st.st_uid,
736
 
                     buffer, size, 0, scontext);
737
 
#else                /*WITH_SELINUX */
738
 
                add_proc(comm, pid, ppid, st.st_uid,
739
 
                     buffer, size, 0);
740
 
#endif                /*WITH_SELINUX */
741
 
              }
742
 
            }
743
 
          }
744
 
        }
745
 
        (void) fclose(file);
746
 
      }
747
 
      free(path);
748
 
    }
749
 
  (void) closedir(dir);
750
 
  if (print_args)
751
 
    free(buffer);
752
 
  if (empty) {
753
 
    fprintf(stderr, _("%s is empty (not mounted ?)\n"), PROC_BASE);
754
 
    exit(1);
755
 
  }
756
 
}
757
 
 
758
 
 
759
 
#if 0
760
 
 
761
 
/* Could use output of  ps achlx | awk '{ print $3,$4,$2,$13 }'  */
762
 
 
763
 
static void read_stdin(void)
764
 
{
765
 
    char comm[PATH_MAX + 1];
766
 
    char *cmd;
767
 
    int pid, ppid, uid;
768
 
 
769
 
    while (scanf("%d %d %d %s\n", &pid, &ppid, &uid, comm) == 4) {
770
 
        if (cmd = strrchr(comm, '/'))
771
 
            cmd++;
772
 
        else
773
 
            cmd = comm;
774
 
        if (*cmd == '-')
775
 
            cmd++;
776
 
#ifdef WITH_SELINUX
777
 
        add_proc(cmd, pid, ppid, uid, NULL, 0, NULL);
778
 
#else                                /*WITH_SELINUX */
779
 
        add_proc(cmd, pid, ppid, uid, NULL, 0);
780
 
#endif                                /*WITH_SELINUX */
781
 
    }
782
 
}
783
 
 
784
 
#endif
785
 
 
786
 
 
787
 
static void usage(void)
788
 
{
789
 
    fprintf(stderr,
790
 
            _
791
 
            ("Usage: pstree [ -a ] [ -c ] [ -h | -H PID ] [ -l ] [ -n ] [ -p ] [ -u ]\n"
792
 
             "              [ -A | -G | -U ] [ PID | USER ]\n"
793
 
             "       pstree -V\n" "Display a tree of processes.\n\n"
794
 
             "  -a, --arguments     show command line arguments\n"
795
 
             "  -A, --ascii         use ASCII line drawing characters\n"
796
 
             "  -c, --compact       don't compact identical subtrees\n"
797
 
             "  -h, --highlight-all highlight current process and its ancestors\n"
798
 
             "  -H PID,\n"
799
 
             "  --highlight-pid=PID highlight this process and its ancestors\n"
800
 
             "  -G, --vt100         use VT100 line drawing characters\n"
801
 
             "  -l, --long          don't truncate long lines\n"
802
 
             "  -n, --numeric-sort  sort output by PID\n"
803
 
             "  -p, --show-pids     show PIDs; implies -c\n"
804
 
             "  -s, --show-parents  show parents of the selected process\n"
805
 
             "  -u, --uid-changes   show uid transitions\n"
806
 
             "  -U, --unicode       use UTF-8 (Unicode) line drawing characters\n"
807
 
             "  -V, --version       display version information\n"));
808
 
#ifdef WITH_SELINUX
809
 
    fprintf(stderr,
810
 
            _("  -Z     show         SELinux security contexts\n"));
811
 
#endif                                /*WITH_SELINUX */
812
 
    fprintf(stderr, _("  PID    start at this PID; default is 1 (init)\n"
813
 
                      "  USER   show only trees rooted at processes of this user\n\n"));
814
 
    exit(1);
815
 
}
816
 
 
817
 
void print_version()
818
 
{
819
 
    fprintf(stderr, _("pstree (PSmisc) %s\n"), VERSION);
820
 
    fprintf(stderr,
821
 
            _
822
 
            ("Copyright (C) 1993-2009 Werner Almesberger and Craig Small\n\n"));
823
 
    fprintf(stderr,
824
 
            _("PSmisc comes with ABSOLUTELY NO WARRANTY.\n"
825
 
              "This is free software, and you are welcome to redistribute it under\n"
826
 
              "the terms of the GNU General Public License.\n"
827
 
              "For more information about these matters, see the files named COPYING.\n"));
828
 
}
829
 
 
830
 
 
831
 
int main(int argc, char **argv)
832
 
{
833
 
    PROC *current;
834
 
    struct winsize winsz;
835
 
    const struct passwd *pw;
836
 
    pid_t pid, highlight;
837
 
    char termcap_area[1024];
838
 
    char *termname;
839
 
    int c;
840
 
 
841
 
    struct option options[] = {
842
 
        {"arguments", 0, NULL, 'a'},
843
 
        {"ascii", 0, NULL, 'A'},
844
 
        {"compact", 0, NULL, 'c'},
845
 
        {"vt100", 0, NULL, 'G'},
846
 
        {"highlight-all", 0, NULL, 'h'},
847
 
        {"highlight-pid", 1, NULL, 'H'},
848
 
        {"long", 0, NULL, 'l'},
849
 
        {"numeric-sort", 0, NULL, 'n'},
850
 
        {"show-pids", 0, NULL, 'p'},
851
 
        {"show-parents", 0, NULL, 's'},
852
 
        {"uid-changes", 0, NULL, 'u'},
853
 
        {"unicode", 0, NULL, 'U'},
854
 
        {"version", 0, NULL, 'V'},
855
 
#ifdef WITH_SELINUX
856
 
        {"security-context", 0, NULL, 'Z'},
857
 
#endif                                /*WITH_SELINUX */
858
 
        { 0, 0, 0, 0 }
859
 
    };
860
 
 
861
 
    if (ioctl(1, TIOCGWINSZ, &winsz) >= 0)
862
 
        if (winsz.ws_col)
863
 
            output_width = winsz.ws_col;
864
 
    pid = 1;
865
 
    highlight = 0;
866
 
    pw = NULL;
867
 
 
868
 
#ifdef ENABLE_NLS
869
 
    setlocale(LC_ALL, "");
870
 
    bindtextdomain(PACKAGE, LOCALEDIR);
871
 
    textdomain(PACKAGE);
872
 
#endif
873
 
 
874
 
    if (!strcmp(__progname, "pstree.x11"))
875
 
        wait_end = 1;
876
 
 
877
 
    /*
878
 
     * Attempt to figure out a good default symbol set.  Will be overriden by
879
 
     * command-line options, if given.
880
 
     */
881
 
 
882
 
    if (isatty(1) && !strcmp(nl_langinfo(CODESET), "UTF-8")) {
883
 
        /* Use UTF-8 symbols if the locale's character set is UTF-8. */
884
 
        sym = &sym_utf;
885
 
    } else if (isatty(1) && (termname = getenv("TERM")) &&
886
 
               (strlen(termname) > 0) &&
887
 
               (setupterm(NULL, 1 /* stdout */ , NULL) == OK) &&
888
 
               (tigetstr("acsc") > 0)) {
889
 
        /*
890
 
         * Failing that, if TERM is defined, a non-null value, and the terminal
891
 
         * has the VT100 graphics charset, use it.
892
 
         */
893
 
        /* problems with VT100 on some terminals, making this ascci
894
 
         * for now
895
 
         */
896
 
        sym = &sym_ascii;
897
 
    } else {
898
 
        /* Otherwise, fall back to ASCII. */
899
 
        sym = &sym_ascii;
900
 
    }
901
 
 
902
 
#ifdef WITH_SELINUX
903
 
    while ((c =
904
 
            getopt_long(argc, argv, "aAcGhH:nplsuUVZ", options,
905
 
                        NULL)) != -1)
906
 
#else                                /*WITH_SELINUX */
907
 
    while ((c =
908
 
            getopt_long(argc, argv, "aAcGhH:nplsuUV", options, NULL)) != -1)
909
 
#endif                                /*WITH_SELINUX */
910
 
        switch (c) {
911
 
        case 'a':
912
 
            print_args = 1;
913
 
            break;
914
 
        case 'A':
915
 
            sym = &sym_ascii;
916
 
            break;
917
 
        case 'c':
918
 
            compact = 0;
919
 
            break;
920
 
        case 'G':
921
 
            sym = &sym_vt100;
922
 
            break;
923
 
        case 'h':
924
 
            if (highlight)
925
 
                usage();
926
 
            if (getenv("TERM")
927
 
                && tgetent(termcap_area, getenv("TERM")) > 0)
928
 
                highlight = getpid();
929
 
            break;
930
 
        case 'H':
931
 
            if (highlight)
932
 
                usage();
933
 
            if (!getenv("TERM")) {
934
 
                fprintf(stderr, _("TERM is not set\n"));
935
 
                return 1;
936
 
            }
937
 
            if (tgetent(termcap_area, getenv("TERM")) <= 0) {
938
 
                fprintf(stderr, _("Can't get terminal capabilities\n"));
939
 
                return 1;
940
 
            }
941
 
            if (!(highlight = atoi(optarg)))
942
 
                usage();
943
 
            break;
944
 
        case 'l':
945
 
            trunc = 0;
946
 
            break;
947
 
        case 'n':
948
 
            by_pid = 1;
949
 
            break;
950
 
        case 'p':
951
 
            pids = 1;
952
 
            compact = 0;
953
 
            break;
954
 
        case 's':
955
 
            show_parents = 1;
956
 
            break;
957
 
        case 'u':
958
 
            user_change = 1;
959
 
            break;
960
 
        case 'U':
961
 
            sym = &sym_utf;
962
 
            break;
963
 
        case 'V':
964
 
            print_version();
965
 
            return 0;
966
 
#ifdef WITH_SELINUX
967
 
        case 'Z':
968
 
            if (is_selinux_enabled() > 0)
969
 
                show_scontext = 1;
970
 
            else
971
 
                fprintf(stderr,
972
 
                        "Warning: -Z ignored. Requires anx SELinux enabled kernel\n");
973
 
            break;
974
 
#endif                                /*WITH_SELINUX */
975
 
        default:
976
 
            usage();
977
 
        }
978
 
    if (optind == argc - 1) {
979
 
        if (isdigit(*argv[optind])) {
980
 
            if (!(pid = (pid_t) atoi(argv[optind++])))
981
 
                usage();
982
 
        } else if (!(pw = getpwnam(argv[optind++]))) {
983
 
            fprintf(stderr, _("No such user name: %s\n"),
984
 
                    argv[optind - 1]);
985
 
            return 1;
986
 
        }
987
 
    }
988
 
    if (optind != argc)
989
 
        usage();
990
 
    read_proc();
991
 
    for (current = find_proc(highlight); current;
992
 
         current = current->parent)
993
 
        current->flags |= PFLAG_HILIGHT;
994
 
 
995
 
    if(show_parents && pid != 0) {
996
 
      trim_tree_by_parent(find_proc(pid));
997
 
 
998
 
      pid = 1;
999
 
    }
1000
 
 
1001
 
    if (!pw)
1002
 
        dump_tree(find_proc(pid), 0, 1, 1, 1, 0, 0);
1003
 
    else {
1004
 
        dump_by_user(find_proc(1), pw->pw_uid);
1005
 
        if (!dumped) {
1006
 
            fprintf(stderr, _("No processes found.\n"));
1007
 
            return 1;
1008
 
        }
1009
 
    }
1010
 
    free_buffers();
1011
 
    if (wait_end == 1) {
1012
 
        fprintf(stderr, _("Press return to close\n"));
1013
 
        (void) getchar();
1014
 
    }
1015
 
 
1016
 
    return 0;
1017
 
}