enum{
Maxfile = 1000, /* number of Files we'll log */
- Maxrpc = 20000,/* number of RPCs we'll log */
};
typedef struct File File;
vlong totwrite;
ulong nrpc;
vlong nproto;
- Rpc rpc[Maxrpc];
+ Rpc rpc[Tmax];
File file[Maxfile];
};
void
usage(void)
{
- fprint(2, "usage: iostats [-d] [-f debugfile] cmds [args ...]\n");
+ fprint(2, "usage: iostats [-dC] [-f debugfile] cmds [args ...]\n");
exits("usage");
}
char *dbfile;
char buf[64*1024];
float brpsec, bwpsec, bppsec;
- int cpid, fspid, rspid, dbg, n, mflag;
+ int cpid, fspid, expid, rspid, dbg, n, mflag;
+ char *fds[3];
+ Waitmsg *w;
File *fs;
- Req *r, **rr;
+ Req *r;
dbg = 0;
mflag = MREPL;
usage();
if(pipe(pfd) < 0)
- sysfatal("pipe");
+ sysfatal("pipe: %r");
+
+ /* dup std fds to be inherited to exportfs */
+ fds[0] = smprint("/fd/%d", dup(0, -1));
+ fds[1] = smprint("/fd/%d", dup(1, -1));
+ fds[2] = smprint("/fd/%d", dup(2, -1));
switch(cpid = fork()) {
case -1:
- sysfatal("fork");
+ sysfatal("fork: %r");
case 0:
close(pfd[1]);
+ close(atoi(strrchr(fds[0], '/')+1));
+ close(atoi(strrchr(fds[1], '/')+1));
+ close(atoi(strrchr(fds[2], '/')+1));
+
if(getwd(buf, sizeof(buf)) == 0)
- sysfatal("no working directory");
+ sysfatal("no working directory: %r");
- rfork(RFENVG|RFNAMEG|RFNOTEG);
+ rfork(RFENVG|RFNAMEG);
if(mount(pfd[0], -1, "/", mflag, "") < 0)
- sysfatal("mount /");
+ sysfatal("mount /: %r");
+
+ /* replace std fds with the exported ones */
+ close(0); open(fds[0], OREAD);
+ close(1); open(fds[1], OWRITE);
+ close(2); open(fds[2], OWRITE);
bind("#c/pid", "/dev/pid", MREPL);
bind("#c/ppid", "/dev/ppid", MREPL);
bind("#e", "/env", MREPL|MCREATE);
- close(0);
- close(1);
- close(2);
- open("/fd/0", OREAD);
- open("/fd/1", OWRITE);
- open("/fd/2", OWRITE);
+ bind("#d", "/fd", MREPL);
+
if(chdir(buf) < 0)
- sysfatal("chdir");
- exec(argv[0], argv);
- exec(smprint("/bin/%s", argv[0]), argv);
+ sysfatal("chdir: %r");
+
+ exec(*argv, argv);
+ if(**argv != '/' && strncmp(*argv, "./", 2) != 0 && strncmp(*argv, "../", 3) != 0)
+ exec(smprint("/bin/%s", *argv), argv);
sysfatal("exec: %r");
default:
close(pfd[0]);
}
- switch(fspid = fork()) {
- default:
- while(cpid != waitpid())
- ;
- postnote(PNPROC, fspid, DONESTR);
- while(fspid != waitpid())
- ;
- exits(0);
- case -1:
- sysfatal("fork");
- case 0:
- notify(catcher);
- break;
- }
-
+ /* isolate us from interrupts */
+ rfork(RFNOTEG);
if(pipe(efd) < 0)
- sysfatal("pipe");
+ sysfatal("pipe: %r");
/* spawn exportfs */
- switch(fork()) {
+ switch(expid = fork()) {
default:
close(efd[0]);
+ close(atoi(strrchr(fds[0], '/')+1));
+ close(atoi(strrchr(fds[1], '/')+1));
+ close(atoi(strrchr(fds[2], '/')+1));
break;
case -1:
- sysfatal("fork");
+ sysfatal("fork: %r");
case 0:
dup(efd[0], 0);
close(efd[0]);
close(efd[1]);
+ close(pfd[1]);
if(dbg){
execl("/bin/exportfs", "exportfs", "-df", dbfile, "-r", "/", nil);
} else {
execl("/bin/exportfs", "exportfs", "-r", "/", nil);
}
- exits(0);
+ sysfatal("exec: %r");
}
- fmtinstall('F', fcallfmt);
+ switch(fspid = fork()) {
+ default:
+ close(pfd[1]);
+ close(efd[1]);
+
+ buf[0] = '\0';
+ while((w = wait()) != nil && (cpid != -1 || fspid != -1 || expid != -1)){
+ if(w->pid == fspid)
+ fspid = -1;
+ else if(w->pid == expid)
+ expid = -1;
+ else if(w->pid == cpid){
+ cpid = -1;
+ strcpy(buf, w->msg);
+ if(fspid != -1)
+ postnote(PNPROC, fspid, DONESTR);
+ }
+ if(buf[0] == '\0')
+ strcpy(buf, w->msg);
+ free(w);
+ }
+ exits(buf);
+ case -1:
+ sysfatal("fork: %r");
+ case 0:
+ notify(catcher);
+ break;
+ }
stats->rpc[Tversion].name = "version";
stats->rpc[Tauth].name = "auth";
stats->rpc[Tstat].name = "stat";
stats->rpc[Twstat].name = "wstat";
- for(n = 0; n < Maxrpc; n++)
+ for(n = 0; n < nelem(stats->rpc); n++)
stats->rpc[n].lo = 10000000000LL;
switch(rspid = rfork(RFPROC|RFMEM)) {
while(!done){
uchar tmp[sizeof(buf)];
Fcall f;
+ Req **rr;
n = read(efd[1], buf, sizeof(buf));
if(n < 0)
if(write(pfd[1], buf, n) != n)
break;
}
- exits(0);
+ exits(nil);
default:
/* read request from mount and pass to exportfs */
while(!done){
bwpsec = (double)stats->totwrite / (((float)rpc->time/1e9)+.000001);
ttime = 0;
- for(n = 0; n < Maxrpc; n++) {
+ for(n = 0; n < nelem(stats->rpc); n++) {
rpc = &stats->rpc[n];
if(rpc->count == 0)
continue;
fprint(2, "%-10s %5s %5s %5s %5s %5s T R\n",
"Message", "Count", "Low", "High", "Time", "Averg");
- for(n = 0; n < Maxrpc; n++) {
+ for(n = 0; n < nelem(stats->rpc); n++) {
rpc = &stats->rpc[n];
if(rpc->count == 0)
continue;
for(fs = stats->file; fs < &stats->file[Maxfile]; fs++){
if(fs->nopen == 0)
break;
+
+ if(strcmp(fs->path, fds[0]) == 0)
+ fs->path = "stdin";
+ else if(strcmp(fs->path, fds[1]) == 0)
+ fs->path = "stdout";
+ else if(strcmp(fs->path, fds[2]) == 0)
+ fs->path = "stderr";
+
fprint(2, "%5lud %8lud %8llud %8lud %8llud %s\n",
fs->nopen,
fs->nread, fs->bread,
fs->path);
}
- exits(0);
+ exits(nil);
}