Bump to procps-ng 3.3.16
[platform/upstream/procps-ng.git] / pwdx.c
1 /*
2  * pwdx.c - print process working directory
3  * Copyright 2004 Nicholas Miell
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19
20 #include <errno.h>
21 #include <getopt.h>
22 #include <limits.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28
29 #include "c.h"
30 #include "nls.h"
31 #include "xalloc.h"
32 #include "fileutils.h"
33
34 static void __attribute__ ((__noreturn__)) usage(FILE * out)
35 {
36         fputs(USAGE_HEADER, out);
37         fprintf(out, _(" %s [options] pid...\n"), program_invocation_short_name);
38         fputs(USAGE_OPTIONS, out);
39         fputs(USAGE_HELP, out);
40         fputs(USAGE_VERSION, out);
41         fprintf(out, USAGE_MAN_TAIL("pwdx(1)"));
42
43         exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
44 }
45
46 int check_pid_argument(char *input)
47 {
48         int skip = 0;
49         long pid;
50         char *end = NULL;
51
52         if (!strncmp("/proc/", input, 6))
53                 skip = 6;
54         errno = 0;
55         pid = strtol(input + skip, &end, 10);
56
57         if (errno || input + skip == end || (end && *end))
58                 return 1;
59         if (pid < 1)
60                 return 1;
61         return 0;
62 }
63
64 int main(int argc, char *argv[])
65 {
66         int ch;
67         int retval = 0, i;
68         ssize_t alloclen = 128;
69         char *pathbuf;
70
71         static const struct option longopts[] = {
72                 {"version", no_argument, 0, 'V'},
73                 {"help", no_argument, 0, 'h'},
74                 {NULL, 0, 0, 0}
75         };
76
77 #ifdef HAVE_PROGRAM_INVOCATION_NAME
78         program_invocation_name = program_invocation_short_name;
79 #endif
80         setlocale (LC_ALL, "");
81         bindtextdomain(PACKAGE, LOCALEDIR);
82         textdomain(PACKAGE);
83         atexit(close_stdout);
84
85         while ((ch = getopt_long(argc, argv, "Vh", longopts, NULL)) != -1)
86                 switch (ch) {
87                 case 'V':
88                         printf(PROCPS_NG_VERSION);
89                         return EXIT_SUCCESS;
90                 case 'h':
91                         usage(stdout);
92                 default:
93                         usage(stderr);
94                 }
95
96         argc -= optind;
97         argv += optind;
98
99         if (argc == 0)
100                 usage(stderr);
101
102         pathbuf = xmalloc(alloclen);
103
104         for (i = 0; i < argc; i++) {
105                 char *s;
106                 ssize_t len, buflen;
107                 /* Constant 10 is the length of strings "/proc/" + "/cwd" */
108                 char *buf;
109                 buflen = 10 + strlen(argv[i]) + 1;
110                 buf = xmalloc(buflen);
111
112                 if (check_pid_argument(argv[i]))
113                         xerrx(EXIT_FAILURE, _("invalid process id: %s"),
114                              argv[i]);
115                 /*
116                  * At this point, all arguments are in the form
117                  * /proc/NNNN or NNNN, so a simple check based on
118                  * the first char is possible
119                  */
120                 if (argv[i][0] != '/')
121                         snprintf(buf, buflen, "/proc/%s/cwd", argv[i]);
122                 else
123                         snprintf(buf, buflen, "%s/cwd", argv[i]);
124
125                 /*
126                  * buf contains /proc/NNNN/cwd symlink name
127                  * on entry, the target of that symlink on return
128                  */
129                 while ((len = readlink(buf, pathbuf, alloclen)) == alloclen) {
130                         alloclen *= 2;
131                         pathbuf = xrealloc(pathbuf, alloclen);
132                 }
133                 free(buf);
134
135                 if (len < 0) {
136                         s = strerror(errno == ENOENT ? ESRCH : errno);
137                         retval = EXIT_FAILURE;
138                         fprintf(stderr, "%s: %s\n", argv[i], s);
139                         continue;
140                 } else {
141                         pathbuf[len] = 0;
142                         s = pathbuf;
143                 }
144
145                 printf("%s: %s\n", argv[i], s);
146         }
147         free(pathbuf);
148         return retval;
149 }