2009-07-03 22:16:11 +00:00
|
|
|
/* (C) Guenter Geiger <geiger@epy.co.at> */
|
|
|
|
|
|
|
|
#include "m_pd.h"
|
|
|
|
#ifdef NT
|
|
|
|
#pragma warning( disable : 4244 )
|
|
|
|
#pragma warning( disable : 4305 )
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <sched.h>
|
|
|
|
|
|
|
|
void sys_rmpollfn(int fd);
|
|
|
|
void sys_addpollfn(int fd, void* fn, void *ptr);
|
|
|
|
|
|
|
|
/* ------------------------ shell ----------------------------- */
|
|
|
|
|
|
|
|
#define INBUFSIZE 1024
|
|
|
|
|
|
|
|
static t_class *shell_class;
|
|
|
|
|
|
|
|
|
|
|
|
static void drop_priority(void)
|
|
|
|
{
|
|
|
|
#ifdef _POSIX_PRIORITY_SCHEDULING
|
|
|
|
struct sched_param par;
|
|
|
|
int p1 ,p2, p3;
|
|
|
|
par.sched_priority = 0;
|
|
|
|
sched_setscheduler(0,SCHED_OTHER,&par);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct _shell
|
|
|
|
{
|
|
|
|
t_object x_obj;
|
|
|
|
int x_echo;
|
|
|
|
char *sr_inbuf;
|
|
|
|
int sr_inhead;
|
|
|
|
int sr_intail;
|
|
|
|
void* x_binbuf;
|
|
|
|
int fdpipe[2];
|
|
|
|
int fdinpipe[2];
|
|
|
|
int pid;
|
|
|
|
int x_del;
|
|
|
|
t_outlet* x_done;
|
|
|
|
t_clock* x_clock;
|
|
|
|
} t_shell;
|
|
|
|
|
|
|
|
static int shell_pid;
|
|
|
|
|
|
|
|
|
|
|
|
void shell_cleanup(t_shell* x)
|
|
|
|
{
|
|
|
|
sys_rmpollfn(x->fdpipe[0]);
|
|
|
|
|
|
|
|
if (x->fdpipe[0]>0) close(x->fdpipe[0]);
|
|
|
|
if (x->fdpipe[1]>0) close(x->fdpipe[1]);
|
|
|
|
if (x->fdinpipe[0]>0) close(x->fdinpipe[0]);
|
|
|
|
if (x->fdinpipe[1]>0) close(x->fdinpipe[1]);
|
|
|
|
|
|
|
|
x->fdpipe[0] = -1;
|
|
|
|
x->fdpipe[1] = -1;
|
|
|
|
x->fdinpipe[0] = -1;
|
|
|
|
x->fdinpipe[1] = -1;
|
|
|
|
clock_unset(x->x_clock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void shell_check(t_shell* x)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
int status;
|
|
|
|
ret = waitpid(x->pid,&status,WNOHANG);
|
|
|
|
if (ret == x->pid) {
|
|
|
|
shell_cleanup(x);
|
|
|
|
if (WIFEXITED(status)) {
|
|
|
|
outlet_float(x->x_done,WEXITSTATUS(status));
|
|
|
|
}
|
|
|
|
else outlet_float(x->x_done,0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (x->x_del < 100) x->x_del+=2; /* increment poll times */
|
|
|
|
clock_delay(x->x_clock,x->x_del);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void shell_bang(t_shell *x)
|
|
|
|
{
|
|
|
|
post("bang");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* snippet from pd's code */
|
|
|
|
static void shell_doit(void *z, t_binbuf *b)
|
|
|
|
{
|
|
|
|
t_shell *x = (t_shell *)z;
|
|
|
|
int msg, natom = binbuf_getnatom(b);
|
|
|
|
t_atom *at = binbuf_getvec(b);
|
|
|
|
|
|
|
|
for (msg = 0; msg < natom;)
|
|
|
|
{
|
|
|
|
int emsg;
|
|
|
|
for (emsg = msg; emsg < natom && at[emsg].a_type != A_COMMA
|
|
|
|
&& at[emsg].a_type != A_SEMI; emsg++)
|
|
|
|
;
|
|
|
|
if (emsg > msg)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = msg; i < emsg; i++)
|
|
|
|
if (at[i].a_type == A_DOLLAR || at[i].a_type == A_DOLLSYM)
|
|
|
|
{
|
|
|
|
pd_error(x, "netreceive: got dollar sign in message");
|
|
|
|
goto nodice;
|
|
|
|
}
|
|
|
|
if (at[msg].a_type == A_FLOAT)
|
|
|
|
{
|
|
|
|
if (emsg > msg + 1)
|
|
|
|
outlet_list(x->x_obj.ob_outlet, 0, emsg-msg, at + msg);
|
|
|
|
else outlet_float(x->x_obj.ob_outlet, at[msg].a_w.w_float);
|
|
|
|
}
|
|
|
|
else if (at[msg].a_type == A_SYMBOL)
|
|
|
|
outlet_anything(x->x_obj.ob_outlet, at[msg].a_w.w_symbol,
|
|
|
|
emsg-msg-1, at + msg + 1);
|
|
|
|
}
|
|
|
|
nodice:
|
|
|
|
msg = emsg + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void shell_read(t_shell *x, int fd)
|
|
|
|
{
|
|
|
|
char buf[INBUFSIZE];
|
|
|
|
t_binbuf* bbuf = binbuf_new();
|
|
|
|
int i;
|
|
|
|
int readto =
|
|
|
|
(x->sr_inhead >= x->sr_intail ? INBUFSIZE : x->sr_intail-1);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = read(fd, buf,INBUFSIZE-1);
|
|
|
|
buf[ret] = '\0';
|
|
|
|
|
|
|
|
for (i=0;i<ret;i++)
|
|
|
|
if (buf[i] == '\n') buf[i] = ';';
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
error("shell: pipe read error");
|
|
|
|
sys_rmpollfn(fd);
|
|
|
|
x->fdpipe[0] = -1;
|
|
|
|
close(fd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (ret == 0)
|
|
|
|
{
|
|
|
|
post("EOF on socket %d\n", fd);
|
|
|
|
sys_rmpollfn(fd);
|
|
|
|
x->fdpipe[0] = -1;
|
|
|
|
close(fd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int natom;
|
|
|
|
t_atom *at;
|
|
|
|
binbuf_text(bbuf, buf, strlen(buf));
|
|
|
|
|
|
|
|
natom = binbuf_getnatom(bbuf);
|
|
|
|
at = binbuf_getvec(bbuf);
|
|
|
|
shell_doit(x,bbuf);
|
|
|
|
}
|
|
|
|
binbuf_free(bbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void shell_send(t_shell *x, t_symbol *s,int ac, t_atom *at)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char tmp[MAXPDSTRING];
|
|
|
|
int size = 0;
|
|
|
|
|
|
|
|
if (x->fdinpipe[0] == -1) return; /* nothing to send to */
|
|
|
|
|
|
|
|
for (i=0;i<ac;i++) {
|
|
|
|
atom_string(at,tmp+size,MAXPDSTRING - size);
|
|
|
|
at++;
|
|
|
|
size=strlen(tmp);
|
|
|
|
tmp[size++] = ' ';
|
|
|
|
}
|
|
|
|
tmp[size-1] = '\0';
|
|
|
|
post("sending %s",tmp);
|
|
|
|
write(x->fdinpipe[0],tmp,strlen(tmp));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void shell_anything(t_shell *x, t_symbol *s, int ac, t_atom *at)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char* argv[20];
|
|
|
|
t_symbol* sym;
|
|
|
|
|
|
|
|
if (!strcmp(s->s_name,"send")) {
|
|
|
|
post("send");
|
|
|
|
shell_send(x,s,ac,at);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
argv[0] = s->s_name;
|
|
|
|
|
|
|
|
if (x->fdpipe[0] != -1) {
|
|
|
|
post("shell: old process still running");
|
|
|
|
kill(x->pid,SIGKILL);
|
|
|
|
shell_cleanup(x);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (pipe(x->fdpipe) < 0) {
|
|
|
|
error("unable to create pipe");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pipe(x->fdinpipe) < 0) {
|
|
|
|
error("unable to create input pipe");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
sys_addpollfn(x->fdpipe[0],shell_read,x);
|
|
|
|
|
|
|
|
if (!(x->pid = fork())) {
|
|
|
|
int status;
|
|
|
|
char* cmd = getbytes(1024);
|
|
|
|
char* tcmd = getbytes(1024);
|
|
|
|
strcpy(cmd,s->s_name);
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
for (i=1;i<=ac;i++) {
|
|
|
|
argv[i] = getbytes(255);
|
|
|
|
atom_string(at,argv[i],255);
|
|
|
|
/* post("argument %s",argv[i]); */
|
|
|
|
at++;
|
|
|
|
}
|
|
|
|
argv[i] = 0;
|
|
|
|
#endif
|
|
|
|
for (i=1;i<=ac;i++) {
|
|
|
|
atom_string(at,tcmd,255);
|
|
|
|
strcat(cmd," ");
|
|
|
|
strcat(cmd,tcmd);
|
|
|
|
at++;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* reassign stdout */
|
|
|
|
dup2(x->fdpipe[1],1);
|
|
|
|
dup2(x->fdinpipe[1],0);
|
|
|
|
|
|
|
|
/* drop privileges */
|
|
|
|
drop_priority();
|
|
|
|
seteuid(getuid()); /* lose setuid priveliges */
|
|
|
|
|
|
|
|
post("executing %s",cmd);
|
|
|
|
system(cmd);
|
|
|
|
// execvp(s->s_name,argv);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
x->x_del = 4;
|
|
|
|
clock_delay(x->x_clock,x->x_del);
|
|
|
|
|
|
|
|
if (x->x_echo)
|
|
|
|
outlet_anything(x->x_obj.ob_outlet, s, ac, at);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void shell_free(t_shell* x)
|
|
|
|
{
|
|
|
|
binbuf_free(x->x_binbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *shell_new(void)
|
|
|
|
{
|
|
|
|
t_shell *x = (t_shell *)pd_new(shell_class);
|
|
|
|
|
|
|
|
x->x_echo = 0;
|
|
|
|
x->fdpipe[0] = -1;
|
|
|
|
x->fdpipe[1] = -1;
|
|
|
|
x->fdinpipe[0] = -1;
|
|
|
|
x->fdinpipe[1] = -1;
|
|
|
|
|
|
|
|
x->sr_inhead = x->sr_intail = 0;
|
|
|
|
if (!(x->sr_inbuf = (char*) malloc(INBUFSIZE))) bug("t_shell");;
|
|
|
|
|
|
|
|
x->x_binbuf = binbuf_new();
|
|
|
|
|
|
|
|
outlet_new(&x->x_obj, &s_list);
|
|
|
|
x->x_done = outlet_new(&x->x_obj, &s_bang);
|
|
|
|
x->x_clock = clock_new(x, (t_method) shell_check);
|
|
|
|
return (x);
|
|
|
|
}
|
|
|
|
|
|
|
|
void shell_setup(void)
|
|
|
|
{
|
|
|
|
shell_class = class_new(gensym("shell"), (t_newmethod)shell_new,
|
|
|
|
(t_method)shell_free,sizeof(t_shell), 0,0);
|
|
|
|
class_addbang(shell_class,shell_bang);
|
|
|
|
class_addanything(shell_class, shell_anything);
|
|
|
|
}
|
|
|
|
|
2009-05-24 21:28:16 +00:00
|
|
|
|