- andreas@cvs.openbsd.org 2009/05/28 16:50:16
     [sshd.c packet.c serverloop.c monitor_wrap.c clientloop.c sshconnect.c
     monitor.c Added roaming.h roaming_common.c roaming_dummy.c]
     Keep track of number of bytes read and written. Needed for upcoming
     changes. Most code from Martin Forssen, maf at appgate dot com.
     ok markus@
     Also, applied appropriate changes to Makefile.in
diff --git a/ChangeLog b/ChangeLog
index 2f73a6b..8ed7db9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -83,10 +83,11 @@
      ok markus@
    - andreas@cvs.openbsd.org 2009/05/28 16:50:16
      [sshd.c packet.c serverloop.c monitor_wrap.c clientloop.c sshconnect.c
-      monitor.c]
+     monitor.c Added roaming.h roaming_common.c roaming_dummy.c]
      Keep track of number of bytes read and written. Needed for upcoming
      changes. Most code from Martin Forssen, maf at appgate dot com.
      ok markus@
+     Also, applied appropriate changes to Makefile.in
 
 20090616
  - (dtucker) [configure.ac defines.h] Bug #1607: handle the case where fsid_t
diff --git a/Makefile.in b/Makefile.in
index 312b8d2..75eb06d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,4 +1,4 @@
-# $Id: Makefile.in,v 1.298 2008/11/05 05:20:46 djm Exp $
+# $Id: Makefile.in,v 1.299 2009/06/21 08:53:53 dtucker Exp $
 
 # uncomment if you run a non bourne compatable shell. Ie. csh
 #SHELL = @SH@
@@ -74,7 +74,8 @@
 	entropy.o scard-opensc.o gss-genr.o umac.o jpake.o schnorr.o
 
 SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
-	sshconnect.o sshconnect1.o sshconnect2.o mux.o
+	sshconnect.o sshconnect1.o sshconnect2.o mux.o \
+	roaming_common.o
 
 SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
 	sshpty.o sshlogin.o servconf.o serverloop.o \
@@ -86,7 +87,8 @@
 	auth-krb5.o \
 	auth2-gss.o gss-serv.o gss-serv-krb5.o \
 	loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
-	audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o
+	audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o \
+	roaming_common.o
 
 MANPAGES	= moduli.5.out scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out sshd_config.5.out ssh_config.5.out
 MANPAGES_IN	= moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 sshd_config.5 ssh_config.5
@@ -151,11 +153,11 @@
 ssh-keygen$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keygen.o
 	$(LD) -o $@ ssh-keygen.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
 
-ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o
-	$(LD) -o $@ ssh-keysign.o readconf.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+ssh-keysign$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keysign.o roaming_dummy.o
+	$(LD) -o $@ ssh-keysign.o readconf.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
 
-ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o
-	$(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
+ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o roaming_dummy.o
+	$(LD) -o $@ ssh-keyscan.o roaming_dummy.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
 
 sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o
 	$(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
diff --git a/clientloop.c b/clientloop.c
index d5a0655..43f001b 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.c,v 1.211 2009/05/27 06:33:39 andreas Exp $ */
+/* $OpenBSD: clientloop.c,v 1.212 2009/05/28 16:50:16 andreas Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -109,6 +109,7 @@
 #include "misc.h"
 #include "match.h"
 #include "msg.h"
+#include "roaming.h"
 
 /* import options */
 extern Options options;
@@ -634,7 +635,7 @@
 static void
 client_process_net_input(fd_set *readset)
 {
-	int len;
+	int len, cont = 0;
 	char buf[8192];
 
 	/*
@@ -643,8 +644,8 @@
 	 */
 	if (FD_ISSET(connection_in, readset)) {
 		/* Read as much as possible. */
-		len = read(connection_in, buf, sizeof(buf));
-		if (len == 0) {
+		len = roaming_read(connection_in, buf, sizeof(buf), &cont);
+		if (len == 0 && cont == 0) {
 			/*
 			 * Received EOF.  The remote host has closed the
 			 * connection.
diff --git a/monitor.c b/monitor.c
index 61242e6..36a9e1d 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor.c,v 1.102 2009/05/25 06:48:01 andreas Exp $ */
+/* $OpenBSD: monitor.c,v 1.103 2009/05/28 16:50:16 andreas Exp $ */
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
  * Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -125,6 +125,8 @@
 	u_int ilen;
 	u_char *output;
 	u_int olen;
+	u_int64_t sent_bytes;
+	u_int64_t recv_bytes;
 } child_state;
 
 /* Functions on the monitor that answer unprivileged requests */
@@ -1679,6 +1681,10 @@
 		      child_state.olen);
 	memset(child_state.output, 0, child_state.olen);
 	xfree(child_state.output);
+
+	/* Roaming */
+	if (compat20)
+		roam_set_bytes(child_state.sent_bytes, child_state.recv_bytes);
 }
 
 static Kex *
@@ -1794,6 +1800,12 @@
 	child_state.input = buffer_get_string(&m, &child_state.ilen);
 	child_state.output = buffer_get_string(&m, &child_state.olen);
 
+	/* Roaming */
+	if (compat20) {
+		child_state.sent_bytes = buffer_get_int64(&m);
+		child_state.recv_bytes = buffer_get_int64(&m);
+	}
+
 	buffer_free(&m);
 }
 
diff --git a/monitor_wrap.c b/monitor_wrap.c
index d71d4a8..b696d78 100644
--- a/monitor_wrap.c
+++ b/monitor_wrap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: monitor_wrap.c,v 1.66 2009/05/25 06:48:01 andreas Exp $ */
+/* $OpenBSD: monitor_wrap.c,v 1.67 2009/05/28 16:50:16 andreas Exp $ */
 /*
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
  * Copyright 2002 Markus Friedl <markus@openbsd.org>
@@ -77,6 +77,7 @@
 #include "channels.h"
 #include "session.h"
 #include "servconf.h"
+#include "roaming.h"
 
 /* Imports */
 extern int compat20;
@@ -660,6 +661,12 @@
 	buffer_put_string(&m, buffer_ptr(input), buffer_len(input));
 	buffer_put_string(&m, buffer_ptr(output), buffer_len(output));
 
+	/* Roaming */
+	if (compat20) {
+		buffer_put_int64(&m, get_sent_bytes());
+		buffer_put_int64(&m, get_recv_bytes());
+	}
+
 	mm_request_send(monitor->m_recvfd, MONITOR_REQ_KEYEXPORT, &m);
 	debug3("%s: Finished sending state", __func__);
 
diff --git a/packet.c b/packet.c
index cecab82..f3f8389 100644
--- a/packet.c
+++ b/packet.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.162 2009/05/27 06:36:07 andreas Exp $ */
+/* $OpenBSD: packet.c,v 1.163 2009/05/28 16:50:16 andreas Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -77,6 +77,7 @@
 #include "canohost.h"
 #include "misc.h"
 #include "ssh.h"
+#include "roaming.h"
 
 #ifdef PACKET_DEBUG
 #define DBG(x) x
@@ -1012,7 +1013,7 @@
 int
 packet_read_seqnr(u_int32_t *seqnr_p)
 {
-	int type, len, ret, ms_remain;
+	int type, len, ret, ms_remain, cont;
 	fd_set *setp;
 	char buf[8192];
 	struct timeval timeout, start, *timeoutp = NULL;
@@ -1061,8 +1062,7 @@
 			if ((ret = select(active_state->connection_in + 1, setp,
 			    NULL, NULL, timeoutp)) >= 0)
 				break;
-			if (errno != EAGAIN && errno != EINTR &&
-			    errno != EWOULDBLOCK)
+			if (errno != EAGAIN && errno != EINTR)
 				break;
 			if (active_state->packet_timeout_ms == -1)
 				continue;
@@ -1078,7 +1078,11 @@
 			cleanup_exit(255);
 		}
 		/* Read data from the socket. */
-		len = read(active_state->connection_in, buf, sizeof(buf));
+		do {
+			cont = 0;
+			len = roaming_read(active_state->connection_in, buf,
+			    sizeof(buf), &cont);
+		} while (len == 0 && cont);
 		if (len == 0) {
 			logit("Connection closed by %.200s", get_remote_ipaddr());
 			cleanup_exit(255);
@@ -1624,23 +1628,23 @@
 packet_write_poll(void)
 {
 	int len = buffer_len(&active_state->output);
+	int cont;
 
 	if (len > 0) {
-		len = write(active_state->connection_out,
-		    buffer_ptr(&active_state->output), len);
+		cont = 0;
+		len = roaming_write(active_state->connection_out,
+		    buffer_ptr(&active_state->output), len, &cont);
 		if (len == -1) {
-			if (errno == EINTR || errno == EAGAIN ||
-			    errno == EWOULDBLOCK)
+			if (errno == EINTR || errno == EAGAIN)
 				return;
 			fatal("Write failed: %.100s", strerror(errno));
 		}
-		if (len == 0)
+		if (len == 0 && !cont)
 			fatal("Write connection closed");
 		buffer_consume(&active_state->output, len);
 	}
 }
 
-
 /*
  * Calls packet_write_poll repeatedly until all pending output data has been
  * written.
@@ -1673,8 +1677,7 @@
 			if ((ret = select(active_state->connection_out + 1,
 			    NULL, setp, NULL, timeoutp)) >= 0)
 				break;
-			if (errno != EAGAIN && errno != EINTR &&
-			    errno != EWOULDBLOCK)
+			if (errno != EAGAIN && errno != EINTR)
 				break;
 			if (active_state->packet_timeout_ms == -1)
 				continue;
@@ -1713,7 +1716,6 @@
 		return buffer_len(&active_state->output) < 128 * 1024;
 }
 
-
 static void
 packet_set_tos(int interactive)
 {
diff --git a/roaming.h b/roaming.h
new file mode 100644
index 0000000..8819345
--- /dev/null
+++ b/roaming.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2004-2009 AppGate Network Security AB
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef ROAMING_H
+#define ROAMING_H
+
+extern int resume_in_progress;
+
+void	add_recv_bytes(u_int64_t);
+ssize_t	roaming_write(int, const void *, size_t, int *);
+ssize_t	roaming_read(int, void *, size_t, int *);
+ssize_t	roaming_atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t);
+u_int64_t	get_recv_bytes(void);
+u_int64_t	get_sent_bytes(void);
+void	roam_set_bytes(u_int64_t, u_int64_t);
+int	resume_kex(void);
+
+#endif /* ROAMING */
diff --git a/roaming_common.c b/roaming_common.c
new file mode 100644
index 0000000..5a871b2
--- /dev/null
+++ b/roaming_common.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2004-2009 AppGate Network Security AB
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <errno.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include "atomicio.h"
+#include "log.h"
+#include "packet.h"
+#include "xmalloc.h"
+#include "cipher.h"
+#include "buffer.h"
+#include "roaming.h"
+
+static u_int64_t write_bytes = 0;
+static u_int64_t read_bytes = 0;
+
+int resume_in_progress = 0;
+
+u_int64_t
+get_recv_bytes(void)
+{
+	return read_bytes;
+}
+
+void
+add_recv_bytes(u_int64_t num)
+{
+	read_bytes += num;
+}
+
+u_int64_t
+get_sent_bytes(void)
+{
+	return write_bytes;
+}
+
+void
+roam_set_bytes(u_int64_t sent, u_int64_t recv)
+{
+	read_bytes = recv;
+	write_bytes = sent;
+}
+
+ssize_t
+roaming_write(int fd, const void *buf, size_t count, int *cont)
+{
+	ssize_t ret;
+
+	ret = write(fd, buf, count);
+	if (ret > 0 && !resume_in_progress) {
+		write_bytes += ret;
+	}
+	debug("Wrote %d bytes for a total of %lld", ret, write_bytes);
+	return ret;
+}
+
+ssize_t
+roaming_read(int fd, void *buf, size_t count, int *cont)
+{
+	ssize_t ret = read(fd, buf, count);
+	if (ret > 0) {
+		if (!resume_in_progress) {
+			read_bytes += ret;
+		}
+	}
+	return ret;
+}
+
+ssize_t
+roaming_atomicio(ssize_t(*f)(), int fd, void *buf, size_t count)
+{
+	ssize_t ret = atomicio(f, fd, buf, count);
+
+	if ((f == write || f == vwrite) && ret > 0 && !resume_in_progress) {
+		write_bytes += ret;
+	} else if (f == read && ret > 0 && !resume_in_progress) {
+		read_bytes += ret;
+	}
+	return ret;
+}
diff --git a/roaming_dummy.c b/roaming_dummy.c
new file mode 100644
index 0000000..cd1d202
--- /dev/null
+++ b/roaming_dummy.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2004-2009 AppGate Network Security AB
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * This file is included in the client programs which should not
+ * support roaming.
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+
+int resume_in_progress = 0;
+
+u_int64_t get_recv_bytes()
+{
+	return 0;
+}
+
+ssize_t
+roaming_write(int fd, const void *buf, size_t count, int *cont)
+{
+	return write(fd, buf, count);
+}
+
+ssize_t
+roaming_read(int fd, void *buf, size_t count, int *cont)
+{
+	if (cont)
+		*cont = 0;
+	return read(fd, buf, count);
+}
+
+void
+add_recv_bytes(u_int64_t num)
+{
+}
+
+int
+resume_kex()
+{
+	return 1;
+}
diff --git a/serverloop.c b/serverloop.c
index 53cb67d..d8cb54b 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: serverloop.c,v 1.158 2009/05/25 06:48:01 andreas Exp $ */
+/* $OpenBSD: serverloop.c,v 1.159 2009/05/28 16:50:16 andreas Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -78,6 +78,7 @@
 #include "auth-options.h"
 #include "serverloop.h"
 #include "misc.h"
+#include "roaming.h"
 
 extern ServerOptions options;
 
@@ -391,8 +392,11 @@
 
 	/* Read and buffer any input data from the client. */
 	if (FD_ISSET(connection_in, readset)) {
-		len = read(connection_in, buf, sizeof(buf));
+		int cont = 0;
+		len = roaming_read(connection_in, buf, sizeof(buf), &cont);
 		if (len == 0) {
+			if (cont)
+				return;
 			verbose("Connection closed by %.100s",
 			    get_remote_ipaddr());
 			connection_closed = 1;
diff --git a/sshconnect.c b/sshconnect.c
index dee3ba5..3e57e85 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect.c,v 1.213 2009/05/27 06:38:16 andreas Exp $ */
+/* $OpenBSD: sshconnect.c,v 1.214 2009/05/28 16:50:16 andreas Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -56,6 +56,7 @@
 #include "atomicio.h"
 #include "misc.h"
 #include "dns.h"
+#include "roaming.h"
 #include "version.h"
 
 char *client_version_string = NULL;
@@ -452,7 +453,7 @@
 				}
 			}
 
-			len = atomicio(read, connection_in, &buf[i], 1);
+			len = roaming_atomicio(read, connection_in, &buf[i], 1);
 
 			if (len != 1 && errno == EPIPE)
 				fatal("ssh_exchange_identification: "
@@ -537,7 +538,8 @@
 	    compat20 ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1,
 	    compat20 ? PROTOCOL_MINOR_2 : minor1,
 	    SSH_VERSION, compat20 ? "\r\n" : "\n");
-	if (atomicio(vwrite, connection_out, buf, strlen(buf)) != strlen(buf))
+	if (roaming_atomicio(vwrite, connection_out, buf, strlen(buf))
+	    != strlen(buf))
 		fatal("write: %.100s", strerror(errno));
 	client_version_string = xstrdup(buf);
 	chop(client_version_string);
diff --git a/sshd.c b/sshd.c
index 3b5cd3c..91831e2 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshd.c,v 1.366 2009/01/22 10:02:34 djm Exp $ */
+/* $OpenBSD: sshd.c,v 1.367 2009/05/28 16:50:16 andreas Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -117,6 +117,7 @@
 #include "ssh-gss.h"
 #endif
 #include "monitor_wrap.h"
+#include "roaming.h"
 #include "version.h"
 
 #ifdef LIBWRAP
@@ -419,7 +420,7 @@
 	server_version_string = xstrdup(buf);
 
 	/* Send our protocol version identification. */
-	if (atomicio(vwrite, sock_out, server_version_string,
+	if (roaming_atomicio(vwrite, sock_out, server_version_string,
 	    strlen(server_version_string))
 	    != strlen(server_version_string)) {
 		logit("Could not write ident string to %s", get_remote_ipaddr());
@@ -429,7 +430,7 @@
 	/* Read other sides version identification. */
 	memset(buf, 0, sizeof(buf));
 	for (i = 0; i < sizeof(buf) - 1; i++) {
-		if (atomicio(read, sock_in, &buf[i], 1) != 1) {
+		if (roaming_atomicio(read, sock_in, &buf[i], 1) != 1) {
 			logit("Did not receive identification string from %s",
 			    get_remote_ipaddr());
 			cleanup_exit(255);