From b9b693eafe2925f323f54ff6444e09dbe8d9591a Mon Sep 17 00:00:00 2001 From: blatzfab Date: Thu, 15 Oct 2020 21:28:36 +0000 Subject: [PATCH] Adds ssh aware spawn command --- config.def.h | 2 +- config.mk | 3 +- dwm.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+), 2 deletions(-) diff --git a/config.def.h b/config.def.h index 1c0b587..1a26f32 100644 --- a/config.def.h +++ b/config.def.h @@ -62,7 +62,7 @@ static const char *termcmd[] = { "st", NULL }; static Key keys[] = { /* modifier key function argument */ { MODKEY, XK_p, spawn, {.v = dmenucmd } }, - { MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } }, + { MODKEY|ShiftMask, XK_Return, spawnsshaware, {.v = termcmd } }, { MODKEY, XK_b, togglebar, {0} }, { MODKEY, XK_j, focusstack, {.i = +1 } }, { MODKEY, XK_k, focusstack, {.i = -1 } }, diff --git a/config.mk b/config.mk index 7084c33..bc99153 100644 --- a/config.mk +++ b/config.mk @@ -19,10 +19,11 @@ FREETYPELIBS = -lfontconfig -lXft FREETYPEINC = /usr/include/freetype2 # OpenBSD (uncomment) #FREETYPEINC = ${X11INC}/freetype2 +#KVMLIB = -lkvm # includes and libs INCS = -I${X11INC} -I${FREETYPEINC} -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lX11-xcb -lxcb -lxcb-res ${KVMLIB} -lprocps # flags CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} diff --git a/dwm.c b/dwm.c index 664c527..0f623ea 100644 --- a/dwm.c +++ b/dwm.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include #include @@ -40,6 +42,12 @@ #include #endif /* XINERAMA */ #include +#include +#include +#ifdef __OpenBSD__ +#include +#include +#endif /* __OpenBSD */ #include "drw.h" #include "util.h" @@ -93,6 +101,7 @@ struct Client { int bw, oldbw; unsigned int tags; int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen; + pid_t pid; Client *next; Client *snext; Monitor *mon; @@ -156,6 +165,8 @@ static void clientmessage(XEvent *e); static void configure(Client *c); static void configurenotify(XEvent *e); static void configurerequest(XEvent *e); +static char* checksshsession(pid_t process); +static int checkparents(pid_t pid, pid_t target); static Monitor *createmon(void); static void destroynotify(XEvent *e); static void detach(Client *c); @@ -172,6 +183,7 @@ static void focusstack(const Arg *arg); static Atom getatomprop(Client *c, Atom prop); static int getrootptr(int *x, int *y); static long getstate(Window w); +static int getprocinfo(pid_t pid, proc_t *procinfo); static int gettextprop(Window w, Atom atom, char *text, unsigned int size); static void grabbuttons(Client *c, int focused); static void grabkeys(void); @@ -207,6 +219,8 @@ static void seturgent(Client *c, int urg); static void showhide(Client *c); static void sigchld(int unused); static void spawn(const Arg *arg); +static void spawnsshaware(const Arg *arg); +static int strtopid(char *s, pid_t *pid); static void tag(const Arg *arg); static void tagmon(const Arg *arg); static void tile(Monitor *); @@ -230,6 +244,7 @@ static void updatewmhints(Client *c); static void view(const Arg *arg); static Client *wintoclient(Window w); static Monitor *wintomon(Window w); +static pid_t winpid(Window w); static int xerror(Display *dpy, XErrorEvent *ee); static int xerrordummy(Display *dpy, XErrorEvent *ee); static int xerrorstart(Display *dpy, XErrorEvent *ee); @@ -268,6 +283,7 @@ static Display *dpy; static Drw *drw; static Monitor *mons, *selmon; static Window root, wmcheckwin; +static xcb_connection_t *xcon; /* configuration, allows nested code to access above variables */ #include "config.h" @@ -628,6 +644,62 @@ configurerequest(XEvent *e) XSync(dpy, False); } +int +checkparents(pid_t pid, pid_t target) +{ + proc_t *pinf = calloc(1, sizeof(proc_t)); + pid_t current = pid; + + while(current!=(pid_t)0 && current!=(pid_t)1 && current!=target){ + getprocinfo(current, pinf); + current = pinf->ppid; + } + freeproc(pinf); + if(current==target) + return 1; + return 0; +} + +char* +checksshsession(pid_t process) +{ + struct dirent *dp; + DIR *dfd; + const char *dir = "/proc"; + char filename_qfd[100] ; + pid_t pid; + proc_t* process_info = calloc(1, sizeof(proc_t)); + struct stat stbuf; + char* res = 0; + + if ((dfd = opendir(dir)) == NULL) { + fprintf(stderr, "Can't open %s\n", dir); + freeproc(process_info); + return 0; + } + + while ((dp = readdir(dfd)) != NULL && res == 0) { + sprintf( filename_qfd , "%s/%s",dir,dp->d_name); + if(stat(filename_qfd,&stbuf ) == -1) { + fprintf(stderr, "Unable to stat file: %s\n",filename_qfd); + continue; + } + if (((stbuf.st_mode & S_IFMT) == S_IFDIR) && strtopid(dp->d_name, &pid)) { + getprocinfo(pid, process_info); + if(!process_info->cmdline) + continue; + char* cmdline = *process_info->cmdline; + if(strncmp("ssh ", cmdline, 4) == 0 && checkparents(pid, process)){ + res = calloc(strlen(cmdline)+1, sizeof(char)); + strcpy(res, cmdline); + } + } + } + freeproc(process_info); + free(dfd); + return res; +} + Monitor * createmon(void) { @@ -900,6 +972,19 @@ getstate(Window w) return result; } +int +getprocinfo(pid_t pid, proc_t *procinfo) +{ + int res = 1; + if(!procinfo) + return 0; + PROCTAB *pt_ptr = openproc(PROC_FILLARG | PROC_EDITCMDLCVT | PROC_FILLSTATUS | PROC_PID, &pid); + if(readproc(pt_ptr, procinfo)) + res = 0; + closeproc(pt_ptr); + return res; +} + int gettextprop(Window w, Atom atom, char *text, unsigned int size) { @@ -1024,6 +1109,7 @@ manage(Window w, XWindowAttributes *wa) c = ecalloc(1, sizeof(Client)); c->win = w; + c->pid = winpid(w); /* geometry */ c->x = c->oldx = wa->x; c->y = c->oldy = wa->y; @@ -1637,6 +1723,38 @@ sigchld(int unused) while (0 < waitpid(-1, NULL, WNOHANG)); } +void +spawnsshaware(const Arg *arg) +{ + if(selmon->sel) { + char* sshcmdline = checksshsession(selmon->sel->pid); + if(sshcmdline){ + const char* sshcmd[] = {"st", "-e", "/bin/bash", "-c", sshcmdline, NULL}; + Arg a = {.v=sshcmd}; + spawn(&a); + free(sshcmdline); + }else{ + spawn(arg); + } + }else{ + spawn(arg); + } +} + +int +strtopid(char *s, pid_t *pid) +{ + long result = 0; + char *eptr; + if(!pid) + return 0; + result = strtol(s, &eptr, 10); + if((eptr && *eptr!='\0') || errno == ERANGE) + return 0; + *pid=(pid_t) result; + return 1; +} + void spawn(const Arg *arg) { @@ -2077,6 +2195,59 @@ wintomon(Window w) return selmon; } +pid_t +winpid(Window w) +{ + + pid_t result = 0; + + #ifdef __linux__ + xcb_res_client_id_spec_t spec = {0}; + spec.client = w; + spec.mask = XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID; + + xcb_generic_error_t *e = NULL; + xcb_res_query_client_ids_cookie_t c = xcb_res_query_client_ids(xcon, 1, &spec); + xcb_res_query_client_ids_reply_t *r = xcb_res_query_client_ids_reply(xcon, c, &e); + + if (!r) + return (pid_t)0; + + xcb_res_client_id_value_iterator_t i = xcb_res_query_client_ids_ids_iterator(r); + for (; i.rem; xcb_res_client_id_value_next(&i)) { + spec = i.data->spec; + if (spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { + uint32_t *t = xcb_res_client_id_value_value(i.data); + result = *t; + break; + } + } + + free(r); + + if (result == (pid_t)-1) + result = 0; + + #endif /* __linux__ */ + + #ifdef __OpenBSD__ + Atom type; + int format; + unsigned long len, bytes; + unsigned char *prop; + pid_t ret; + + if (XGetWindowProperty(dpy, w, XInternAtom(dpy, "_NET_WM_PID", 1), 0, 1, False, AnyPropertyType, &type, &format, &len, &bytes, &prop) != Success || !prop) + return 0; + + ret = *(pid_t*)prop; + XFree(prop); + result = ret; + + #endif /* __OpenBSD__ */ + return result; +} + /* There's no way to check accesses to destroyed windows, thus those cases are * ignored (especially on UnmapNotify's). Other types of errors call Xlibs * default error handler, which may call exit. */ @@ -2138,6 +2309,8 @@ main(int argc, char *argv[]) fputs("warning: no locale support\n", stderr); if (!(dpy = XOpenDisplay(NULL))) die("dwm: cannot open display"); + if (!(xcon = XGetXCBConnection(dpy))) + die("dwm: cannot get xcb connection\n"); checkotherwm(); setup(); #ifdef __OpenBSD__ -- 2.28.0