minor documentation fix
[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 "wrappers.h"
25 #include "wrappers-vserver.h"
26 #include "pathconfig.h"
27
28 #include <lib/vserver.h>
29 #include <lib/fmt.h>
30 #include <assert.h>
31
32 #define CTXNR_WIDTH     5
33 #define HUNK_SIZE       0x4000
34 #define CONTEXT_WIDTH   20
35 #define CONTEXT_PLACE   "                    "
36
37 int wrapper_exit_code = 254;
38
39 struct ContextMapping {
40     xid_t               ctx;
41     char const *        id;
42 };
43
44 static struct ContextMapping            *mapping    = 0;
45 static size_t                           mapping_len = 0;
46
47
48 static void
49 showHelp(int fd, char const *cmd, int res)
50 {
51   WRITE_MSG(fd, "Usage:  ");
52   WRITE_STR(fd, cmd);
53   WRITE_MSG(fd,
54             " <ps-opts>*\n\n"
55             "Please report bugs to " PACKAGE_BUGREPORT "\n");
56   exit(res);
57 }
58
59 static void
60 showVersion()
61 {
62   WRITE_MSG(1,
63             "vps " VERSION " -- shows processes in vserver-contexts\n"
64             "This program is part of " PACKAGE_STRING "\n\n"
65             "Copyright (C) 2004 Enrico Scholz\n"
66             VERSION_COPYRIGHT_DISCLAIMER);
67   exit(0);
68 }
69
70
71 static size_t
72 writeContextInfo(xid_t ctx, char const *name)
73 {
74   char          buf[sizeof(ctx)*3+1];
75   size_t        l   = utilvserver_fmt_ulong(buf, ctx);
76   size_t        l1  = name==0 ? 0 : strlen(name);
77   size_t        res = CTXNR_WIDTH + 1;
78
79   if (l<CTXNR_WIDTH) write(1, CONTEXT_PLACE, CTXNR_WIDTH-l);
80   write(1, buf, l);
81   write(1, " ", 1);
82
83   if (l1!=0) {
84     assert(name!=0);
85     write(1, name, l1);
86   }
87
88   return res+l1;
89 }
90
91 static xid_t
92 extractCtx(char *pid_str)
93 {
94   pid_t         pid;
95   
96   while (*pid_str==' ') ++pid_str;
97   pid = atoi(pid_str);
98
99   return vc_X_getctx(pid);
100 }
101
102 static char const *
103 resolveCtx(xid_t ctx)
104 {
105   char const *  res;
106   size_t        i;
107
108   for (i=0; i<mapping_len; ++i)
109     if (mapping[i].ctx==ctx) return mapping[i].id;
110
111   ++mapping_len;
112   mapping = Erealloc(mapping, mapping_len * sizeof(mapping[0]));
113   
114   if (ctx==0)      res = strdup("MAIN");
115   else if (ctx==1) res = strdup("ALL_PROC");
116   else {
117     vcCfgStyle  style = vcCFG_AUTO;
118     char        *tmp  = vc_getVserverByCtx(ctx, &style,0);
119     if (tmp) res = vc_getVserverName(tmp, style);
120     else     res = 0;
121     free(tmp);
122   }
123
124   mapping[mapping_len-1].ctx = ctx;
125   mapping[mapping_len-1].id  = res;
126   return res;
127 }
128
129 static char *
130 readOutput(int fd, size_t *total_len)
131 {
132   size_t        len  = 2*HUNK_SIZE;
133   char          *buf = Emalloc(len+1);
134   size_t        offset = 0;
135
136   for (;;) {
137     size_t      l;
138
139     while (offset >= len) {
140       len += HUNK_SIZE;
141       buf  = Erealloc(buf, len+1);
142     }
143     
144     l = Eread(fd, buf+offset, len - offset);
145     if (l==0) break;
146
147     offset += l;
148   }
149
150   buf[offset] = '\0';
151
152   if (total_len)
153     *total_len = offset;
154
155   return buf;
156 }
157
158 static void
159 processOutput(char *data, size_t len)
160 {
161   size_t        pid_end;
162   char *        eol_pos = strchr(data, '\n');
163   char *        pos;
164
165   if (eol_pos==0) eol_pos  = data + len;
166   else            *eol_pos = '\0';
167   
168   pos = strstr(data, "PID");
169   if (pos==0) {
170     WRITE_MSG(2, "Failed to parse ps-output\n");
171     exit(wrapper_exit_code);
172   }
173
174   pid_end = pos-data + 4;
175
176   write(1, data, pid_end);
177   write(1, "CONTEXT" CONTEXT_PLACE, CONTEXT_WIDTH);
178   write(1, data+pid_end, eol_pos-(data+pid_end));
179   write(1, "\n", 1);
180
181   len -= eol_pos-data;
182   data = eol_pos+1;
183   
184   while (len > 1) {
185     char const  *vserver_name = 0;
186     xid_t       ctx;
187     size_t      l;
188
189     --len;
190     eol_pos = strchr(data, '\n');
191     
192     if (eol_pos==0) eol_pos  = data + len;
193
194     ctx          = extractCtx(data + pid_end - 6);
195     vserver_name = resolveCtx(ctx);
196
197     write(1, data, pid_end);
198     l = writeContextInfo(ctx, vserver_name);
199     if (l<CONTEXT_WIDTH) write(1, CONTEXT_PLACE, CONTEXT_WIDTH-l);
200     write(1, data+pid_end, eol_pos-(data+pid_end));
201     write(1, "\n", 1);
202     
203     len -= eol_pos-data;
204     data = eol_pos+1;
205   }
206 }
207
208 int main(int argc, char *argv[])
209 {
210   int           p[2];
211   pid_t         pid;
212   char *        data;
213   size_t        len;
214
215   if (argc>1) {
216     if (strcmp(argv[1], "--help")   ==0) showHelp(1, argv[0], 0);
217     if (strcmp(argv[1], "--version")==0) showVersion();
218   }
219     
220   if (vc_X_getctx(0)!=1)
221     Evc_new_s_context(1, vc_get_securecaps(), 0);
222
223   Epipe(p);
224   pid = Efork();
225
226   if (pid==0) {
227     int         fd = Eopen("/dev/null", O_RDONLY, 0);
228     Edup2(fd,   0);
229     Edup2(p[1], 1);
230     Eclose(p[0]);
231     Eclose(p[1]);
232     Eclose(fd);
233
234     argv[0] = "ps";
235
236     Eexecv(PS_PROG, argv);
237   }
238
239   Eclose(p[1]);
240   data = readOutput(p[0], &len);
241   Eclose(p[0]);
242   
243   processOutput(data, len);
244
245   exitLikeProcess(pid);
246   perror("exitLikeProcess()");
247   return wrapper_exit_code;
248 }