036ea128108798e1ff00fb787733f4e5a2b30912
[util-vserver.git] / util-vserver / src / vps.c
1 // $Id$    --*- c -*--
2
3 // Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
4 //  
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; version 2 of the License.
8 //  
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //  
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18
19 #ifdef HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22
23 #include "util.h"
24 #include "pathconfig.h"
25
26 #include <lib/vserver.h>
27 #include <lib/fmt.h>
28 #include <assert.h>
29 #include <fcntl.h>
30
31 #define ENSC_WRAPPERS_VSERVER   1
32 #define ENSC_WRAPPERS_STDLIB    1
33 #define ENSC_WRAPPERS_UNISTD    1
34 #define ENSC_WRAPPERS_FCNTL     1
35 #include <wrappers.h>
36
37 #define CTXNR_WIDTH     5
38 #define HUNK_SIZE       0x4000
39 #define CONTEXT_WIDTH   20
40 #define CONTEXT_PLACE   "                    "
41
42 int wrapper_exit_code = 254;
43
44 struct ContextMapping {
45     xid_t               ctx;
46     char const *        id;
47 };
48
49 static struct ContextMapping            *mapping    = 0;
50 static size_t                           mapping_len = 0;
51
52
53 static void
54 showHelp(int fd, char const *cmd, int res)
55 {
56   WRITE_MSG(fd, "Usage:  ");
57   WRITE_STR(fd, cmd);
58   WRITE_MSG(fd,
59             " <ps-opts>*\n\n"
60             "Please report bugs to " PACKAGE_BUGREPORT "\n");
61   exit(res);
62 }
63
64 static void
65 showVersion()
66 {
67   WRITE_MSG(1,
68             "vps " VERSION " -- shows processes in vserver-contexts\n"
69             "This program is part of " PACKAGE_STRING "\n\n"
70             "Copyright (C) 2004 Enrico Scholz\n"
71             VERSION_COPYRIGHT_DISCLAIMER);
72   exit(0);
73 }
74
75
76 static size_t
77 writeContextInfo(xid_t ctx, char const *name)
78 {
79   size_t        l1  = name==0 ? 0 : strlen(name);
80   size_t        res = CTXNR_WIDTH + 1;
81   
82   if (ctx==VC_NOCTX) {
83     if (3<CTXNR_WIDTH) write(1, CONTEXT_PLACE, CTXNR_WIDTH-3);
84     write(1, "ERR ", 4);
85   }
86   else {
87     char        buf[sizeof(ctx)*3+1];
88     size_t      l = utilvserver_fmt_ulong(buf, ctx);
89
90     if (l<CTXNR_WIDTH) write(1, CONTEXT_PLACE, CTXNR_WIDTH-l);
91     write(1, buf, l);
92     write(1, " ", 1);
93   }
94
95   if (l1!=0) {
96     assert(name!=0);
97     write(1, name, l1);
98   }
99
100   return res+l1;
101 }
102
103 static xid_t
104 extractCtx(char *pid_str)
105 {
106   pid_t         pid;
107   
108   while (*pid_str==' ') ++pid_str;
109   pid = atoi(pid_str);
110
111   return vc_get_task_xid(pid);
112 }
113
114 static char const *
115 resolveCtx(xid_t ctx)
116 {
117   char const *  res;
118   size_t        i;
119
120   for (i=0; i<mapping_len; ++i)
121     if (mapping[i].ctx==ctx) return mapping[i].id;
122
123   ++mapping_len;
124   mapping = Erealloc(mapping, mapping_len * sizeof(mapping[0]));
125   
126   if (ctx==0)      res = strdup("MAIN");
127   else if (ctx==1) res = strdup("ALL_PROC");
128   else {
129     vcCfgStyle  style = vcCFG_AUTO;
130     char        *tmp  = vc_getVserverByCtx(ctx, &style,0);
131     if (tmp) res = vc_getVserverName(tmp, style);
132     else     res = 0;
133     free(tmp);
134   }
135
136   mapping[mapping_len-1].ctx = ctx;
137   mapping[mapping_len-1].id  = res;
138   return res;
139 }
140
141 static char *
142 readOutput(int fd, size_t *total_len)
143 {
144   size_t        len  = 2*HUNK_SIZE;
145   char          *buf = Emalloc(len+1);
146   size_t        offset = 0;
147
148   for (;;) {
149     size_t      l;
150
151     while (offset >= len) {
152       len += HUNK_SIZE;
153       buf  = Erealloc(buf, len+1);
154     }
155     
156     l = Eread(fd, buf+offset, len - offset);
157     if (l==0) break;
158
159     offset += l;
160   }
161
162   buf[offset] = '\0';
163
164   if (total_len)
165     *total_len = offset;
166
167   return buf;
168 }
169
170 static void
171 processOutput(char *data, size_t len)
172 {
173   size_t        pid_end;
174   char *        eol_pos = strchr(data, '\n');
175   char *        pos;
176
177   if (eol_pos==0) eol_pos  = data + len;
178   else            *eol_pos = '\0';
179   
180   pos = strstr(data, "PID");
181   if (pos==0) {
182     WRITE_MSG(2, "Failed to parse ps-output\n");
183     exit(wrapper_exit_code);
184   }
185
186   pid_end = pos-data + 4;
187
188   write(1, data, pid_end);
189   write(1, "CONTEXT" CONTEXT_PLACE, CONTEXT_WIDTH);
190   write(1, data+pid_end, eol_pos-(data+pid_end));
191   write(1, "\n", 1);
192
193   len -= eol_pos-data;
194   data = eol_pos+1;
195   
196   while (len > 1) {
197     char const  *vserver_name = 0;
198     xid_t       ctx;
199     size_t      l;
200
201     --len;
202     eol_pos = strchr(data, '\n');
203     
204     if (eol_pos==0) eol_pos  = data + len;
205
206     ctx          = extractCtx(data + pid_end - 6);
207     vserver_name = resolveCtx(ctx);
208
209     write(1, data, pid_end);
210     l = writeContextInfo(ctx, vserver_name);
211     if (l<CONTEXT_WIDTH) write(1, CONTEXT_PLACE, CONTEXT_WIDTH-l);
212     else                 write(1, " ", 1);
213     write(1, data+pid_end, eol_pos-(data+pid_end));
214     write(1, "\n", 1);
215     
216     len -= eol_pos-data;
217     data = eol_pos+1;
218   }
219 }
220
221 int main(int argc, char *argv[])
222 {
223   int           p[2];
224   pid_t         pid;
225   char *        data;
226   size_t        len;
227   char const *  errptr;
228
229   if (argc>1) {
230     if (strcmp(argv[1], "--help")   ==0) showHelp(1, argv[0], 0);
231     if (strcmp(argv[1], "--version")==0) showVersion();
232   }
233
234   if (!switchToWatchXid(&errptr)) {
235     perror(errptr);
236     exit(wrapper_exit_code);
237   }
238
239   Epipe(p);
240   pid = Efork();
241
242   if (pid==0) {
243     int         fd = Eopen("/dev/null", O_RDONLY, 0);
244     Edup2(fd,   0);
245     Edup2(p[1], 1);
246     Eclose(p[0]);
247     Eclose(p[1]);
248     Eclose(fd);
249
250     argv[0] = "ps";
251
252     Eexecv(PS_PROG, argv);
253   }
254
255   Eclose(p[1]);
256   data = readOutput(p[0], &len);
257   Eclose(p[0]);
258   
259   processOutput(data, len);
260
261   exitLikeProcess(pid, "ps");
262   perror("exitLikeProcess()");
263   return wrapper_exit_code;
264 }