esc
Externally Scriptable Editor
git clone git://mccd.space/esc
| Log | Files | Refs | README |
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