aac59f4d60aa71bc60de97259a140f98a931c815
[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       0x40;
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 static size_t
48 writeContextInfo(xid_t ctx, char const *name)
49 {
50   char          buf[sizeof(ctx)*3+1];
51   size_t        l   = utilvserver_fmt_ulong(buf, ctx);
52   size_t        l1  = name==0 ? 0 : strlen(name);
53   size_t        res = CTXNR_WIDTH + 1;
54
55   if (l<CTXNR_WIDTH) write(1, CONTEXT_PLACE, CTXNR_WIDTH-l);
56   write(1, buf, l);
57   write(1, " ", 1);
58
59   if (l1!=0) {
60     assert(name!=0);
61     write(1, name, l1);
62   }
63
64   return res+l1;
65 }
66
67 static xid_t
68 extractCtx(char *pid_str)
69 {
70   pid_t         pid;
71   
72   while (*pid_str==' ') ++pid_str;
73   pid = atoi(pid_str);
74
75   return vc_X_getctx(pid);
76 }
77
78 static char const *
79 resolveCtx(xid_t ctx)
80 {
81   char const *  res;
82   size_t        i;
83
84   for (i=0; i<mapping_len; ++i)
85     if (mapping[i].ctx==ctx) return mapping[i].id;
86
87   ++mapping_len;
88   mapping = Erealloc(mapping, mapping_len * sizeof(mapping[0]));
89   
90   if (ctx==0)      res = strdup("MAIN");
91   else if (ctx==1) res = strdup("ALL_PROC");
92   else {
93     vcCfgStyle  style = vcCFG_AUTO;
94     char        *tmp  = vc_getVserverByCtx(ctx, &style,0);
95     if (tmp) res = vc_getVserverName(tmp, style);
96     else     res = 0;
97     free(tmp);
98   }
99
100   mapping[mapping_len-1].ctx = ctx;
101   mapping[mapping_len-1].id  = res;
102   return res;
103 }
104
105 static char *
106 readOutput(int fd, size_t *total_len)
107 {
108   size_t        len  = 2*HUNK_SIZE;
109   char          *buf = Emalloc(len+1);
110   size_t        offset = 0;
111
112   for (;;) {
113     size_t      l;
114
115     while (offset >= len) {
116       len += HUNK_SIZE;
117       buf  = Erealloc(buf, len+1);
118     }
119     
120     l = Eread(fd, buf+offset, len - offset);
121     if (l==0) break;
122
123     offset += l;
124   }
125
126   buf[offset] = '\0';
127
128   if (total_len)
129     *total_len = offset;
130
131   return buf;
132 }
133
134 static void
135 processOutput(char *data, size_t len)
136 {
137   size_t        pid_end;
138   char *        eol_pos = strchr(data, '\n');
139   char *        pos;
140
141   if (eol_pos==0) eol_pos  = data + len;
142   else            *eol_pos = '\0';
143   
144   pos = strstr(data, "PID");
145   if (pos==0) {
146     WRITE_MSG(2, "Failed to parse ps-output\n");
147     exit(wrapper_exit_code);
148   }
149
150   pid_end = pos-data + 4;
151
152   write(1, data, pid_end);
153   write(1, "CONTEXT" CONTEXT_PLACE, CONTEXT_WIDTH);
154   write(1, data+pid_end, eol_pos-(data+pid_end));
155   write(1, "\n", 1);
156
157   len -= eol_pos-data;
158   data = eol_pos+1;
159   
160   while (len > 1) {
161     char const  *vserver_name = 0;
162     xid_t       ctx;
163     size_t      l;
164
165     --len;
166     eol_pos = strchr(data, '\n');
167     
168     if (eol_pos==0) eol_pos  = data + len;
169
170     ctx          = extractCtx(data + pid_end - 6);
171     vserver_name = resolveCtx(ctx);
172
173     write(1, data, pid_end);
174     l = writeContextInfo(ctx, vserver_name);
175     if (l<CONTEXT_WIDTH) write(1, CONTEXT_PLACE, CONTEXT_WIDTH-l);
176     write(1, data+pid_end, eol_pos-(data+pid_end));
177     write(1, "\n", 1);
178     
179     len -= eol_pos-data;
180     data = eol_pos+1;
181   }
182 }
183
184 int main(int argc, char *argv[])
185 {
186   int           p[2];
187   pid_t         pid;
188   char *        data;
189   size_t        len;
190
191   if (vc_X_getctx(0)!=1)
192     Evc_new_s_context(1, vc_get_securecaps(), 0);
193
194   Epipe(p);
195   pid = Efork();
196
197   if (pid==0) {
198     int         fd = Eopen("/dev/null", O_RDONLY, 0);
199     Edup2(fd,   0);
200     Edup2(p[1], 1);
201     Eclose(p[0]);
202     Eclose(p[1]);
203     Eclose(fd);
204
205     argv[0] = "ps";
206
207     Eexecv(PS_PROG, argv);
208   }
209
210   Eclose(p[1]);
211   data = readOutput(p[0], &len);
212   Eclose(p[0]);
213   
214   processOutput(data, len);
215
216   exitLikeProcess(pid);
217   perror("exitLikeProcess()");
218   return wrapper_exit_code;
219 }