version 1.1, 2009/09/20 19:15:01 |
version 1.2, 2009/10/11 08:58:05 |
|
|
|
|
int cmd_run_shell_exec(struct cmd *, struct cmd_ctx *); |
int cmd_run_shell_exec(struct cmd *, struct cmd_ctx *); |
|
|
|
void cmd_run_shell_callback(struct job *); |
|
void cmd_run_shell_free(void *); |
|
|
const struct cmd_entry cmd_run_shell_entry = { |
const struct cmd_entry cmd_run_shell_entry = { |
"run-shell", "run", |
"run-shell", "run", |
"command", |
"command", |
|
|
cmd_target_print |
cmd_target_print |
}; |
}; |
|
|
|
struct cmd_run_shell_data { |
|
char *cmd; |
|
struct cmd_ctx ctx; |
|
}; |
|
|
int |
int |
cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx) |
cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx) |
{ |
{ |
struct cmd_target_data *data = self->data; |
struct cmd_target_data *data = self->data; |
FILE *fp; |
struct cmd_run_shell_data *cdata; |
char *buf, *lbuf, *msg; |
struct job *job; |
size_t len; |
|
int has_output, ret, status; |
|
|
|
if ((fp = popen(data->arg, "r")) == NULL) { |
cdata = xmalloc(sizeof *cdata); |
ctx->error(ctx, "popen error"); |
cdata->cmd = xstrdup(data->arg); |
return (-1); |
memcpy(&cdata->ctx, ctx, sizeof cdata->ctx); |
} |
|
|
|
has_output = 0; |
if (ctx->cmdclient != NULL) |
lbuf = NULL; |
ctx->cmdclient->references++; |
while ((buf = fgetln(fp, &len)) != NULL) { |
if (ctx->curclient != NULL) |
if (buf[len - 1] == '\n') |
ctx->curclient->references++; |
buf[len - 1] = '\0'; |
|
else { |
job = job_add(NULL, NULL, |
lbuf = xmalloc(len + 1); |
data->arg, cmd_run_shell_callback, cmd_run_shell_free, cdata); |
memcpy(lbuf, buf, len); |
job_run(job); |
lbuf[len] = '\0'; |
|
buf = lbuf; |
return (1); /* don't let client exit */ |
|
} |
|
|
|
void |
|
cmd_run_shell_callback(struct job *job) |
|
{ |
|
struct cmd_run_shell_data *cdata = job->data; |
|
struct cmd_ctx *ctx = &cdata->ctx; |
|
char *cmd, *msg, *line, *buf; |
|
size_t off, len, llen; |
|
int retcode; |
|
|
|
buf = BUFFER_OUT(job->out); |
|
len = BUFFER_USED(job->out); |
|
|
|
cmd = cdata->cmd; |
|
|
|
if (len != 0) { |
|
line = buf; |
|
for (off = 0; off < len; off++) { |
|
if (buf[off] == '\n') { |
|
llen = buf + off - line; |
|
if (llen > INT_MAX) |
|
break; |
|
ctx->print(ctx, "%.*s", (int) llen, line); |
|
line = buf + off + 1; |
|
} |
} |
} |
ctx->print(ctx, "%s", buf); |
llen = buf + len - line; |
has_output = 1; |
if (llen > 0 && llen < INT_MAX) |
|
ctx->print(ctx, "%.*s", (int) llen, line); |
} |
} |
if (lbuf != NULL) |
|
xfree(lbuf); |
|
|
|
msg = NULL; |
msg = NULL; |
status = pclose(fp); |
if (WIFEXITED(job->status)) { |
|
if ((retcode = WEXITSTATUS(job->status)) != 0) |
if (WIFEXITED(status)) { |
xasprintf(&msg, "'%s' returned %d", cmd, retcode); |
if ((ret = WEXITSTATUS(status)) == 0) |
} else if (WIFSIGNALED(job->status)) { |
return (0); |
retcode = WTERMSIG(job->status); |
xasprintf(&msg, "'%s' returned %d", data->arg, ret); |
xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode); |
} else if (WIFSIGNALED(status)) { |
|
xasprintf( |
|
&msg, "'%s' terminated by signal %d", data->arg, |
|
WTERMSIG(status)); |
|
} |
} |
|
|
if (msg != NULL) { |
if (msg != NULL) { |
if (has_output) |
if (len != 0) |
ctx->print(ctx, "%s", msg); |
ctx->print(ctx, "%s", msg); |
else |
else |
ctx->info(ctx, "%s", msg); |
ctx->info(ctx, "%s", msg); |
xfree(msg); |
xfree(msg); |
} |
} |
|
|
return (0); |
job_free(job); /* calls cmd_run_shell_free */ |
|
} |
|
|
|
void |
|
cmd_run_shell_free(void *data) |
|
{ |
|
struct cmd_run_shell_data *cdata = data; |
|
struct cmd_ctx *ctx = &cdata->ctx; |
|
|
|
return; |
|
if (ctx->cmdclient != NULL) { |
|
ctx->cmdclient->references--; |
|
server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0); |
|
} |
|
if (ctx->curclient != NULL) |
|
ctx->curclient->references--; |
|
|
|
xfree(cdata->cmd); |
|
xfree(cdata); |
} |
} |