chiark / gitweb /
working on trivsoundd branchpoint-trivsoundd
authorianmdlvl <ianmdlvl>
Thu, 22 May 2003 17:34:47 +0000 (17:34 +0000)
committerianmdlvl <ianmdlvl>
Thu, 22 May 2003 17:34:47 +0000 (17:34 +0000)
12 files changed:
backup/Makefile
cprogs/.cvsignore
cprogs/Makefile [new file with mode: 0644]
cprogs/dlist.h [new file with mode: 0644]
cprogs/readbuffer.c
cprogs/rwbuffer.c
cprogs/rwbuffer.h
cprogs/trivsoundd-start [new file with mode: 0755]
cprogs/trivsoundd.8 [new file with mode: 0644]
cprogs/trivsoundd.c
cprogs/wrbufcore.c
cprogs/writebuffer.c

index 938dd27..084c6fb 100644 (file)
 # with this program; if not, write to the Free Software Foundation, Inc.,
 # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
-CC=            gcc
-CFLAGS=                $(WARNINGS) $(OPTIMISE) $(DEBUG)
-CPPFLAGS=      -DRWBUFFER_SIZE_MB=$(RWBUFFER_SIZE_MB)
-
-WARNINGS=      -Wall -Wwrite-strings -Wmissing-prototypes \
-               -Wstrict-prototypes -Wpointer-arith
-OPTIMISE=      -O2
-DEBUG=         -g
-RWBUFFER_SIZE_MB=16
-
 SYSTEM_GROUP=  root
 
 prefix=/usr/local
@@ -52,28 +42,20 @@ INSTALL_SCRIPT=             $(INSTALL) -m 755 -o root -g $(SYSTEM_GROUP)
 INSTALL_PROGRAM=       $(INSTALL_SCRIPT) -s
 INSTALL_DIRECTORY=     $(INSTALL) -m 2755 -o root -g $(SYSTEM_GROUP) -d
 
-CTARGETS=      readbuffer writebuffer
 BINSCRIPTS=    checkallused loaded driver takedown whatsthis labeltape
 SHARESCRIPTS=  bringup full increm
 SHAREFILES=    backuplib.pl
 
 EXAMPLES=      relativity chiark
 
-all:           $(CTARGETS)
-
-readbuffer:                            readbuffer.o rwbuffer.o
-writebuffer:                           writebuffer.o rwbuffer.o
-readbuffer.o writebuffer.o rwbuffer.o: rwbuffer.h
+all:
 
 install:               all
                $(INSTALL_DIRECTORY) $(confdir) $(bindir) $(sharedir) $(vardir) $(man1dir)
-               $(INSTALL_PROGRAM) $(CTARGETS) $(bindir)
                set -e; for s in $(BINSCRIPTS); do \
                        $(INSTALL_SCRIPT) $$s $(bindir)/backup-$$s; done
                $(INSTALL_SHARE) $(SHAREFILES) $(sharedir)
                $(INSTALL_SCRIPT) $(SHARESCRIPTS) $(sharedir)
-               $(INSTALL) -m 644 readbuffer.1 ${man1dir}/readbuffer.1
-               $(INSTALL) -m 644 writebuffer.1 ${man1dir}/writebuffer.1
 
 install-docs:
                $(INSTALL_DIRECTORY) $(txtdocdir)
@@ -95,4 +77,3 @@ clean:
                rm -f *~ ./#*# *.o
 
 distclean realclean:   clean
-               rm -f $(CTARGETS)
index cf6c95c..ebfb6ab 100644 (file)
@@ -1,2 +1,3 @@
 readbuffer
 writebuffer
+trivsoundd
diff --git a/cprogs/Makefile b/cprogs/Makefile
new file mode 100644 (file)
index 0000000..2066d60
--- /dev/null
@@ -0,0 +1,77 @@
+# Makefile
+# simple make settings
+#
+# This file is part of chiark backup, a system for backing up GNU/Linux and
+# other UN*X-compatible machines, as used on chiark.greenend.org.uk.
+#
+# chiark backup is:
+#  Copyright (C) 1997-1998,2000-2001 Ian Jackson <ian@chiark.greenend.org.uk>
+#  Copyright (C) 1999 Peter Maydell <pmaydell@chiark.greenend.org.uk>
+#
+# This is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 2, or (at your option) any later version.
+#
+# This is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+CC=            gcc
+CFLAGS=                $(WARNINGS) $(OPTIMISE) $(DEBUG)
+CPPFLAGS=      -DRWBUFFER_SIZE_MB=$(RWBUFFER_SIZE_MB)
+
+WARNINGS=      -Wall -Wwrite-strings -Wmissing-prototypes \
+               -Wstrict-prototypes -Wpointer-arith
+OPTIMISE=      -O2
+DEBUG=         -g
+RWBUFFER_SIZE_MB=16
+
+SYSTEM_GROUP=  root
+
+prefix=/usr/local
+
+bindir=$(prefix)/bin
+sbindir=$(prefix)/sbin
+mandir=${prefix}/man
+man1dir=${mandir}/man1
+man8dir=${mandir}/man8
+
+INSTALL=               install -c
+INSTALL_PROGRAM=       $(INSTALL_SCRIPT) -s
+
+PROGRAMS=      readbuffer writebuffer
+DAEMONS=       trivsoundd
+MAN1PAGES=     readbuffer.1 writebuffer.1
+MAN8PAGES=     trivsoundd.8
+
+TARGETS=       $(PROGRAMS) $(DAEMONS)
+
+all:           $(TARGETS)
+
+readbuffer:                    readbuffer.o                    rwbuffer.o
+writebuffer:                   writebuffer.o   wrbufcore.o     rwbuffer.o 
+trivsoundd:                    trivsoundd.o    wrbufcore.o     rwbuffer.o 
+readbuffer.o writebuffer.o rwbuffer.o wrbufcoore.o:    rwbuffer.h
+
+install:               all
+               $(INSTALL_DIRECTORY) $(bindir) $(sbindir)
+               $(INSTALL_PROGRAM) $(PROGRAMS) $(bindir)
+               $(INSTALL_PROGRAM) $(DAEMONS) $(sbindir)
+
+install-docs:
+               $(INSTALL_DIRECTORY) $(man1dir) $(man8dir) $(txtdocdir)
+               $(INSTALL) -m 644 $(MAN1PAGES) ${man1dir}/.
+               $(INSTALL) -m 644 $(MAN8PAGES) ${man8dir}/.
+
+install-examples:
+
+clean:
+               rm -f *~ ./#*# *.o
+
+distclean realclean:   clean
+               rm -f $(TARGETS)
diff --git a/cprogs/dlist.h b/cprogs/dlist.h
new file mode 100644 (file)
index 0000000..44bf556
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * dlist.h
+ * - macros for handling doubly linked lists
+ */
+/*
+ *  This file is
+ *    Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk>
+ *
+ *  It is part of adns, which is
+ *    Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
+ *    Copyright (C) 1999 Tony Finch <dot@dotat.at>
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software Foundation,
+ *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
+ */
+
+#ifndef ADNS_DLIST_H_INCLUDED
+#define ADNS_DLIST_H_INCLUDED
+
+#define LIST_INIT(list) ((list).head= (list).tail= 0)
+#define LINK_INIT(link) ((link).next= (link).back= 0)
+
+#define LIST_UNLINK_PART(list,node,part) \
+  do { \
+    if ((node)->part back) (node)->part back->part next= (node)->part next; \
+      else                                  (list).head= (node)->part next; \
+    if ((node)->part next) (node)->part next->part back= (node)->part back; \
+      else                                  (list).tail= (node)->part back; \
+  } while(0)
+
+#define LIST_LINK_TAIL_PART(list,node,part) \
+  do { \
+    (node)->part next= 0; \
+    (node)->part back= (list).tail; \
+    if ((list).tail) (list).tail->part next= (node); else (list).head= (node); \
+    (list).tail= (node); \
+  } while(0)
+
+#define LIST_UNLINK(list,node) LIST_UNLINK_PART(list,node,)
+#define LIST_LINK_TAIL(list,node) LIST_LINK_TAIL_PART(list,node,)
+
+#endif
index e48e78c..2be121c 100644 (file)
  *
  */
 
-#include <sys/time.h>
-#include <sys/types.h>
-#include <assert.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-
 #include "rwbuffer.h"
 
 const char *progname= "readbuffer";
index d91a96e..cb88027 100644 (file)
  *
  */
 
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <assert.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/mman.h>
-
 #include "rwbuffer.h"
 
 #ifndef RWBUFFER_SIZE_MB_DEF
@@ -54,6 +43,8 @@ size_t buffersize;
 fd_set readfds;
 fd_set writefds;
 
+static int opt_mlock=0;
+
 int min(int a, int b) { return a<=b ? a : b; }
 
 static void usage(FILE *f) {
@@ -67,7 +58,7 @@ static void usageerr(const char *what) {
   exit(12);
 }
 
-static void nonblock(int fd, int yesno) {
+void nonblock(int fd, int yesno) {
   int r;
   r= fcntl(fd,F_GETFL,0); if (r == -1) { perror("fcntl getfl"); exit(8); }
   if (yesno) r |= O_NDELAY;
@@ -79,11 +70,21 @@ static void unnonblock(void) {
   nonblock(0,0); nonblock(1,0);
 }
 
+void startupcore(void) {
+  buf= xmalloc(buffersize);
+
+  if (opt_mlock) {
+    if (mlock(buf,buffersize)) { perror("mlock"); exit(2); }
+  }
+
+  used=0; wp=rp=buf; seeneof=0;
+  if (atexit(unnonblock)) { perror("atexit"); exit(16); }
+}
+
 void startup(const char *const *argv) {
   const char *arg;
   char *ep;
   unsigned long opt_buffersize=RWBUFFER_SIZE_MB_DEF;
-  int opt_mlock=0;
   
   assert(argv[0]);
   
@@ -100,14 +101,7 @@ void startup(const char *const *argv) {
   }
 
   buffersize= opt_buffersize*1024*1024;
-  buf= xmalloc(buffersize);
-
-  if (opt_mlock) {
-    if (mlock(buf,buffersize)) { perror("mlock"); exit(2); }
-  }
-
-  used=0; wp=rp=buf; seeneof=0;
-  if (atexit(unnonblock)) { perror("atexit"); exit(16); }
+  startupcore();
   nonblock(0,1); nonblock(1,1);
 }
 
index 3684c39..fe308c1 100644 (file)
 #ifndef RWBUFFER_H
 #define RWBUFFER_H
 
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+
+#include "dlist.h"
+
+
 int min(int a, int b);
 void callselect(void);
 void startup(const char *const *argv);
+void startupcore(void);
+void *xmalloc(size_t sz);
+void nonblock(int fd, int yesno);
 
 extern const char *progname; /* must be defined by main .c file */
 
@@ -42,4 +61,10 @@ extern size_t buffersize;
 extern fd_set readfds;
 extern fd_set writefds;
 
+
+void wrbufcore_startup(void);
+void wrbufcore_prepselect(int rdfd, int wrfd);
+void wrbufcore_afterselect(int rdfd, int wrfd);
+
+
 #endif /*RWBUFFER_H*/
diff --git a/cprogs/trivsoundd-start b/cprogs/trivsoundd-start
new file mode 100755 (executable)
index 0000000..9b50700
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/bash
+set -e
+pf=`tempfile`
+rm -f $pf
+mknod -m600 $pf p
+exec 3<>$pf
+exec >$pf 4<$pf
+rm -f $pf
+exec 3>&-
+(exec logger -p user.info -t trivsoundd <&4 >/dev/null 2>&1) &
+exec 4<&- 2>&1 </dev/null
+exec ${0%%-start}
diff --git a/cprogs/trivsoundd.8 b/cprogs/trivsoundd.8
new file mode 100644 (file)
index 0000000..796ba93
--- /dev/null
@@ -0,0 +1,25 @@
+.TH writebuffer 1 2001-10-21 chiark-backup
+.SH NAME
+writebuffer \- write output to devices which don't like constant stopping and starting
+.SH SYNOPSIS
+.B writebuffer
+.RB [ --mlock ]
+.RI [ size ]
+.SH DESCRIPTION
+.B writebuffer
+reads data on standard input and writes it to standard output.  It
+will buffer internally up to \fIsize\fR megabytes and will only write
+data when the buffer is at least 75% full or when there is no more
+input to fill the buffer.
+.PP
+It is intended for use in situations where many small writes are
+undesirable for performance reasons, e.g. tape drives.
+.SH OPTIONS
+.TP
+.B --mlock
+Calls
+.BR mlock (2)
+to lock the buffer into memory.
+.SH "SEE ALSO"
+.BR readbuffer (1),
+.BR mlock (2)
index e3d1acf..5eda4f7 100644 (file)
  *
  */
 
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <assert.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/mman.h>
-
 #include "rwbuffer.h"
 
-const char *progname= "triv-sound-d";
+const char *progname= "trivsoundd";
 
-static int master;
+static int maxstartdelay=60, maxbadaccept=10;
 
-int main(int argc, const char *const *argv) {
-  const char *bindname;
-  union {
-    struct sockaddr sa;
-    struct sockaddr_in sin;
-    struct sockaddr_un sun;
-  } su;
-  socklen_t sulen;
-
-  bindname= *++argv;
-  if (!bindname) usageerr("need bind argument");
-  startup(argv);
-
-  memset(&su,0,sizeof(su));
-
-  if (bindname[0]=='/' || bindname[0]='.') {
-    if (strlen(bindname) >= sizeof(su.sun.sun_path))
-      usageerr("AF_UNIX bind path too long");
-    sulen= sizeof(su.sun);
-    su.sun.sun_family= AF_UNIX;
-    strcpy(su.sun.sun_path, bindname);
-  } else if ((colon= strrchr(bindname,':'))) {
-    char *copy, *ep;
-    unsigned long portul;
-
-    sulen= sizeof(su.sin);
-    su.sin.sin_family= AF_INET;
-
-    copy= xmalloc(colon - bindname + 1);
-    memcpy(copy,bindname, colon - bindname + 1);
-    copy[colon - bindname]= 0;
-    portul= strtoul(colon+1,0,&ep);
-    if (!*ep) {
-      if (!portul || portul>=65536) usageerr("invalid port number");
-      su.sin.sin_port= htons(portul);
-    } else {
-      struct servent *se= getservbyname(colon+1, "tcp");
-      if (!se) { fprintf(stderr,"unknown service `%s'\n",colon+1); exit(4); }
-      su.sin.sin_port= htons(se->s_port);
+struct inqnode {
+  struct inqnode *next, *back;
+  time_t accepted;
+  int fd;
+};
+
+static struct { struct inqnode *head, *tail; } inq;
+static int sdev;
+static time_t now;
+
+static void opensounddevice(void) {
+  int r;
+  char cbuf[200];
+  
+  sdev= open("/dev/dsp", O_WRONLY);
+  if (sdev<0) { perror("open sound device"); exit(8); }
+
+  snprintf(cbuf, sizeof(cbuf), "sox -t raw -s -w -r 44100 -c 2"
+          " - </dev/null -t ossdsp - >&%d", sdev);
+  r= system(cbuf);  if (r) { fprintf(stderr,"sox gave %d\n",r); exit(5); }
+}
+
+static void selectcopy(void) {
+  int slave= inq.head ? inq.head->fd : -1;
+  wrbufcore_prepselect(slave, sdev);
+  FD_SET(0,&readfds);
+  callselect();
+  wrbufcore_afterselect(slave, sdev);
+}
+
+static void expireoldconns(void) {
+  struct inqnode *searchold, *nextsearchold;
+      
+  for (searchold= inq.head ? inq.head->next : 0;
+       searchold;
+       searchold= nextsearchold) {
+    nextsearchold= searchold;
+    if (searchold->accepted < now-maxstartdelay) {
+      printf("expired %p\n",searchold);
+      LIST_UNLINK(inq,searchold);
+      free(searchold);
     }
+  }
+}
 
-    if (!inet_aton(copy,&su.sin.sin_addr)) {
-      struct hostent *he= gethostbyname(copy);
-      if (!he) { herror(copy); exit(4); }
-      if (he->h_addrtype != AF_INET ||
-         he->h_length != sizeof(su.sin.sin_addr) ||
-         !he->h_addrs[0] ||
-         he->h_addrs[1]) {
-       fprintf(stderr,"hostname lookup `%s' did not yield"
-               " exactly one IPv4 address\n",copy);
+static void acceptnewconns(void) {
+  static int bad;
+  
+  int slave;
+  struct inqnode *new;
+
+  if (!FD_ISSET(0,&readfds)) return;
+
+  slave= accept(0,0,0);
+  if (slave < 0) {
+    if (!(errno == EINTR ||
+         errno == EAGAIN ||
+         errno == EWOULDBLOCK)) {
+      perror("accept");
+      bad++;
+      if (bad > maxbadaccept) {
+       fprintf(stderr,"accept failures repeating\n");
        exit(4);
       }
-      memcpy(su.sin.sin_addr, he->h_addrs[0], sizeof(su.sin.sin_addr));
     }
+    /* any transient error will just send us round again via select */
+    return;
   }
 
-  master= socket(su.sa.sa_family,SOCK_STREAM,0);
-  if (master<0) { perror("socket"); exit(8); }
+  bad= 0;
+  new= xmalloc(sizeof(struct inqnode));
+  new->accepted= now;
+  new->fd= slave;
+  LIST_LINK_TAIL(inq,new);
 
-  
-  
-    if (
+  printf("accepted %p\n",new);
+}
 
-      sdigit((unsigned char)bindname[0])) {
-    
+static void switchinput(void) {
+  struct inqnode *old;
+  if (!seeneof) return;
+  old= inq.head;
+  assert(old);
+  printf("finished %p\n",old);
+  close(old->fd);
+  LIST_UNLINK(inq,old);
+  free(old);
+  seeneof= 0;
+}  
 
-  if (argv[0]
-    
-  startup(argv);
-  writebuf_startup();
-  writebuf_mainloop();
-  exit(0);
+int main(int argc, const char *const *argv) {
+  assert(argv[0]);
+  if (argv[1]) { fputs("no arguments allowed\n",stderr); exit(12); }
+
+  buffersize= 44100*4* 5/*seconds*/;
+
+  opensounddevice();
+  nonblock(sdev,1);
+  nonblock(0,1);
+
+  startupcore();
+  wrbufcore_startup();
+  
+  printf("started\n");
+  for (;;) {
+    selectcopy();
+    if (time(&now)==(time_t)-1) { perror("time(2)"); exit(4); }
+    expireoldconns();
+    acceptnewconns();
+    switchinput();
+  }
 }
index 260f6d2..417cb01 100644 (file)
@@ -27,6 +27,8 @@
  *
  */
 
+#include "rwbuffer.h"
+
 static size_t waitfill;
 static int writing;
 
@@ -35,44 +37,46 @@ void wrbufcore_startup(void) {
   writing=0;
 }
 
-void wrbufcore_mainloop(void) {
-  int r;
+void wrbufcore_prepselect(int rdfd, int wrfd) {
+  FD_ZERO(&readfds);
+  if (rdfd>=0 && !seeneof && used+1<buffersize) FD_SET(rdfd,&readfds);
 
-  while (!seeneof || used) {
-    
-    FD_ZERO(&readfds); if (!seeneof && used+1<buffersize) FD_SET(0,&readfds);
-    FD_ZERO(&writefds); if (writing) FD_SET(1,&writefds);
+  FD_ZERO(&writefds);
+  if (writing) FD_SET(wrfd,&writefds);
+}
 
-    callselect();
+void wrbufcore_afterselect(int rdfd, int wrfd) {
+  int r;
     
-    if (FD_ISSET(1,&writefds) && !FD_ISSET(0,&readfds) && !used) {
-      writing= 0;
-      FD_CLR(1,&writefds);
-    }
+  if (FD_ISSET(wrfd,&writefds) &&
+      !(rdfd>=0 && FD_ISSET(rdfd,&readfds)) &&
+      !used) {
+    writing= 0;
+    FD_CLR(wrfd,&writefds);
+  }
 
-    if (FD_ISSET(0,&readfds)) {
-      r= read(0,rp,min(buffersize-1-used,buf+buffersize-rp));
-      if (!r) {
-        seeneof=1; writing=1;
-      } else if (r<0) {
-        if (!(errno == EAGAIN || errno == EINTR)) { perror("read"); exit(1); }
-      } else {
-        used+= r;
-        rp+= r;
-        if (rp == buf+buffersize) rp=buf;
-      }
-      if (used > waitfill) writing=1;
+  if (rdfd>=0 && FD_ISSET(rdfd,&readfds)) {
+    r= read(rdfd,rp,min(buffersize-1-used,buf+buffersize-rp));
+    if (!r) {
+      seeneof=1; writing=1;
+    } else if (r<0) {
+      if (!(errno == EAGAIN || errno == EINTR)) { perror("read"); exit(1); }
+    } else {
+      used+= r;
+      rp+= r;
+      if (rp == buf+buffersize) rp=buf;
     }
+    if (used > waitfill) writing=1;
+  }
 
-    if (FD_ISSET(1,&writefds) && used) {
-      r= write(1,wp,min(used,buf+buffersize-wp));
-      if (r<=0) {
-        if (!(errno == EAGAIN || errno == EINTR)) { perror("write"); exit(1); }
-      } else {
-        used-= r;
-        wp+= r;
-        if (wp == buf+buffersize) wp=buf;
-      }
+  if (FD_ISSET(wrfd,&writefds) && used) {
+    r= write(wrfd,wp,min(used,buf+buffersize-wp));
+    if (r<=0) {
+      if (!(errno == EAGAIN || errno == EINTR)) { perror("write"); exit(1); }
+    } else {
+      used-= r;
+      wp+= r;
+      if (wp == buf+buffersize) wp=buf;
     }
   }
 }
index 9b1a368..f37edd1 100644 (file)
  *
  */
 
-#include <sys/time.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-
 #include "rwbuffer.h"
 
 const char *progname= "writebuffer";
 
 int main(int argc, const char *const *argv) {
-  int r, writing;
-
   startup(argv);
-  writebuf_startup();
-  writebuf_mainloop();
+  wrbufcore_startup();
+  while (!seeneof || used) {
+    wrbufcore_prepselect(0,1);
+    callselect();
+    wrbufcore_afterselect(0,1);
+  }
   exit(0);
 }