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