From 781ed9aaf0a6c313c7a6c721c193529df9674757 Mon Sep 17 00:00:00 2001 From: glenux Date: Wed, 1 Mar 2006 21:40:31 +0000 Subject: [PATCH] --- Makefile | 58 ++++++++ README | 35 +++++ detector-server.c | 348 ++++++++++++++++++++++++++++++++++++++++++++++ libdetect.c | 130 +++++++++++++++++ test.c | 11 ++ test_mod.c | 13 ++ tip-macosx.txt | 24 ++++ worms.c | 344 +++++++++++++++++++++++++++++++++++++++++++++ worms_mod.c | 347 +++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 1310 insertions(+) create mode 100644 Makefile create mode 100644 README create mode 100644 detector-server.c create mode 100644 libdetect.c create mode 100644 test.c create mode 100644 test_mod.c create mode 100644 tip-macosx.txt create mode 100644 worms.c create mode 100644 worms_mod.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..7c15949 --- /dev/null +++ b/Makefile @@ -0,0 +1,58 @@ +all: + @echo "Usage: make " + @echo "" + @echo "Commandes disponibles:" + @echo "- worm_inc : version modifiée des programmes, avec insertion de detect_init()" + @echo " et bibliothèque de détection de pannes liée statiquement" + @echo "- worm_shared : version modifiée des programmes, avec insertion de detect_init()" + @echo " et bibliothèque de détection de pannes liée dynamiquement" + @echo "- worm_preload: version non modifiée des programmes, avec préchargement de la " + @echo " bibliothèque de détection de pannes, et execution de celle-ci." + +worm_inc: clean server + gcc -ggdb -o worms_mod libdetect.c worms_mod.c -lcurses -lrt -lpthread -Wall + gcc -ggdb -o test_mod libdetect.c test_mod.c -lrt -lpthread -Wall + @echo -e "\n* Pour executer, taper: " + @echo -e "*\n* ./worms_mod" + @echo -e "*\n* ou " + @echo -e "*\n* ./test_mod\n*" + +worm_shared: clean server + gcc -fPIC -Wall -ggdb -c libdetect.c + gcc -g -shared -Wl,-soname,libdetect.so.0 \ + -o libdetect.so.0.0 libdetect.o -lc + /sbin/ldconfig -n . + ln -sf libdetect.so.0 libdetect.so + gcc -Wall -ggdb -o test_shr test_mod.c -L. -lrt -lpthread -ldetect + gcc -Wall -ggdb -o worms_shr worms_mod.c -L. -lcurses -lrt -lpthread -ldetect + @echo -e "\n* Pour executer, taper: " + @echo -e "*\n* LD_LIBRARY_PATH="." ./worms_shr" + @echo -e "*\n* ou " + @echo -e "*\n* LD_LIBRARY_PATH="." ./test_shr\n*" + +# run with: +# LD_LIBRARY_PATH="." ./command + + +worm_preload: clean server + gcc -fPIC -Wall -ggdb -c libdetect.c -D_GYR_PRELOAD + gcc -g -shared -Wl,-soname,libdetect.so.0 \ + -o libdetect.so.0.0 libdetect.o -lc + /sbin/ldconfig -n . + ln -sf libdetect.so.0 libdetect.so + gcc -ggdb -o worms worms.c -lcurses -lrt -lpthread -Wall + gcc -ggdb -o test test.c -lrt -lpthread -Wall + @echo -e "\n* Pour executer, taper: " + @echo -e "*\n* LD_LIBRARY_PATH="." LD_PRELOAD=libdetect.so ./worms" + @echo -e "*\n* ou " + @echo -e "*\n* LD_LIBRARY_PATH="." LD_PRELOAD=libdetect.so ./test\n*" + +server: + gcc -ggdb -o detector-server detector-server.c -Wall + +clean: + rm -f *.so* + rm -f *.o + rm -f detector-server + rm -f test test_mod test_shr + rm -f worms worms_mod worms_shr diff --git a/README b/README new file mode 100644 index 0000000..a4cc2de --- /dev/null +++ b/README @@ -0,0 +1,35 @@ + +Prérequis: L'utilisation de ce projet nécessite un système GNU/Linux, et la +présence du compilateur GNU GCC + + + + make + +* Détecteur de pannes, invoqué depuis main + + Taper: + + make worm_inc + + et suivre les instructions. + + +* Détecteur de pannes, invoqué depuis main et compilé + dans une bibliothèque chargée dynamiquement + + Taper: + + make worm_shared + + et suivre les instructions. + +* Détecteur de pannes, dans une bibliothèque chargée + dynamiquement, mais sans toucher au code source du programme original. + + Taper: + + make worm_preload + + et suivre les instructions. + diff --git a/detector-server.c b/detector-server.c new file mode 100644 index 0000000..4a8701e --- /dev/null +++ b/detector-server.c @@ -0,0 +1,348 @@ +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define LINK_CELL_NAME_SIZE 100 + +#define KEEP_SOCK_MAX(x, y) if (x < ((y) +1)){ x = (y) + 1; } + +#define FOREACH_SOCKET_IN_SOCKBASKET(i, sockbasket, link) for (i = 0; \ + ((i < sockbasket->size) \ + && (link_basket_get(sockbasket, i, &link)) \ + ); \ + i++) \ + if (link != NULL) + +#define SELECT_TIMEOUT 100000; +#define REQUEST_INTERVAL 5 +#define REQUEST_TIMEOUT 30 + +#define MIN(x, y) (((x) < (y))?(x):(y)) + +#define bool short +#define true 1 +#define false 0 + +typedef struct { + int sock_desc; + bool is_dead; + bool is_alive; + bool is_registered; + time_t request_stamp; + time_t answer_stamp; + char * name; +} link_cell_t; + +typedef struct { + link_cell_t ** data; + int size; + int next; +} link_basket_t; + +void show_progress(){ + static int prog = 0; + prog = prog % 100; + printf("["); + if (prog < 25){ + printf("|"); + } else if (prog < 50) { + printf("/"); + } else if (prog < 75) { + printf("-"); + } else { + printf("\\"); + } + printf("] "); + prog += 25; +} +bool link_basket_get (link_basket_t *sb, int index, link_cell_t ** res){ + bool result; + if (index < sb->size){ + *res = sb->data[ index ]; + /* + if (*res != NULL){ + printf ("Get at %d == %d\n", index, (*res)->sock_desc); + } */ + result = 1; + } else { + *res = NULL; + result = 0; + } + return result; +} + +void link_basket_delete (link_basket_t * sb){ + free (sb->data); + free (sb); +} + +void link_basket_remove (link_basket_t * sb, int index){ + link_cell_t * result = sb->data[ index ]; + if (sb->data[ index ]){ + free(result->name); + free (result); + } + sb->data[ index ] = NULL; + if (index < sb->next){ + sb->next = index; + } + return; +} + +void link_basket_add (link_basket_t * sb, int sockfd){ + int i; + + assert (sb->next != -1); // basket overflow ! + + link_cell_t * cell = (link_cell_t *) malloc (sizeof (link_cell_t)); + + cell->sock_desc = sockfd; + cell->is_dead = false; + cell->is_alive = true; + cell->is_registered = false; + cell->request_stamp = time(NULL); + cell->answer_stamp = time(NULL); + cell->name = (char *) malloc (sizeof (char) * LINK_CELL_NAME_SIZE); + memset(cell->name, 0, LINK_CELL_NAME_SIZE); + + sb->data[ sb->next ] = cell; + + for (i = sb->next; i < sb->size; i++){ + if (sb->data[ i ] == NULL){ + sb->next = i; + } + } + return; +} + +link_basket_t * link_basket_create (int size){ + link_basket_t * result = + (link_basket_t *) malloc (sizeof (link_basket_t)); + result->size = size; + result->data = (link_cell_t **) malloc (sizeof (link_cell_t *) * size); + result->next = 0; + + int i; + for (i = 0; i < result->size; i++){ + result->data[i] = NULL; + } + return result; +} + +int main (){ + link_basket_t * basket = link_basket_create(10); + + int main_sock ; + int port; + char * hostname; + char * portstr; + struct hostent * server; + struct sockaddr_in * myaddr; + + main_sock = socket (AF_INET, SOCK_STREAM, 0); + if (main_sock < 0){ + perror ("Creation de la socket impossible"); + fprintf (stderr,"BOOM at %s:%d\n",__FILE__,__LINE__); + exit (-1); + } + + hostname = getenv ("DETECTOR_HOSTNAME"); + portstr = getenv ("DETECTOR_PORT"); + if ((NULL == hostname) || (NULL == portstr)){ + printf("Environment variables DETECTOR_PORT and DETECTOR_HOSTNAME should have been defined.\n"); + exit(-1); + } + sscanf (portstr, "%d", &port); + + + printf ("Lookup for %s...\n", hostname); + server = gethostbyname(hostname); + if (server == NULL){ + fprintf (stderr, "Error, no such host\n"); + exit (-1); + } + printf ("Host found\n"); + + + myaddr = + (struct sockaddr_in *) malloc (sizeof(struct sockaddr_in)); + bzero (myaddr, sizeof(struct sockaddr_in)); + myaddr->sin_family = AF_INET; + myaddr->sin_port = htons(port); + + memcpy (&(myaddr->sin_addr.s_addr), server->h_addr, sizeof(u_long)); + //myaddr->sin_addr.s_addr = INADDR_ANY; + + // on bind sur le port voulu... + if (bind(main_sock, (struct sockaddr *)myaddr, sizeof(struct sockaddr)) < 0){ + perror("Unable to bind"); + fprintf(stderr,"Cannot bind on port %d of %s\n",port, inet_ntoa(myaddr->sin_addr)); + exit(-1); + } else { + printf("Bind on port %d of %s\n",port, inet_ntoa(myaddr->sin_addr)); + } + + // on fait un listen + if (listen(main_sock, 10) < 0){ + perror("Unable to listen"); + exit(-1); + } else { + printf("Ready to accept connexions.\n"); + } + + fd_set sock_set; + struct timeval tv; + int sock_set_size = 0; + + FD_ZERO(&sock_set); + FD_SET(main_sock, &sock_set); + sock_set_size++; + + + while(1){ + printf("\r"); + show_progress(); + + tv.tv_sec = 0; + tv.tv_usec = SELECT_TIMEOUT; + // + // si on recoit qqchose sur la socket principale, on fait un accept + // et on ajoute la nouvelle socket au set + link_cell_t * link; + int i; + + fd_set read_set;//= sock_set; + FD_ZERO(&read_set); + FD_SET(main_sock, &read_set); + KEEP_SOCK_MAX(sock_set_size, main_sock); + + + // on ajoute tous les socket ouverts au read_set + FOREACH_SOCKET_IN_SOCKBASKET (i, basket, link) { + time_t curtime = time(NULL); + bool must_add = false; + if (link->is_registered){ + if (link->is_alive){ + // si le programme est en vie + if (difftime(curtime, link->answer_stamp) > REQUEST_INTERVAL){ + // si le temps nécessaire est écoulé depuis la derniere réponse + printf ("\nRequesting liveness for '%s'\n", link->name); + + send(link->sock_desc,"status?", 7, 0); + link->request_stamp = curtime; + link->is_alive = false; + must_add = true; + } else { + // sinon on attend le temps nécessaire avant de douter... + // printf ("On attend que le temps s'écoule pour '%s'\n", link->name); + } + } else { + // sinon + if (difftime(curtime, link->request_stamp) > REQUEST_TIMEOUT){ + // ou on le tue... + // FIXME: retirer de la corbeille a liens... + printf ("\nTimeout: closing connection of '%s'\n", link->name); + close(link->sock_desc); + link_basket_remove(basket, i); + } else { + // on est toujours dans les temps de réponse... + //printf ("\nWaiting for '%s'\n", link->name); + must_add = true; + } + } + + } else { + must_add = true; + } + + if (must_add){ + //printf ("Adding '%s' (%d) to the set\n", link->name, link->sock_desc); + FD_SET (link->sock_desc, &read_set); + KEEP_SOCK_MAX (sock_set_size, link->sock_desc); + } + } + + printf("Select..."); fflush(stdout); + select(sock_set_size, &read_set, NULL, NULL, &tv); + printf("done"); fflush(stdout); + + FOREACH_SOCKET_IN_SOCKBASKET(i, basket, link) { + time_t curtime = time(NULL); + + if (FD_ISSET(link->sock_desc, &read_set)){ + // on lit les données recues, et sinon on ferme la socket. + // on vérifie qu'elle sont égales à ... + int buffer_len = 1024; + char * buffer = (char *) malloc (sizeof(char) * buffer_len); + int recv_len; + recv_len = recv(link->sock_desc, buffer, buffer_len, 0); + + if (recv_len == 0){ + printf("\nClient '%s' has disconnected !\n", link->name); + link_basket_remove(basket, i); + } else { + if ((recv_len >= 9) && (!strncmp("register:", buffer, 9))) { + buffer[MIN(recv_len, buffer_len - 1)] = '\0'; + + int i=0; + while(i < buffer_len -1){ + if ((buffer[i] == 0xD) || (buffer[i] == 0xA)) { buffer[i] = '\0'; } + i++; + } + strncpy(link->name, buffer + 9, MIN(recv_len - 9, LINK_CELL_NAME_SIZE)); + printf("\nRegistering client : %s\n", link->name); + link->is_registered = true; + link->answer_stamp = curtime; + + } else if ((recv_len >= 6) && (!strncmp("alive!", buffer, 6))) { + //printf("Process on fd %d is alive !\n", link->sock_desc); + link->is_alive = true; + link->answer_stamp = curtime; + + } else { + buffer[99] = '\0'; + printf("\nUnknow message %s", buffer); + } + } + + } else { + // printf("Rien sur %d\n", link->sock_desc); + } + } + + if (FD_ISSET(main_sock, &read_set)){ + unsigned int sin_size = sizeof(struct sockaddr_in); + struct sockaddr_in their_addr; /* Adresse du connecté */ + int sockfd; + + sockfd = accept(main_sock, (struct sockaddr *)&their_addr, + &sin_size); + link_basket_add(basket, sockfd); + printf("\nGot new connection at %d\n", sockfd); + }; + + + // lors d'un accept, on ajoute au tableau des entrées + // possibles l'hote qui se connecte + + // regarder les entrées... + // faire un select dessus + // garde des timer pour chaque entrée + // lorsque le temps D est écoule pour un timer + // on envoie un paquet "WIEGEHTS" a la machine + // et on attend une réponse en moins de 60 sec; + + } + return EXIT_SUCCESS; +} diff --git a/libdetect.c b/libdetect.c new file mode 100644 index 0000000..36298aa --- /dev/null +++ b/libdetect.c @@ -0,0 +1,130 @@ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifdef _GYR_PRELOAD +void __attribute__ ((constructor)) detector_init(void); +#endif + +typedef struct { + char * hostname; + int port; +} detector_serv_t; + +void * detector_thread_fun(void * paramvoid){ + detector_serv_t * param = paramvoid; + + printf("Thread launched\n"); + // se connecter + int socket_desc = socket(AF_INET, SOCK_STREAM, 0); + if (socket_desc < 0){ + perror("Creation de la socket impossible"); + fprintf(stderr,"BOUM at %s:%d\n",__FILE__,__LINE__); + exit(-1); + } + + printf("Lookup for %s...\n", param->hostname); + struct hostent * server = gethostbyname(param->hostname); + if (server == NULL){ + fprintf(stderr, "Error, no such host\n"); + exit(-1); + } + + printf("Host found\n"); + + struct sockaddr_in * myaddr = + (struct sockaddr_in *) malloc (sizeof(struct sockaddr_in)); + bzero(myaddr, sizeof(struct sockaddr_in)); + myaddr->sin_family = AF_INET; + myaddr->sin_port = htons(param->port); + + memcpy (&(myaddr->sin_addr.s_addr), server->h_addr, sizeof(u_long)); + // myaddr->sin_addr.s_addr = server->h_addr[0]; + + /* + bcopy((char *)(server->h_addr), + (char *)(myaddr->sin_addr.s_addr), + server->h_length); + */ + + if (connect(socket_desc, + (struct sockaddr *)myaddr, + sizeof(struct sockaddr_in)) < 0){ + perror("Attachement de la socket impossible"); + fprintf(stderr,"No connect at %s:%d\n",__FILE__,__LINE__); + exit(-1); + } + printf("Thread connected\n"); + + char hostname[50]; + gethostname(hostname, 50); + char ident[100]; + sprintf(ident, "%d@%s", getpid(), hostname); + + char * message = (char *) malloc (sizeof(char) * 1024); + memset(message, 0, 1024); + sprintf(message, "register:%s\n", ident); + + write(socket_desc, message, strlen(message)); + + // indiquer au serveur qu'il faut qu'il vérifie ce prog + // identifant pid + while(1){ + // on attend "status?", on répond "alive!" + int recv_len; + memset(message, 0, 1024); + recv_len = recv (socket_desc, message, 1024, 0); + + if (!strncmp("status?", message, 7)){ + send (socket_desc, "alive!", 6, 0); + } + + } + // se déconnecter ? + +} + +void detector_init(){ + // créer un thread "a part" qui répond au serveur + // et retourner dans le programme principal + pthread_t thr_detector; + pthread_attr_t thr_att; + + pthread_attr_init(&thr_att); + + detector_serv_t * param = (detector_serv_t *) + malloc (sizeof(detector_serv_t)); + // FIXME: read environment variable + param->hostname = getenv("DETECTOR_HOSTNAME"); + if (param->hostname == NULL){ + fprintf(stderr,"Undefined envirnoment variable DETECTOR_HOSTNAME\n"); + } + + //FIXME: read env variable + char * portstr = getenv("DETECTOR_PORT"); + if (portstr == NULL){ + fprintf(stderr,"Undefined envirnoment variable DETECTOR_HOSTNAME\n"); + } + sscanf(portstr, "%d", &(param->port)); + printf("HOST (%s) PORT (%d)\n", param->hostname, param->port); + + if (pthread_create (&thr_detector, + &thr_att, + detector_thread_fun, + param)) + { + perror("Impossible de créer le thread\n"); + exit(-1); + } + +} diff --git a/test.c b/test.c new file mode 100644 index 0000000..4e40636 --- /dev/null +++ b/test.c @@ -0,0 +1,11 @@ +#include +#include +#include + + +int main(){ + while(1){ + sleep(1); + printf("Loooooping \n"); + } +} diff --git a/test_mod.c b/test_mod.c new file mode 100644 index 0000000..af619d9 --- /dev/null +++ b/test_mod.c @@ -0,0 +1,13 @@ +#include +#include +#include + +void detector_init(); + +int main(){ + detector_init(); + while(1){ + sleep(1); + printf("Loooooping \n"); + } +} diff --git a/tip-macosx.txt b/tip-macosx.txt new file mode 100644 index 0000000..1b129ed --- /dev/null +++ b/tip-macosx.txt @@ -0,0 +1,24 @@ + +EXO 3 (pour macosX) +------------------------------------------------------- +gcc -dynamiclib -std=gnu99 -current-version 1.0 + -compatibility_version 1.0 -fvisibility=hidden + -o (lib)Detect.A.dylib *.c + +#define EXPORT __attribute__((visibility("default")) + + +EXPORT: + void detect_init(){ } + +EXO 4 (pour macosX) +------------------------------------------------------- +__attribute__((constructor)) + static void initializer(void) +} + + +EXO 5 (pour macosX) +------------------------------------------------------- +DYLD_INSERT_LIBRARIES = ./libDetect.A.dylib + diff --git a/worms.c b/worms.c new file mode 100644 index 0000000..b269e33 --- /dev/null +++ b/worms.c @@ -0,0 +1,344 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)worms.c 8.1 (Berkeley) 5/31/93"; +#endif +static const char rcsid[] = +"$FreeBSD: /repoman/r/ncvs/src/games/worms/worms.c,v 1.11 2002/02/23 10:35:25 billf Exp $"; +#endif /* not lint */ + +/* + * + * @@@ @@@ @@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@ + * @@@ @@@ @@@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@@@@ + * @@@ @@@ @@@@ @@@@ @@@@ @@@@ @@@ @@@@ + * @@@ @@ @@@ @@@ @@@ @@@ @@@ @@@ @@@ + * @@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ @@@ + * @@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ + * @@@@@@@@@@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ + * @@@@ @@@@ @@@@@@@@@@@@ @@@ @@@ @@@ @@@ + * @@ @@ @@@@@@@@@@ @@@ @@@ @@@ @@@ + * + * Eric P. Scott + * Caltech High Energy Physics + * October, 1980 + * + */ +#include +#include +#include +#include +#include +#include +#include + +static const struct options { + int nopts; + int opts[3]; +} +normal[8] = { + { 3, { 7, 0, 1 } }, + { 3, { 0, 1, 2 } }, + { 3, { 1, 2, 3 } }, + { 3, { 2, 3, 4 } }, + { 3, { 3, 4, 5 } }, + { 3, { 4, 5, 6 } }, + { 3, { 5, 6, 7 } }, + { 3, { 6, 7, 0 } } +}, upper[8] = { + { 1, { 1, 0, 0 } }, + { 2, { 1, 2, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 2, { 4, 5, 0 } }, + { 1, { 5, 0, 0 } }, + { 2, { 1, 5, 0 } } +}, + left[8] = { + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 2, { 2, 3, 0 } }, + { 1, { 3, 0, 0 } }, + { 2, { 3, 7, 0 } }, + { 1, { 7, 0, 0 } }, + { 2, { 7, 0, 0 } } + }, + right[8] = { + { 1, { 7, 0, 0 } }, + { 2, { 3, 7, 0 } }, + { 1, { 3, 0, 0 } }, + { 2, { 3, 4, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 2, { 6, 7, 0 } } + }, + lower[8] = { + { 0, { 0, 0, 0 } }, + { 2, { 0, 1, 0 } }, + { 1, { 1, 0, 0 } }, + { 2, { 1, 5, 0 } }, + { 1, { 5, 0, 0 } }, + { 2, { 5, 6, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } } + }, + upleft[8] = { + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 1, { 3, 0, 0 } }, + { 2, { 1, 3, 0 } }, + { 1, { 1, 0, 0 } } + }, + upright[8] = { + { 2, { 3, 5, 0 } }, + { 1, { 3, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 1, { 5, 0, 0 } } + }, + lowleft[8] = { + { 3, { 7, 0, 1 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 1, { 1, 0, 0 } }, + { 2, { 1, 7, 0 } }, + { 1, { 7, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } } + }, + lowright[8] = { + { 0, { 0, 0, 0 } }, + { 1, { 7, 0, 0 } }, + { 2, { 5, 7, 0 } }, + { 1, { 5, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } } + }; + + +static const char flavor[] = { + 'O', '*', '#', '$', '%', '0', '@', '~' +}; +static const short xinc[] = { + 1, 1, 1, 0, -1, -1, -1, 0 +}, yinc[] = { + -1, 0, 1, 1, 1, 0, -1, -1 +}; +static struct worm { + int orientation, head; + short *xpos, *ypos; +} *worm; + +volatile sig_atomic_t sig_caught = 0; +void nomem(void); +void onsig(int); + +int main(int argc, char *argv[]) +{ + int x, y, h, n; + struct worm *w; + const struct options *op; + short *ip; + int CO, LI, last, bottom, ch, length, number, trail; + short **ref; + const char *field; + char *mp; + unsigned int delay = 0; + + // hb_init(); + mp = NULL; + length = 16; + number = 3; + trail = ' '; + field = NULL; + while ((ch = getopt(argc, argv, "d:fl:n:t")) != -1) + switch(ch) { + case 'd': + if ((delay = (unsigned int)strtoul(optarg, (char **)NULL, 10)) < 1 || delay > 1000) + errx(1, "invalid delay (1-1000)"); + delay *= 1000; /* ms -> us */ + break; + case 'f': + field = "WORM"; + break; + case 'l': + if ((length = atoi(optarg)) < 2 || length > 1024) { + errx(1, "invalid length (%d - %d).", + 2, 1024); + } + break; + case 'n': + if ((number = atoi(optarg)) < 1) { + errx(1, "invalid number of worms."); + } + break; + case 't': + trail = '.'; + break; + case '?': + default: + (void)fprintf(stderr, + "usage: worms [-ft] [-d delay] [-l length] [-n number]\n"); + exit(1); + } + + if (!(worm = malloc((size_t)number * + sizeof(struct worm))) || !(mp = malloc((size_t)1024))) + nomem(); + initscr(); + CO = COLS; + LI = LINES; + last = CO - 1; + bottom = LI - 1; + if (!(ip = malloc((size_t)(LI * CO * sizeof(short))))) + nomem(); + if (!(ref = malloc((size_t)(LI * sizeof(short *))))) + nomem(); + for (n = 0; n < LI; ++n) { + ref[n] = ip; + ip += CO; + } + for (ip = ref[0], n = LI * CO; --n >= 0;) + *ip++ = 0; + for (n = number, w = &worm[0]; --n >= 0; w++) { + w->orientation = w->head = 0; + if (!(ip = malloc((size_t)(length * sizeof(short))))) + nomem(); + w->xpos = ip; + for (x = length; --x >= 0;) + *ip++ = -1; + if (!(ip = malloc((size_t)(length * sizeof(short))))) + nomem(); + w->ypos = ip; + for (y = length; --y >= 0;) + *ip++ = -1; + } + + (void)signal(SIGHUP, onsig); + (void)signal(SIGINT, onsig); + (void)signal(SIGQUIT, onsig); + (void)signal(SIGSTOP, onsig); + (void)signal(SIGTSTP, onsig); + (void)signal(SIGTERM, onsig); + + if (field) { + const char *p = field; + + for (y = LI; --y >= 0;) { + for (x = CO; --x >= 0;) { + addch(*p++); + if (!*p) + p = field; + } + refresh(); + } + } + for (;;) { + refresh(); + if (sig_caught) { + endwin(); + exit(0); + } + for (n = 0, w = &worm[0]; n < number; n++, w++) { + if ((x = w->xpos[h = w->head]) < 0) { + mvaddch(y = w->ypos[h] = bottom, + x = w->xpos[h] = 0, + flavor[n % sizeof(flavor)]); + ref[y][x]++; + } + else + y = w->ypos[h]; + if (++h == length) + h = 0; + if (w->xpos[w->head = h] >= 0) { + int x1, y1; + + x1 = w->xpos[h]; + y1 = w->ypos[h]; + if (--ref[y1][x1] == 0) { + mvaddch(y1, x1, trail); + } + } + op = &(!x ? (!y ? upleft : (y == bottom ? lowleft : left)) : (x == last ? (!y ? upright : (y == bottom ? lowright : right)) : (!y ? upper : (y == bottom ? lower : normal))))[w->orientation]; + switch (op->nopts) { + case 0: + refresh(); + abort(); + return(1); + case 1: + w->orientation = op->opts[0]; + break; + default: + w->orientation = + op->opts[(int)random() % op->nopts]; + } + mvaddch(y += yinc[w->orientation], + x += xinc[w->orientation], + flavor[n % sizeof(flavor)]); + ref[w->ypos[h] = y][w->xpos[h] = x]++; + } + if (usleep(delay)) + onsig(SIGTERM); + } +} + + void +onsig(int signo) +{ + sig_caught = 1; +} + + void +nomem(void) +{ + errx(1, "not enough memory."); +} diff --git a/worms_mod.c b/worms_mod.c new file mode 100644 index 0000000..d047ff5 --- /dev/null +++ b/worms_mod.c @@ -0,0 +1,347 @@ +/* + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char copyright[] = +"@(#) Copyright (c) 1980, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)worms.c 8.1 (Berkeley) 5/31/93"; +#endif +static const char rcsid[] = +"$FreeBSD: /repoman/r/ncvs/src/games/worms/worms.c,v 1.11 2002/02/23 10:35:25 billf Exp $"; +#endif /* not lint */ + +/* + * + * @@@ @@@ @@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@ + * @@@ @@@ @@@@@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@@@@ + * @@@ @@@ @@@@ @@@@ @@@@ @@@@ @@@ @@@@ + * @@@ @@ @@@ @@@ @@@ @@@ @@@ @@@ @@@ + * @@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ @@@ + * @@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ + * @@@@@@@@@@@@ @@@@ @@@@ @@@ @@@ @@@ @@@ + * @@@@ @@@@ @@@@@@@@@@@@ @@@ @@@ @@@ @@@ + * @@ @@ @@@@@@@@@@ @@@ @@@ @@@ @@@ + * + * Eric P. Scott + * Caltech High Energy Physics + * October, 1980 + * + */ +#include +#include +#include +#include +#include +#include +#include + +static const struct options { + int nopts; + int opts[3]; +} +normal[8] = { + { 3, { 7, 0, 1 } }, + { 3, { 0, 1, 2 } }, + { 3, { 1, 2, 3 } }, + { 3, { 2, 3, 4 } }, + { 3, { 3, 4, 5 } }, + { 3, { 4, 5, 6 } }, + { 3, { 5, 6, 7 } }, + { 3, { 6, 7, 0 } } +}, upper[8] = { + { 1, { 1, 0, 0 } }, + { 2, { 1, 2, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 2, { 4, 5, 0 } }, + { 1, { 5, 0, 0 } }, + { 2, { 1, 5, 0 } } +}, + left[8] = { + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 2, { 2, 3, 0 } }, + { 1, { 3, 0, 0 } }, + { 2, { 3, 7, 0 } }, + { 1, { 7, 0, 0 } }, + { 2, { 7, 0, 0 } } + }, + right[8] = { + { 1, { 7, 0, 0 } }, + { 2, { 3, 7, 0 } }, + { 1, { 3, 0, 0 } }, + { 2, { 3, 4, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 2, { 6, 7, 0 } } + }, + lower[8] = { + { 0, { 0, 0, 0 } }, + { 2, { 0, 1, 0 } }, + { 1, { 1, 0, 0 } }, + { 2, { 1, 5, 0 } }, + { 1, { 5, 0, 0 } }, + { 2, { 5, 6, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } } + }, + upleft[8] = { + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 1, { 3, 0, 0 } }, + { 2, { 1, 3, 0 } }, + { 1, { 1, 0, 0 } } + }, + upright[8] = { + { 2, { 3, 5, 0 } }, + { 1, { 3, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 1, { 5, 0, 0 } } + }, + lowleft[8] = { + { 3, { 7, 0, 1 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 1, { 1, 0, 0 } }, + { 2, { 1, 7, 0 } }, + { 1, { 7, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } } + }, + lowright[8] = { + { 0, { 0, 0, 0 } }, + { 1, { 7, 0, 0 } }, + { 2, { 5, 7, 0 } }, + { 1, { 5, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } }, + { 0, { 0, 0, 0 } } + }; + + +static const char flavor[] = { + 'O', '*', '#', '$', '%', '0', '@', '~' +}; +static const short xinc[] = { + 1, 1, 1, 0, -1, -1, -1, 0 +}, yinc[] = { + -1, 0, 1, 1, 1, 0, -1, -1 +}; +static struct worm { + int orientation, head; + short *xpos, *ypos; +} *worm; + +volatile sig_atomic_t sig_caught = 0; +void nomem(void); +void onsig(int); + +void detector_init(); + +int main(int argc, char *argv[]) +{ + detector_init(); + int x, y, h, n; + struct worm *w; + const struct options *op; + short *ip; + int CO, LI, last, bottom, ch, length, number, trail; + short **ref; + const char *field; + char *mp; + unsigned int delay = 0; + + // hb_init(); + mp = NULL; + length = 16; + number = 3; + trail = ' '; + field = NULL; + while ((ch = getopt(argc, argv, "d:fl:n:t")) != -1) + switch(ch) { + case 'd': + if ((delay = (unsigned int)strtoul(optarg, (char **)NULL, 10)) < 1 || delay > 1000) + errx(1, "invalid delay (1-1000)"); + delay *= 1000; /* ms -> us */ + break; + case 'f': + field = "WORM"; + break; + case 'l': + if ((length = atoi(optarg)) < 2 || length > 1024) { + errx(1, "invalid length (%d - %d).", + 2, 1024); + } + break; + case 'n': + if ((number = atoi(optarg)) < 1) { + errx(1, "invalid number of worms."); + } + break; + case 't': + trail = '.'; + break; + case '?': + default: + (void)fprintf(stderr, + "usage: worms [-ft] [-d delay] [-l length] [-n number]\n"); + exit(1); + } + + if (!(worm = malloc((size_t)number * + sizeof(struct worm))) || !(mp = malloc((size_t)1024))) + nomem(); + initscr(); + CO = COLS; + LI = LINES; + last = CO - 1; + bottom = LI - 1; + if (!(ip = malloc((size_t)(LI * CO * sizeof(short))))) + nomem(); + if (!(ref = malloc((size_t)(LI * sizeof(short *))))) + nomem(); + for (n = 0; n < LI; ++n) { + ref[n] = ip; + ip += CO; + } + for (ip = ref[0], n = LI * CO; --n >= 0;) + *ip++ = 0; + for (n = number, w = &worm[0]; --n >= 0; w++) { + w->orientation = w->head = 0; + if (!(ip = malloc((size_t)(length * sizeof(short))))) + nomem(); + w->xpos = ip; + for (x = length; --x >= 0;) + *ip++ = -1; + if (!(ip = malloc((size_t)(length * sizeof(short))))) + nomem(); + w->ypos = ip; + for (y = length; --y >= 0;) + *ip++ = -1; + } + + (void)signal(SIGHUP, onsig); + (void)signal(SIGINT, onsig); + (void)signal(SIGQUIT, onsig); + (void)signal(SIGSTOP, onsig); + (void)signal(SIGTSTP, onsig); + (void)signal(SIGTERM, onsig); + + if (field) { + const char *p = field; + + for (y = LI; --y >= 0;) { + for (x = CO; --x >= 0;) { + addch(*p++); + if (!*p) + p = field; + } + refresh(); + } + } + for (;;) { + refresh(); + if (sig_caught) { + endwin(); + exit(0); + } + for (n = 0, w = &worm[0]; n < number; n++, w++) { + if ((x = w->xpos[h = w->head]) < 0) { + mvaddch(y = w->ypos[h] = bottom, + x = w->xpos[h] = 0, + flavor[n % sizeof(flavor)]); + ref[y][x]++; + } + else + y = w->ypos[h]; + if (++h == length) + h = 0; + if (w->xpos[w->head = h] >= 0) { + int x1, y1; + + x1 = w->xpos[h]; + y1 = w->ypos[h]; + if (--ref[y1][x1] == 0) { + mvaddch(y1, x1, trail); + } + } + op = &(!x ? (!y ? upleft : (y == bottom ? lowleft : left)) : (x == last ? (!y ? upright : (y == bottom ? lowright : right)) : (!y ? upper : (y == bottom ? lower : normal))))[w->orientation]; + switch (op->nopts) { + case 0: + refresh(); + abort(); + return(1); + case 1: + w->orientation = op->opts[0]; + break; + default: + w->orientation = + op->opts[(int)random() % op->nopts]; + } + mvaddch(y += yinc[w->orientation], + x += xinc[w->orientation], + flavor[n % sizeof(flavor)]); + ref[w->ypos[h] = y][w->xpos[h] = x]++; + } + if (usleep(delay)) + onsig(SIGTERM); + } +} + + void +onsig(int signo) +{ + sig_caught = 1; +} + + void +nomem(void) +{ + errx(1, "not enough memory."); +}