Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

signals mostly work over the pty now

- ^C, ^Z, and ^\ weren't working because bash disables SIGINT, SIGQUIT
  and SIGTSTP when a command is started in the background with &.
- So I wrote another C wrapper called drip_daemon to start a background
  process without disabling these signals.
- I also moved the setsid() call from java in to drip_daemon.
  • Loading branch information...
commit a8cd938700ef7e569f12f14850b50e824c4a2fcb 1 parent cf6b89b
Justin Balthrop ninjudd authored
3  .gitignore
@@ -2,4 +2,5 @@
2 2 *.class
3 3 *.jar
4 4 *.tgz
5   -test/scala
  5 +test/scala
  6 +repl-port
52 bin/drip
@@ -45,15 +45,26 @@ function bootstrap {
45 45 DRIP_JAR=$(mvn_get 'drip' 'org/flatland' "$DRIP_VERSION" "$DRIP_JAR_URL")
46 46 fi
47 47 fi
  48 + drip_proxy=$(compile 'drip_proxy')
  49 + drip_daemon=$(compile 'drip_daemon')
  50 +}
  51 +
  52 +function compile {
  53 + local base=$1
  54 + local src_file
  55 + local bin_file="$DRIP_HOME/$base"
48 56
49 57 if [[ -z $drip_dir ]]; then
50   - [[ -e $DRIP_PROXY_SRC ]] || http_get "$DRIP_PROXY_URL" "$proxy_src"
  58 + mkdir -p "$DRIP_SRC"
  59 + src_file=$DRIP_SRC/$base.c
  60 + [[ -e $src_file ]] || http_get "$DRIP_SRC_URL/$base.c" "$src_file"
51 61 else
52   - DRIP_PROXY_SRC=$drip_dir/src/drip_proxy.c
  62 + src_file=$drip_dir/src/$base.c
53 63 fi
54   - if [[ $DRIP_PROXY_SRC -nt $DRIP_PROXY ]]; then
55   - gcc $DRIP_PROXY_SRC -o $DRIP_PROXY
  64 + if [[ $src_file -nt $bin_file ]]; then
  65 + gcc $src_file -o $bin_file
56 66 fi
  67 + echo "$bin_file"
57 68 }
58 69
59 70 function mvn_get {
@@ -132,21 +143,15 @@ function launch_jvm {
132 143
133 144 export DRIP_INIT=${DRIP_INIT:-$(default_init_args)}
134 145
135   - { # Need to write the exit status to a file.
136   - java "${jvm_args[@]}" -Djava.awt.headless=true "-Xbootclasspath/a:$DRIP_JAR:$JNA_JAR" \
137   - org.flatland.drip.Main "$main_class" "$jvm_dir" &
138   - echo $! > "$jvm_dir/pid"
139   - wait %%
140   - status=$?
141   - [[ -e $jvm_dir/status ]] && echo $status > "$jvm_dir/status"
142   - } > /dev/null &
143   - disown %%
  146 + $drip_daemon $JAVA_CMD "${jvm_args[@]}" -Djava.awt.headless=true \
  147 + "-Xbootclasspath/a:$DRIP_JAR:$JNA_JAR" \
  148 + org.flatland.drip.Main "$main_class" "$jvm_dir" > /dev/null
144 149 fi
145 150 }
146 151
147 152 function lock_dir {
148 153 if mkdir "$jvm_dir/lock" 2> /dev/null; then
149   - if kill -0 $(cat "$jvm_dir/pid") 2> /dev/null; then
  154 + if kill -0 $(cat "$jvm_dir/jvm.pid") 2> /dev/null; then
150 155 echo $$ > "$jvm_dir/client.pid"
151 156 active_jvm_dir=$jvm_dir
152 157 fi
@@ -175,7 +180,7 @@ function find_jvm {
175 180 done
176 181
177 182 if [[ -z $active_jvm_dir ]]; then
178   - exec java "${jvm_args[@]}" "${runtime_args[@]}" "$main_class" "${main_args[@]}"
  183 + exec $JAVA_CMD "${jvm_args[@]}" "${runtime_args[@]}" "$main_class" "${main_args[@]}"
179 184 fi
180 185 }
181 186
@@ -184,7 +189,7 @@ function kill_jvms {
184 189
185 190 for jvm_dir in $DRIP_HOME/*/*/*-*; do
186 191 if lock_dir; then
187   - kill "$1" "$(cat $jvm_dir/pid)" 2> /dev/null
  192 + kill "$1" "$(cat $jvm_dir/jvm.pid)" 2> /dev/null
188 193 rm -rf "$jvm_dir"
189 194 killed=true
190 195 fi
@@ -240,7 +245,7 @@ function wait_for_exit {
240 245
241 246 function run_main {
242 247 send_args
243   - $DRIP_PROXY "$active_jvm_dir"/{in,out,err}
  248 + $drip_proxy "$active_jvm_dir"/{in,out,err}
244 249
245 250 wait_for_exit
246 251
@@ -251,7 +256,7 @@ function run_drip_command {
251 256 case $drip_command in
252 257 version)
253 258 echo "drip version \"$DRIP_VERSION\"" >&2
254   - java -version;;
  259 + $JAVA_CMD -version;;
255 260 kill)
256 261 kill_jvms "$2";;
257 262 ps)
@@ -260,7 +265,7 @@ function run_drip_command {
260 265 if [[ -z $drip_dir ]]; then
261 266 http_get "$DRIP_BIN_URL" "$script" || exit $?
262 267 chmod +x "$script"
263   - rm "$DRIP_PROXY_SRC" # need to refetch in case it has changed
  268 + rm -rf "$DRIP_SRC" # need to refetch in case it has changed
264 269 elif [[ -d $drip_dir/.git ]]; then
265 270 (cd "$drip_dir" && git pull)
266 271 else
@@ -283,19 +288,20 @@ DRIP_VERSION=${DRIP_VERSION:-0.0.4}
283 288 DRIP_REPO=${DRIP_REPO:-http://clojars.org/repo}
284 289 DRIP_JAR_URL=${DRIP_JAR_URL:-$DRIP_REPO/org/flatland/drip/$DRIP_VERSION/drip-$DRIP_VERSION.jar}
285 290 DRIP_BIN_URL=${DRIP_BIN_URL:-https://raw.github.com/flatland/drip/master/bin/drip}
286   -DRIP_PROXY_URL=${DRIP_PROXY_URL:-https://raw.github.com/flatland/drip/master/src/drip_proxy.c}
287   -DRIP_PROXY_SRC=${DRIP_PROXY_SRC:-$DRIP_HOME/drip_proxy.c}
288   -DRIP_PROXY=${DRIP_PROXY:-$DRIP_HOME/drip_proxy}
  291 +DRIP_SRC_URL=${DRIP_SRC_URL:-https://raw.github.com/flatland/drip/master/src}
  292 +DRIP_SRC=${DRIP_SRC:-$DRIP_HOME/src}
289 293 JNA_VERSION=${JNA_VERSION:-3.4.1}
290 294 JNA_JAR_URL=${JNA_JAR_URL:-https://raw.github.com/twall/jna/$JNA_VERSION/dist/jna.jar}
291 295 MVN_REPO=${MVN_REPO:-~/.m2/repository}
  296 +JAVA_CMD=${JAVA_CMD:-java}
  297 +JAVA_CMD=$(which java)
292 298
293 299 bootstrap
294 300
295 301 parse_args "$@"
296 302
297 303 if [[ -z $drip_command ]]; then
298   - [[ -z $java_command ]] || exec java $java_command
  304 + [[ -z $java_command ]] || exec $JAVA_CMD $java_command
299 305 find_jvm
300 306 run_main
301 307 status=$?
47 src/drip_daemon.c
... ... @@ -0,0 +1,47 @@
  1 +#include <errno.h>
  2 +#include <unistd.h>
  3 +#include <stdlib.h>
  4 +#include <stdio.h>
  5 +
  6 +int check(char* prefix, int n) {
  7 + if (n < 0) {
  8 + perror(prefix);
  9 + exit(1);
  10 + } else {
  11 + return n;
  12 + }
  13 +}
  14 +
  15 +#define LEN 1024
  16 +
  17 +void spit_int(char* dir, char* base, int i) {
  18 + static char buf[LEN];
  19 + snprintf(buf, LEN, "%s/%s", dir, base);
  20 +
  21 + FILE* file = fopen(buf,"w");
  22 + fprintf(file,"%d\n", i);
  23 + fclose(file);
  24 +}
  25 +
  26 +int main(int argc, char **argv) {
  27 + char* jvm_dir = argv[argc - 1];
  28 +
  29 + // Start a child process and exit the parent.
  30 + if (check("fork parent", fork()) != 0) exit(0);
  31 +
  32 + /* close(0); */
  33 + /* close(1); */
  34 + umask(0);
  35 +
  36 + int pid = check("fork child", fork());
  37 + if (pid == 0) {
  38 + check("setsid", setsid());
  39 + check("execv", execv(argv[1], argv+1));
  40 + } else {
  41 + spit_int(jvm_dir, "jvm.pid", pid);
  42 +
  43 + int status;
  44 + waitpid(pid, &status, 0);
  45 + spit_int(jvm_dir, "status", status);
  46 + }
  47 +}
83 src/drip_proxy.c
@@ -3,16 +3,21 @@
3 3 #include <stdlib.h>
4 4 #include <stdio.h>
5 5 #include <unistd.h>
  6 +#include <setjmp.h>
  7 +#include <sys/ioctl.h>
6 8 #include <sys/select.h>
7 9 #include <sys/types.h>
8 10 #include <termios.h>
9 11
  12 +jmp_buf env;
  13 +char* err_prefix;
  14 +
10 15 // Based on code from https://github.com/nelhage/reptyr
11 16
12   -int check(char* name, int n) {
  17 +int check(char* prefix, int n) {
13 18 if (n < 0) {
14   - fprintf(stderr, "Error %d on %s\n", errno, name);
15   - exit(1);
  19 + err_prefix = prefix;
  20 + longjmp(env, errno);
16 21 } else {
17 22 return n;
18 23 }
@@ -68,7 +73,7 @@ void proxy(int in, int out, int err) {
68 73 }
69 74
70 75 int open_pty() {
71   - int fd = check("open", open("/dev/ptmx", O_RDWR));
  76 + int fd = check("posix_openpt", posix_openpt(O_RDWR | O_NOCTTY));
72 77
73 78 check("grantpt", grantpt(fd));
74 79 check("unlockpt", unlockpt(fd));
@@ -82,45 +87,59 @@ int open_fifo(char* path, int oflag) {
82 87 }
83 88
84 89 int main(int argc, char **argv) {
85   - struct termios prev;
  90 + if (argc != 4) {
  91 + fprintf(stderr, "Usage: drip_proxy in out err\n");
  92 + exit(1);
  93 + }
  94 +
86 95 char* tty_name = ttyname(0);
  96 + struct termios prev;
  97 + int exit_code = 0;
87 98
88 99 int in = 0;
89 100 int out = 0;
90 101 int err = 0;
91 102
92   - if (tty_name) {
93   - check("tcgetcattr", tcgetattr(0, &prev));
94   -
95   - int pty = open_pty();
96   - char* pty_name = ptsname(pty);
97   -
98   - in = pty;
99   - check("symlink in", symlink(pty_name, argv[1]));
100   -
101   - struct termios raw = prev;
102   - cfmakeraw(&raw);
103   - check("tcsetattr raw", tcsetattr(0, TCSANOW, &raw));
104   -
105   - if (strcmp(tty_name, ttyname(1)) == 0) {
106   - out = pty;
107   - check("symlink out", symlink(pty_name, argv[2]));
108   - }
109   - if (strcmp(tty_name, ttyname(1)) == 0) {
110   - err = pty;
111   - check("symlink err", symlink(pty_name, argv[3]));
  103 + if (setjmp(env) == 0) {
  104 + if (tty_name) {
  105 + check("tcgetcattr", tcgetattr(0, &prev));
  106 + struct termios raw = prev;
  107 + cfmakeraw(&raw);
  108 + check("tcsetattr raw", tcsetattr(0, TCSANOW, &raw));
  109 +
  110 + int pty = open_pty();
  111 + char* pty_name = ptsname(pty);
  112 +
  113 + in = pty;
  114 + check("symlink in", symlink(pty_name, argv[1]));
  115 +
  116 + char* out_name = ttyname(1);
  117 + if (out_name && strcmp(tty_name, out_name) == 0) {
  118 + out = pty;
  119 + check("symlink out", symlink(pty_name, argv[2]));
  120 + }
  121 +
  122 + char* err_name = ttyname(2);
  123 + if (err_name && strcmp(tty_name, err_name) == 0) {
  124 + err = pty;
  125 + check("symlink err", symlink(pty_name, argv[3]));
  126 + }
112 127 }
  128 +
  129 + if (!in) in = open_fifo(argv[1], O_WRONLY);
  130 + if (!out) out = open_fifo(argv[2], O_RDONLY);
  131 + if (!err) err = open_fifo(argv[3], O_RDONLY);
  132 +
  133 + proxy(in, out, err);
  134 + } else {
  135 + exit_code = 1;
113 136 }
114 137
115   - if (!in) in = open_fifo(argv[2], O_WRONLY);
116   - if (!out) out = open_fifo(argv[2], O_RDONLY);
117   - if (!err) err = open_fifo(argv[3], O_RDONLY);
118   -
119   - proxy(in, out, err);
120   -
121 138 if (tty_name) {
122 139 check("tcsetattr prev", tcsetattr(0, TCSANOW, &prev));
123 140 }
124 141
125   - return 0;
  142 + if (exit_code) perror(err_prefix);
  143 +
  144 + return exit_code;
126 145 }
24 src/org/flatland/drip/Main.java
@@ -13,6 +13,8 @@
13 13 import com.sun.jna.Library;
14 14 import com.sun.jna.Native;
15 15 import com.sun.jna.LastErrorException;
  16 +import sun.misc.Signal;
  17 +import sun.misc.SignalHandler;
16 18
17 19 public class Main {
18 20 private List<Switchable> lazyStreams;
@@ -50,7 +52,7 @@ private void killAfterTimeout() {
50 52 // someone is already connected; let the process finish
51 53 }
52 54 }
53   -
  55 +
54 56 private void startIdleKiller() {
55 57 Thread idleKiller = new Thread() {
56 58 public void run() {
@@ -62,6 +64,10 @@ public void run() {
62 64 idleKiller.start();
63 65 }
64 66
  67 + public static void main(String[] args) throws Exception {
  68 + new Main(args[0], args[1]).start();
  69 + }
  70 +
65 71 public void start() throws Exception {
66 72 reopenStreams();
67 73
@@ -93,10 +99,6 @@ public void start() throws Exception {
93 99 invoke(main, split(mainArgs, "\u0000"));
94 100 }
95 101
96   - public static void main(String[] args) throws Exception {
97   - new Main(args[0], args[1]).start();
98   - }
99   -
100 102 private Method mainMethod(String className)
101 103 throws ClassNotFoundException, NoSuchMethodException {
102 104 if (className != null) {
@@ -177,8 +179,6 @@ private void setControllingTerminal() throws Exception {
177 179 Integer fd = (Integer) field.get(fdesc);
178 180 field.setAccessible(false);
179 181
180   - LibC libc = (LibC) Native.loadLibrary("c", LibC.class);
181   - libc.setsid();
182 182 libc.ioctl(fd, TIOCSCTTY, 0);
183 183 }
184 184
@@ -215,15 +215,11 @@ private String readString(Scanner s) throws IOException {
215 215 return arg;
216 216 }
217 217
218   - private static final int TIOCSCTTY=536900705;
219   - private static final int TIOCNOTTY=536900721;
  218 + private static final int TIOCSCTTY = 536900705;
220 219
221 220 public interface LibC extends Library {
222 221 int ioctl(int fildes, long request, Object... args) throws LastErrorException;
223   - int setsid() throws LastErrorException;
224   - int getpgrp();
225   - int getpid();
226   - int getsid(int pid);
227   - void exit(int status);
228 222 }
  223 +
  224 + private static final LibC libc = (LibC) Native.loadLibrary("c", LibC.class);
229 225 }

0 comments on commit a8cd938

Please sign in to comment.
Something went wrong with that request. Please try again.