in output, added a ' ' on overlong vserver-names
[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   char          buf[sizeof(ctx)*3+1];
80   size_t        l   = utilvserver_fmt_ulong(buf, ctx);
81   size_t        l1  = name==0 ? 0 : strlen(name);
82   size_t        res = CTXNR_WIDTH + 1;
83
84   if (l<CTXNR_WIDTH) write(1, CONTEXT_PLACE, CTXNR_WIDTH-l);
85   write(1, buf, l);
86   write(1, " ", 1);
87
88   if (l1!=0) {
89     assert(name!=0);
90     write(1, name, l1);
91   }
92
93   return res+l1;
94 }
95
96 static xid_t
97 extractCtx(char *pid_str)
98 {
99   pid_t         pid;
100   
101   while (*pid_str==' ') ++pid_str;
102   pid = atoi(pid_str);
103
104   return vc_get_task_xid(pid);
105 }
106
107 static char const *
108 resolveCtx(xid_t ctx)
109 {
110   char const *  res;
111   size_t        i;
112
113   for (i=0; i<mapping_len; ++i)
114     if (mapping[i].ctx==ctx) return mapping[i].id;
115
116   ++mapping_len;
117   mapping = Erealloc(mapping, mapping_len * sizeof(mapping[0]));
118   
119   if (ctx==0)      res = strdup("MAIN");
120   else if (ctx==1) res = strdup("ALL_PROC");
121   else {
122     vcCfgStyle  style = vcCFG_AUTO;
123     char        *tmp  = vc_getVserverByCtx(ctx, &style,0);
124     if (tmp) res = vc_getVserverName(tmp, style);
125     else     res = 0;
126     free(tmp);
127   }
128
129   mapping[mapping_len-1].ctx = ctx;
130   mapping[mapping_len-1].id  = res;
131   return res;
132 }
133
134 static char *
135 readOutput(int fd, size_t *total_len)
136 {
137   size_t        len  = 2*HUNK_SIZE;
138   char          *buf = Emalloc(len+1);
139   size_t        offset = 0;
140
141   for (;;) {
142     size_t      l;
143
144     while (offset >= len) {
145       len += HUNK_SIZE;
146       buf  = Erealloc(buf, len+1);
147     }
148     
149     l = Eread(fd, buf+offset, len - offset);
150     if (l==0) break;
151
152     offset += l;
153   }
154
155   buf[offset] = '\0';
156
157   if (total_len)
158     *total_len = offset;
159
160   return buf;
161 }
162
163 static void
164 processOutput(char *data, size_t len)
165 {
166   size_t        pid_end;
167   char *        eol_pos = strchr(data, '\n');
168   char *        pos;
169
170   if (eol_pos==0) eol_pos  = data + len;
171   else            *eol_pos = '\0';
172   
173   pos = strstr(data, "PID");
174   if (pos==0) {
175     WRITE_MSG(2, "Failed to parse ps-output\n");
176     exit(wrapper_exit_code);
177   }
178
179   pid_end = pos-data + 4;
180
181   write(1, data, pid_end);
182   write(1, "CONTEXT" CONTEXT_PLACE, CONTEXT_WIDTH);
183   write(1, data+pid_end, eol_pos-(data+pid_end));
184   write(1, "\n", 1);
185
186   len -= eol_pos-data;
187   data = eol_pos+1;
188   
189   while (len > 1) {
190     char const  *vserver_name = 0;
191     xid_t       ctx;
192     size_t      l;
193
194     --len;
195     eol_pos = strchr(data, '\n');
196     
197     if (eol_pos==0) eol_pos  = data + len;
198
199     ctx          = extractCtx(data + pid_end - 6);
200     vserver_name = resolveCtx(ctx);
201
202     write(1, data, pid_end);
203     l = writeContextInfo(ctx, vserver_name);
204     if (l<CONTEXT_WIDTH) write(1, CONTEXT_PLACE, CONTEXT_WIDTH-l);
205     else                 write(1, " ", 1);
206     write(1, data+pid_end, eol_pos-(data+pid_end));
207     write(1, "\n", 1);
208     
209     len -= eol_pos-data;
210     data = eol_pos+1;
211   }
212 }
213
214 int main(int argc, char *argv[])
215 {
216   int           p[2];
217   pid_t         pid;
218   char *        data;
219   size_t        len;
220
221   if (argc>1) {
222     if (strcmp(argv[1], "--help")   ==0) showHelp(1, argv[0], 0);
223     if (strcmp(argv[1], "--version")==0) showVersion();
224   }
225     
226   if (vc_get_task_xid(0)!=1)
227     Evc_new_s_context(1, vc_get_insecurecaps(), 0);
228
229   Epipe(p);
230   pid = Efork();
231
232   if (pid==0) {
233     int         fd = Eopen("/dev/null", O_RDONLY, 0);
234     Edup2(fd,   0);
235     Edup2(p[1], 1);
236     Eclose(p[0]);
237     Eclose(p[1]);
238     Eclose(fd);
239
240     argv[0] = "ps";
241
242     Eexecv(PS_PROG, argv);
243   }
244
245   Eclose(p[1]);
246   data = readOutput(p[0], &len);
247   Eclose(p[0]);
248   
249   processOutput(data, len);
250
251   exitLikeProcess(pid);
252   perror("exitLikeProcess()");
253   return wrapper_exit_code;
254 }