libk8sterm: rewritten ESC sequences parsing (some code cleanups, on-the-fly parsing...
[k8sterm.git] / src / ttyinit.c
blobd8b4c09e5ded3d543e593904d64b9311c92bcbd3
1 #include <sys/time.h>
2 #include <sys/resource.h>
4 //#define K8STERM_DEBUG_EXEC
7 ////////////////////////////////////////////////////////////////////////////////
8 // tty init
9 /*
10 static void dump (char c) {
11 static int col;
13 fprintf(stderr, " %02x '%c' ", c, isprint(c)?c:'.');
14 if (++col % 10 == 0) fprintf(stderr, "\n");
18 typedef struct {
19 char **args;
20 int argc;
21 } ExecData;
24 static void execsh_free (ExecData *ed) {
25 if (!ed) return;
26 if (ed->args) {
27 for (int f = 0; f < ed->argc; ++f) free(ed->args[f]);
28 free(ed->args);
30 memset(ed, 0, sizeof(*ed));
34 static int execsh_prepare (ExecData *ed, const char *str) {
35 if (!ed) return -1;
36 #ifdef K8STERM_DEBUG_EXEC
37 FILE *fo = stderr; //fopen("/tmp/z_k8sterm_exec_debug.log", "w");
38 #endif
40 memset(ed, 0, sizeof(*ed));
41 char **args;
42 int argc;
43 if (str == NULL) {
44 char *envshell = getenv("SHELL");
45 if (envshell == NULL) envshell = "/bin/sh";
46 K8T_DEFAULT(envshell, opt_shell);
47 setenv("TERM", opt_term, 1);
48 //args = (opt_cmd ? opt_cmd : (char *[]){envshell, "-i", NULL});
49 if (opt_cmd && opt_cmd_count > 0) {
50 #ifdef K8STERM_DEBUG_EXEC
51 if (fo) fprintf(fo, "EXECSH: executing `opt_cmd` (%d): <%s>\n", opt_cmd_count, opt_cmd[0]);
52 #endif
53 args = calloc(opt_cmd_count+1, sizeof(char*));
54 if (!args) return -1;
55 argc = opt_cmd_count;
56 for (int f = 0; f < opt_cmd_count; ++f) {
57 #ifdef K8STERM_DEBUG_EXEC
58 if (fo) fprintf(fo, "EXECSH: arg #%d of %d: <%s>\n", f, opt_cmd_count, opt_cmd[f]);
59 #endif
60 args[f] = strdup(opt_cmd[f]);
61 if (!args[f]) {
62 for (int c = 0; c < f; ++c) free(args[c]);
63 free(args);
64 return -1;
67 args[argc] = NULL;
68 } else {
69 args = calloc(3, sizeof(char*));
70 if (!args) return -1;
71 #ifdef K8STERM_DEBUG_EXEC
72 if (fo) fprintf(fo, "EXECSH: executing `opt_cmd` shell: <%s>\n", envshell);
73 #endif
74 argc = 2;
75 args[0] = strdup(envshell);
76 if (!args[0]) { free(args); return -1; }
77 args[1] = strdup("-i");
78 if (!args[1]) { free(args[0]); free(args); return -1; }
79 args[2] = NULL;
81 } else {
82 #ifdef K8STERM_DEBUG_EXEC
83 if (fo) fprintf(fo, "EXECSH: executing `str`: <%s>\n", str);
84 #endif
85 argc = 0;
86 args = calloc(32768, sizeof(char *));
87 if (args == NULL) return -1;
88 while (*str) {
89 if (argc >= 32766) break;
90 const char *b;
91 while (*str && isspace(*str)) ++str;
92 if (!str[0]) break;
93 b = str;
94 while (*str && !isspace(*str)) {
95 if (*str++ == '\\') {
96 if (*str) ++str;
99 args[argc] = calloc(str-b+1, 1);
100 if (!args[argc]) {
101 for (int f = 0; f < argc; ++f) free(args[f]);
102 free(args);
103 return -1;
105 memcpy(args[argc], b, str-b);
106 #ifdef K8STERM_DEBUG_EXEC
107 if (fo) fprintf(fo, "EXECSH: argc=%d; argv=<%s>\n", argc, args[argc]);
108 #endif
109 ++argc;
111 args[argc] = NULL;
113 #ifdef K8STERM_DEBUG_EXEC
114 if (fo && fo != stdout && fo != stderr) fclose(fo);
115 #endif
117 ed->args = args;
118 ed->argc = argc;
119 if (argc < 1) { execsh_free(ed); return -1; }
120 return 0;
124 static __attribute__((noreturn)) void execsh (ExecData *ed) {
125 if (!ed) exit(EXIT_FAILURE);
126 if (ed->argc == 0) exit(EXIT_FAILURE);
129 extern char **environ;
130 FILE *fo = fopen("z.log", "a");
131 for (char **e = environ; *e; ++e) {
132 fprintf(fo, "[%s]\n", *e);
134 fclose(fo);
137 // close FDs
139 struct rlimit r;
140 getrlimit(RLIMIT_NOFILE, &r);
141 for (rlim_t f = 3; f < r.rlim_cur; ++f) close(f);
143 execvp(ed->args[0], ed->args);
144 exit(EXIT_FAILURE);
148 static int k8t_ttyNew (K8Term *term) {
149 int masterfd = -1;
150 struct winsize w = {term->row, term->col, 0, 0};
151 ExecData ed;
152 if (execsh_prepare(&ed, K8T_DATA(term)->execcmd) != 0) {
153 fprintf(stderr, "EXEC <%s> failed!\n", K8T_DATA(term)->execcmd);
154 return -1;
156 switch (K8T_DATA(term)->pid = forkpty(&masterfd, NULL, NULL, &w)) {
157 case -1: /* error */
158 execsh_free(&ed);
159 fprintf(stderr, "fork failed");
160 if (masterfd != -1) close(masterfd);
161 return -1;
162 case 0: /* child */
163 setsid(); /* create a new process group */
164 execsh(&ed);
165 break;
166 default: /* master */
167 execsh_free(&ed);
168 term->cmdfd = masterfd;
169 term->dead = 0;
170 k8t_ttyResize(term);
171 break;
173 return 0;
176 #if 0
177 static int k8t_ttyNew (K8Term *term) {
178 int m, s;
179 struct winsize w = {term->row, term->col, 0, 0};
181 if (openpty(&m, &s, NULL, NULL, &w) < 0) k8t_die("openpty failed: %s", strerror(errno));
182 term->cmdfd = m;
183 k8t_ttyResize(term);
184 term->cmdfd = -1;
185 switch (K8T_DATA(term)->pid = fork()) {
186 case -1: /* error */
187 fprintf(stderr, "fork failed");
188 return -1;
189 case 0: /* child */
190 setsid(); /* create a new process group */
191 dup2(s, STDIN_FILENO);
192 dup2(s, STDOUT_FILENO);
193 dup2(s, STDERR_FILENO);
194 if (ioctl(s, TIOCSCTTY, NULL) < 0) k8t_die("ioctl TIOCSCTTY failed: %s", strerror(errno));
195 close(s);
196 close(m);
197 execsh(K8T_DATA(term)->execcmd);
198 break;
199 default: /* master */
200 close(s);
201 term->cmdfd = m;
202 term->dead = 0;
203 k8t_ttyResize(term);
204 break;
206 return 0;
208 #endif