esc

Externally Scriptable Editor

git clone git://mccd.space/esc

unix_utils.c (3182B)

      1 #include "unix_utils.h"
      2 #include <fcntl.h>
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 #include <sys/wait.h>
      7 #include <unistd.h>
      8 
      9 char *unix_select_command(void) {
     10 	const char *menu_cmd = getenv("ESC_MENU");
     11 	if (!menu_cmd)
     12 		menu_cmd = "wmenu";
     13 
     14 	// Build the PATH-searching pipeline
     15 	char menu_call[1024];
     16 	snprintf(
     17 	    menu_call, sizeof(menu_call),
     18 	    "echo $PATH | tr ':' '\\n' | xargs -I{} find {} -maxdepth 1 "
     19 	    "-executable -type f -printf \"%%f\\n\" 2>/dev/null | sort -u | %s",
     20 	    menu_cmd);
     21 
     22 	FILE *pipe = popen(menu_call, "r");
     23 	if (!pipe)
     24 		return NULL;
     25 
     26 	char *line = NULL;
     27 	size_t len = 0;
     28 	if (getline(&line, &len, pipe) == -1) {
     29 		free(line);
     30 		line = NULL;
     31 	} 
     32 	pclose(pipe);
     33 	return line;
     34 }
     35 
     36 char *unix_run_command(const char *command, const char *input) {
     37 	int pipe_in[2];
     38 	int pipe_out[2];
     39 
     40 	if (pipe(pipe_in) < 0 || pipe(pipe_out) < 0)
     41 		return NULL;
     42 
     43 	pid_t pid = fork();
     44 	if (pid == 0) {
     45 		dup2(pipe_in[0], STDIN_FILENO);
     46 		dup2(pipe_out[1], STDOUT_FILENO);
     47 		dup2(pipe_out[1], STDERR_FILENO);
     48 
     49 		close(pipe_in[0]);
     50 		close(pipe_in[1]);
     51 		close(pipe_out[0]);
     52 		close(pipe_out[1]);
     53 
     54 		execl("/bin/sh", "sh", "-c", command, NULL);
     55 		exit(1);
     56 	}
     57 
     58 	close(pipe_in[0]);
     59 	close(pipe_out[1]);
     60 
     61 	if (input && strlen(input) > 0) {
     62 		write(pipe_in[1], input, strlen(input));
     63 
     64 		if (input[strlen(input) - 1] != '\n') {
     65 			write(pipe_in[1], "\n", 1);
     66 		}
     67 	}
     68 	close(pipe_in[1]);
     69 
     70 	char *out_buf = NULL;
     71 	size_t out_size = 0;
     72 	FILE *mstream = open_memstream(&out_buf, &out_size);
     73 
     74 	char chunk[1024];
     75 	ssize_t n;
     76 	while ((n = read(pipe_out[0], chunk, sizeof(chunk))) > 0) {
     77 		fwrite(chunk, 1, n, mstream);
     78 	}
     79 
     80 	fclose(mstream);
     81 	close(pipe_out[0]);
     82 	waitpid(pid, NULL, 0);
     83 
     84 	// Remove trailing newlines
     85 	// ... This might not be needed
     86 	if (out_buf && out_size > 0) {
     87 		if (out_buf[out_size - 1] == '\n') {
     88 			out_buf[out_size - 1] = '\0';
     89 			if (out_size > 1 && out_buf[out_size - 2] == '\r') {
     90 				out_buf[out_size - 2] = '\0';
     91 			}
     92 		}
     93 	}
     94 
     95 	return out_buf;
     96 }
     97 
     98 // Ignores output and completely detaches the process
     99 void unix_exec_command(const char *command, const char *input) {
    100     int pipe_in[2];
    101     if (input && pipe(pipe_in) < 0) return;
    102 
    103     pid_t pid = fork();
    104     if (pid == 0) { 
    105         if (fork() == 0) {
    106             setsid(); 
    107 
    108             if (input) {
    109                 dup2(pipe_in[0], STDIN_FILENO);
    110                 close(pipe_in[0]);
    111                 close(pipe_in[1]);
    112             }
    113 
    114             int dev_null = open("/dev/null", O_RDWR);
    115             if (dev_null != -1) {
    116                 if (!input) dup2(dev_null, STDIN_FILENO);
    117                 dup2(dev_null, STDOUT_FILENO);
    118                 dup2(dev_null, STDERR_FILENO);
    119                 if (dev_null > STDERR_FILENO) close(dev_null);
    120             }
    121 
    122             execl("/bin/sh", "sh", "-c", command, NULL);
    123             exit(1);
    124         }
    125         exit(0); 
    126     }
    127 
    128     if (input) {
    129         close(pipe_in[0]);
    130         if (strlen(input) > 0) {
    131             write(pipe_in[1], input, strlen(input));
    132             if (input[strlen(input) - 1] != '\n') {
    133                 write(pipe_in[1], "\n", 1);
    134             }
    135         }
    136         close(pipe_in[1]);
    137     }
    138    
    139     waitpid(pid, NULL, 0); 
    140 }
    141