On 01/11/2018 13:43, Markus Wichmann wrote: > On Thu, Nov 01, 2018 at 08:46:06AM +0100, John Soros wrote: >> config.def.h | 6 +++++ >> x.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 82 insertions(+) >> >> diff --git a/config.def.h b/config.def.h >> index 87ebdbb..265a4ff 100644 >> --- a/config.def.h >> +++ b/config.def.h >> @@ -467,3 +467,9 @@ static char ascii_printable[] = >> " !\"#$%&'()*+,-./0123456789:;<=>?" >> "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" >> "`abcdefghijklmnopqrstuvwxyz{|}~"; >> + >> +/* >> + * plumber_cmd is run on mouse button 3 click, with argument set to >> + * current selection and with cwd set to the cwd of the active shell >> + */ >> +static char *plumber_cmd = "plumb"; >> diff --git a/x.c b/x.c >> index 4345892..f319129 100644 >> --- a/x.c >> +++ b/x.c >> @@ -5,6 +5,9 @@ >> #include <locale.h> >> #include <signal.h> >> #include <sys/select.h> >> +#include <sys/stat.h> >> +#include <sys/wait.h> >> +#include <dirent.h> >> #include <time.h> >> #include <unistd.h> >> #include <libgen.h> >> @@ -644,6 +647,77 @@ xsetsel(char *str) >> setsel(str, CurrentTime); >> } >> >> +char * >> +subprocwd() >> +{ >> + struct dirent* dent; >> + DIR* srcdir = opendir("/proc/self/task"); >> + char path[PATH_MAX]; >> + FILE *fp; >> + int chpid; >> + >> + if (srcdir == NULL) >> + { >> + return NULL; >> + } >> + >> + while((dent = readdir(srcdir)) != NULL) >> + { >> + struct stat st; >> + char newdir[PATH_MAX]; >> + >> + if(strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") >> == 0) >> + continue; >> + if (snprintf(newdir, PATH_MAX, "%s/%s", "/proc/self/task", >> dent->d_name) < 0) >> + return NULL; >> + if (stat(newdir, &st) < 0) >> + continue; >> + >> + if (S_ISDIR(st.st_mode)) break; >> + } >> + closedir(srcdir); >> + if (snprintf(path, PATH_MAX, "/proc/self/task/%s/children", >> dent->d_name) < 0) >> + return NULL; >> + if (!(fp = fopen(path, "r"))) >> + return NULL; >> + if (fscanf(fp, "%d", &chpid) != 1) { >> + fclose(fp); >> + return NULL; >> + } >> + fclose(fp); >> + if (snprintf(path, PATH_MAX, "/proc/%d/cwd", chpid) < 0) >> + return NULL; >> + return realpath(path, NULL); >> +} >> + > > You know, you can have that one cheaper: /proc/self/task will contain a > directory named for the TIDs of each thread of the process. As st is a > single-threaded process, that TID must always equal the PID. So the > first loop can be replaced with. > > snprintf(path, PATH_MAX, "/proc/self/task/%d/children", getpid()); > > Also, your code assumes the shell to be the only child of st, but spawns > other children of st. How about you iterate over all processes, finding > the ones with a PPID equaling st's PID and having an exe pointing to the > shell (maybe remember the shell spawned in a global variable)? Speaking > of remembering things, might it not be easier to just remember the > shell's PID from the point it was spawned in the first place? Then you > don't need to iterate over rarely-available system interfaces. > >> +void >> +plumb(char *sel) { >> + if (sel == NULL) >> + return; >> + char *cwd; >> + char *cmd; >> + pid_t child; >> + cwd = subprocwd(); >> + if (cwd == NULL) >> + return; >> + > > So, if it all failed somehow, you won't even spawn the command in st's > current directory? Nor give any indication of failure to the user. > >> + switch(child = fork()) { >> + case -1: >> + return; >> + case 0: >> + if (cwd == NULL) >> + exit(1); >> + cmd = malloc(PATH_MAX+100); >> + if (snprintf(cmd, PATH_MAX+100, "(cd %s ; %s %s)", cwd, >> plumber_cmd, >> sel) < 0) >> + exit(1); >> + free(cwd); >> + execvp("sh", (char *const []){"sh", "-c", cmd, 0}); >> + exit(0); > > This won't work if there is a space in cwd. Which there might be. Also, > why change dir in the shell? Just change dir in the process. You have > the directory right there, just call chdir() and call it a day. > > Also, do you want word separation to take place? Because if not, I see > no reason for the shell at all. > > Ciao, > Markus >
Thanks for the comments and advise. I will try to implement them soon. As far as I can see, there is no solution for this on OpenBSD. Regs, John