summaryrefslogtreecommitdiff
path: root/pgm3
diff options
context:
space:
mode:
Diffstat (limited to 'pgm3')
-rw-r--r--pgm3/accessed.c122
-rw-r--r--pgm3/pgm3test.d/fileinfo.c30
-rw-r--r--pgm3/pgm3test.d/link.c30
-rw-r--r--pgm3/pgm3test.d/script24
-rw-r--r--pgm3/pgm3test.d/subdir/subfileinfo.c30
-rw-r--r--pgm3/pgm3test.d/subdir/subsubdir/file1bin0 -> 1023 bytes
-rw-r--r--pgm3/pgm3test.d/subdir/subsubdir/file2bin0 -> 1023 bytes
-rw-r--r--pgm3/pgm3test.d/subdir/subsubdir/file3bin0 -> 1023 bytes
-rw-r--r--pgm3/pgm3test.d/symlink.c30
-rw-r--r--pgm3/report.c232
-rw-r--r--pgm3/totalsize.c126
11 files changed, 624 insertions, 0 deletions
diff --git a/pgm3/accessed.c b/pgm3/accessed.c
new file mode 100644
index 0000000..b1007a9
--- /dev/null
+++ b/pgm3/accessed.c
@@ -0,0 +1,122 @@
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <time.h>
+#include <unistd.h>
+
+#define FALSE 0
+#define FILE_BUFF 4096
+#define TRUE 1
+
+struct NODE {
+ char filename[FILE_BUFF];
+ int inode;
+ long atime;
+ struct NODE *next;
+};
+
+int makeList(struct NODE **head) {
+ /*
+ * makeList builds a linked list of nodes representing the filenames
+ * given on stdin and their access time.
+ */
+ char filename[FILE_BUFF];
+ int inList = FALSE;
+ struct NODE *currentNode = NULL;
+ struct NODE *newNode = NULL;
+ struct stat statData;
+
+ while (scanf(" %s", filename) == 1) {
+
+ if (stat(filename, &statData) == 0 && S_ISREG(statData.st_mode)) {
+ inList = FALSE;
+
+ for (currentNode = *head; currentNode != NULL; currentNode = currentNode->next) {
+
+ if (currentNode->inode == statData.st_ino) {
+ inList = TRUE;
+ }
+
+ }
+
+ if (!inList) {
+ newNode = (struct NODE *) malloc(sizeof(struct NODE));
+ newNode->inode = statData.st_ino;
+ strcpy(newNode->filename, filename);
+ newNode->atime = (time(NULL) - statData.st_atime) / 86400;
+ newNode->next = *head;
+ *head = newNode;
+ }
+
+ }
+
+ }
+
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ /*
+ * accessed takes in filenames from stdin and one command line argument,
+ * "num". It then builds a linked list of the unique, regular files and
+ * prints out those files not accessed in "num" days (if num is positive)
+ * or prints out those files accesssed within "num" days (if num is
+ * negative).
+ */
+ int accessedNum = 0;
+ struct NODE *currentNode = NULL;
+ struct NODE *list = NULL;
+
+ // Go through args
+ if (argc != 2) {
+ fprintf(stderr, "accessed: usage: ./accessed [num days]\n");
+ exit(1);
+ }
+
+ accessedNum = strtol(argv[1], NULL, 10);
+
+ if (errno == EINVAL) {
+ fprintf(stderr, "accessed: error: num must be integer type.\n");
+ exit(1);
+ }
+ else if (errno == ERANGE) {
+ fprintf(stderr, "accessed: error: num must be of integer size.\n");
+ exit(1);
+ }
+ else if (accessedNum == 0) {
+ fprintf(stderr, "accessed: error: num must be nonzero integer.\n");
+ exit(1);
+ }
+
+ if (makeList(&list) != 0) {
+ fprintf(stderr, "accessed: error: could not build linked list.\n");
+ exit(1);
+ }
+
+ // print out filenames that match requested access time
+ for (currentNode = list; currentNode != NULL; currentNode = currentNode->next) {
+
+ if (accessedNum > 0 && currentNode->atime > accessedNum) { // not within num days
+ printf("%s\n", currentNode->filename);
+ }
+
+ if (accessedNum < 0 && currentNode->atime <= (accessedNum * -1)) { // within num days
+ printf("%s\n", currentNode->filename);
+ }
+
+ }
+
+ // free list
+ while (currentNode != NULL) {
+ currentNode = list;
+ list = list->next;
+ free(currentNode);
+ }
+
+ exit(0);
+}
diff --git a/pgm3/pgm3test.d/fileinfo.c b/pgm3/pgm3test.d/fileinfo.c
new file mode 100644
index 0000000..eed7902
--- /dev/null
+++ b/pgm3/pgm3test.d/fileinfo.c
@@ -0,0 +1,30 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/sysmacros.h>
+#include <sys/time.h>
+
+main(argc,argv)
+int argc; char *argv[];
+{
+
+ struct stat info;
+
+ if (argc != 2) {
+ fprintf(stderr, "fileinfo: usage fileinfo filename\n");
+ exit(1);
+ }
+
+ if (stat(argv[1], &info) != 0) {
+ fprintf(stderr,"fileinfo: cannot stat %s:", argv[1]);
+ perror(NULL);
+ }
+ printf("%s: ", argv[1]);
+ printf("(device,i_number)=(%d/%d,%ld)", major(info.st_dev), minor(info.st_dev), (long) info.st_ino);
+ printf(" last accessed %d seconds ago\n", time(NULL)-info.st_atime);
+ if (S_ISREG(info.st_mode))
+ printf("\tdesignated a regular file\n");
+ if (S_ISLNK(info.st_mode))
+ printf("\tdesignated a symlink\n");
+}
diff --git a/pgm3/pgm3test.d/link.c b/pgm3/pgm3test.d/link.c
new file mode 100644
index 0000000..eed7902
--- /dev/null
+++ b/pgm3/pgm3test.d/link.c
@@ -0,0 +1,30 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/sysmacros.h>
+#include <sys/time.h>
+
+main(argc,argv)
+int argc; char *argv[];
+{
+
+ struct stat info;
+
+ if (argc != 2) {
+ fprintf(stderr, "fileinfo: usage fileinfo filename\n");
+ exit(1);
+ }
+
+ if (stat(argv[1], &info) != 0) {
+ fprintf(stderr,"fileinfo: cannot stat %s:", argv[1]);
+ perror(NULL);
+ }
+ printf("%s: ", argv[1]);
+ printf("(device,i_number)=(%d/%d,%ld)", major(info.st_dev), minor(info.st_dev), (long) info.st_ino);
+ printf(" last accessed %d seconds ago\n", time(NULL)-info.st_atime);
+ if (S_ISREG(info.st_mode))
+ printf("\tdesignated a regular file\n");
+ if (S_ISLNK(info.st_mode))
+ printf("\tdesignated a symlink\n");
+}
diff --git a/pgm3/pgm3test.d/script b/pgm3/pgm3test.d/script
new file mode 100644
index 0000000..9bb8248
--- /dev/null
+++ b/pgm3/pgm3test.d/script
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+# after doing a
+# cp -a ~kearns/public/415/P3/pgm3test.d .
+# run ./script to set access times
+#
+# ./script should be run before every test to
+# reset access times to well-known values
+
+OLD='2005-01-01'
+NEW='yesterday'
+
+TOUCH=/usr/bin/touch
+
+#give a.out current access time
+$TOUCH --time=access ./a.out
+
+# give fileinfo.c access time of Jan 1, 2005
+$TOUCH --time=access --date=$OLD ./fileinfo.c
+
+# subdir/subsubdir files given staggered access times
+$TOUCH --time=access --date=$OLD ./subdir/subsubdir/file1
+$TOUCH --time=access --date=$NEW ./subdir/subsubdir/file2
+$TOUCH --time=access --date=$NEW ./subdir/subsubdir/file3
diff --git a/pgm3/pgm3test.d/subdir/subfileinfo.c b/pgm3/pgm3test.d/subdir/subfileinfo.c
new file mode 100644
index 0000000..eed7902
--- /dev/null
+++ b/pgm3/pgm3test.d/subdir/subfileinfo.c
@@ -0,0 +1,30 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/sysmacros.h>
+#include <sys/time.h>
+
+main(argc,argv)
+int argc; char *argv[];
+{
+
+ struct stat info;
+
+ if (argc != 2) {
+ fprintf(stderr, "fileinfo: usage fileinfo filename\n");
+ exit(1);
+ }
+
+ if (stat(argv[1], &info) != 0) {
+ fprintf(stderr,"fileinfo: cannot stat %s:", argv[1]);
+ perror(NULL);
+ }
+ printf("%s: ", argv[1]);
+ printf("(device,i_number)=(%d/%d,%ld)", major(info.st_dev), minor(info.st_dev), (long) info.st_ino);
+ printf(" last accessed %d seconds ago\n", time(NULL)-info.st_atime);
+ if (S_ISREG(info.st_mode))
+ printf("\tdesignated a regular file\n");
+ if (S_ISLNK(info.st_mode))
+ printf("\tdesignated a symlink\n");
+}
diff --git a/pgm3/pgm3test.d/subdir/subsubdir/file1 b/pgm3/pgm3test.d/subdir/subsubdir/file1
new file mode 100644
index 0000000..1bce2be
--- /dev/null
+++ b/pgm3/pgm3test.d/subdir/subsubdir/file1
Binary files differ
diff --git a/pgm3/pgm3test.d/subdir/subsubdir/file2 b/pgm3/pgm3test.d/subdir/subsubdir/file2
new file mode 100644
index 0000000..1bce2be
--- /dev/null
+++ b/pgm3/pgm3test.d/subdir/subsubdir/file2
Binary files differ
diff --git a/pgm3/pgm3test.d/subdir/subsubdir/file3 b/pgm3/pgm3test.d/subdir/subsubdir/file3
new file mode 100644
index 0000000..1bce2be
--- /dev/null
+++ b/pgm3/pgm3test.d/subdir/subsubdir/file3
Binary files differ
diff --git a/pgm3/pgm3test.d/symlink.c b/pgm3/pgm3test.d/symlink.c
new file mode 100644
index 0000000..eed7902
--- /dev/null
+++ b/pgm3/pgm3test.d/symlink.c
@@ -0,0 +1,30 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/sysmacros.h>
+#include <sys/time.h>
+
+main(argc,argv)
+int argc; char *argv[];
+{
+
+ struct stat info;
+
+ if (argc != 2) {
+ fprintf(stderr, "fileinfo: usage fileinfo filename\n");
+ exit(1);
+ }
+
+ if (stat(argv[1], &info) != 0) {
+ fprintf(stderr,"fileinfo: cannot stat %s:", argv[1]);
+ perror(NULL);
+ }
+ printf("%s: ", argv[1]);
+ printf("(device,i_number)=(%d/%d,%ld)", major(info.st_dev), minor(info.st_dev), (long) info.st_ino);
+ printf(" last accessed %d seconds ago\n", time(NULL)-info.st_atime);
+ if (S_ISREG(info.st_mode))
+ printf("\tdesignated a regular file\n");
+ if (S_ISLNK(info.st_mode))
+ printf("\tdesignated a symlink\n");
+}
diff --git a/pgm3/report.c b/pgm3/report.c
new file mode 100644
index 0000000..623de6f
--- /dev/null
+++ b/pgm3/report.c
@@ -0,0 +1,232 @@
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <unistd.h>
+
+#define FALSE 0
+#define FILE_BUFF 4096
+#define TRUE 1
+
+int terminateFlag = 1; // Used with signal handler function.
+
+void sigHandler(int signum) {
+ /*
+ * sigHandler() waits for a SIGUSR1 signal. Upon receiving this signal it
+ * decrements terminateFlag, lowering it to zero.
+ */
+
+ if (signum == SIGUSR1) {
+ terminateFlag--;
+ }
+
+}
+
+int main(int argc, char *argv[]) {
+ /*
+ * report takes in one required argument ("num") and two optional arguments.
+ * -k specifies that output should be printed in kilobytes, not bytes
+ * -d specifies a delay that should be waited before reading each filename
+ * into the totalsize child process.
+ *
+ * Report takes in filenames on its stdin and then calls four child
+ * processes. Two execute accessed, one with num as an arg and one with
+ * -num as an arg. report writes its stdin to the stdin of the accessed
+ * children. The accessed children then print their output to the stdin
+ * of two more children that execute totalsize. These totalsize
+ * children run through the filenames they're given and print out the
+ * size of those files back into report. This is all done via pipes.
+ *
+ * report then prints out the results it receives from its children.
+ */
+ char byteSum[10];
+ char delayStr[10];
+ char *envar = NULL;
+ char filename[FILE_BUFF];
+ char numNeg[11];
+ char thisPID[10];
+ int accessedNum;
+ int delay = 0;
+ int i = 2;
+
+ // Go through args.
+ if (argc < 2) {
+ fprintf(stderr, "usage: ./report [num days] {-k} {-d} [delay]\n");
+ exit(1);
+ }
+
+ // Fetch accessedNum parameter
+ accessedNum = strtol(argv[1], NULL, 10);
+ errno = 0;
+
+ if (accessedNum <= 0) {
+ fprintf(stderr, "report: num must be positive, nonzero integer.\n");
+ exit(1);
+ }
+ else if (errno == ERANGE) {
+ fprintf(stderr, "report: num must be of integer size.\n");
+ exit(1);
+ }
+ else if (errno == EINVAL) {
+ fprintf(stderr, "report: num must be integer type.\n");
+ exit(1);
+ }
+
+ // Set the second accessed num as negative.
+ sprintf(numNeg, "%d", accessedNum * -1);
+
+ while (argv[i]) {
+
+ if (strcmp(argv[i], "-k") == 0) {
+ setenv("UNITS", "k", 1);
+ }
+ else if (strcmp(argv[i], "-d") == 0) {
+ delay = strtol(argv[i+1], NULL, 10);
+ errno = 0;
+
+ if (delay <= 0) {
+ fprintf(stderr, "report: delay must be positive, nonzero integer.\n");
+ exit(1);
+ }
+ else if (errno == ERANGE) {
+ fprintf(stderr, "report: delay must be of integer size.\n");
+ exit(1);
+ }
+ else if (errno == EINVAL) {
+ fprintf(stderr, "report: delay must be integer type.\n");
+ exit(1);
+ }
+
+ sprintf(delayStr, "%d", delay);
+ setenv("TSTALL", delayStr, 1);
+ i++;
+ }
+ else {
+ fprintf(stderr, "usage: ./report [num days] {-k} {-d} [delay]\n");
+ exit(1);
+ }
+
+ i++;
+ }
+
+ // Set up signal handling.
+ sprintf(thisPID, "%d", getpid());
+ setenv("TMOM", thisPID, 1);
+ signal(SIGUSR1, sigHandler);
+
+ // Set up pipes.
+ int pipeRtoA1[2]; pipe(pipeRtoA1);
+ int pipeRtoA2[2]; pipe(pipeRtoA2);
+ int pipeA1toT1[2]; pipe(pipeA1toT1);
+ int pipeA2toT2[2]; pipe(pipeA2toT2);
+ int pipeT1toR[2]; pipe(pipeT1toR);
+ int pipeT2toR[2]; pipe(pipeT2toR);
+
+ if (fork() == 0) { // accessed 1
+ // Close unneeded pipes =====================
+ close(pipeRtoA1[1]);
+ close(pipeRtoA2[0]); close(pipeRtoA2[1]);
+ close(pipeA1toT1[0]);
+ close(pipeA2toT2[0]); close(pipeA2toT2[1]);
+ close(pipeT1toR[0]); close(pipeT1toR[1]);
+ close(pipeT2toR[0]); close(pipeT2toR[1]);
+ // ==========================================
+
+ // Dup read end to stdin and write end to stdout
+ close(0); dup(pipeRtoA1[0]); close(pipeRtoA1[0]);
+ close(1); dup(pipeA1toT1[1]); close(pipeA1toT1[1]);
+ execl("accessed", "accessed", argv[1], NULL);
+ }
+ else if (fork() == 0) { // accessed 2
+ // Close unneeded pipes =====================
+ close(pipeRtoA1[0]); close(pipeRtoA1[1]);
+ close(pipeRtoA2[1]);
+ close(pipeA1toT1[0]); close(pipeA1toT1[1]);
+ close(pipeA2toT2[0]);
+ close(pipeT1toR[0]); close(pipeT1toR[1]);
+ close(pipeT2toR[0]); close(pipeT2toR[1]);
+ // ==========================================
+
+ close(0); dup(pipeRtoA2[0]); close(pipeRtoA2[0]);
+ close(1); dup(pipeA2toT2[1]); close(pipeA2toT2[1]);
+ execl("accessed", "accessed", numNeg, NULL);
+ }
+ else if (fork() == 0) { // totalsize 1
+ // Close unneeded pipes =====================
+ close(pipeRtoA1[0]); close(pipeRtoA1[1]);
+ close(pipeRtoA2[0]); close(pipeRtoA2[1]);
+ close(pipeA1toT1[1]);
+ close(pipeA2toT2[0]); close(pipeA2toT2[1]);
+ close(pipeT1toR[0]);
+ close(pipeT2toR[0]); close(pipeT2toR[1]);
+ // ==========================================
+
+ close(0); dup(pipeA1toT1[0]); close(pipeA1toT1[0]);
+ close(1); dup(pipeT1toR[1]); close(pipeT1toR[1]);
+ execl("totalsize", "totalsize", NULL);
+ }
+ else if (fork() == 0) { // totalsize 2
+ // Close unneeded pipes =====================
+ close(pipeRtoA1[0]); close(pipeRtoA1[1]);
+ close(pipeRtoA2[0]); close(pipeRtoA2[1]);
+ close(pipeA1toT1[0]); close(pipeA1toT1[1]);
+ close(pipeA2toT2[1]);
+ close(pipeT1toR[0]); close(pipeT1toR[1]);
+ close(pipeT2toR[0]);
+ // ==========================================
+
+ close(0); dup(pipeA2toT2[0]); close(pipeA2toT2[0]);
+ close(1); dup(pipeT2toR[1]); close(pipeT2toR[1]);
+ execl("totalsize", "totalsize", NULL);
+ }
+
+ // Close those pipes which parent report does not need
+ close(pipeRtoA1[0]);
+ close(pipeRtoA2[0]);
+ close(pipeA1toT1[0]); close(pipeA1toT1[1]);
+ close(pipeA2toT2[0]); close(pipeA2toT2[1]);
+ close(pipeT1toR[1]);
+ close(pipeT2toR[1]);
+
+ // Write stdin from report to accessed children
+ while (scanf("%s", filename) == 1) {
+ write(pipeRtoA1[1], strcat(filename, " "), strlen(filename) + 1);
+ write(pipeRtoA2[1], strcat(filename, " "), strlen(filename) + 1);
+ }
+
+ // Close remaining pipes.
+ close(pipeRtoA1[1]); close(pipeRtoA2[1]);
+
+ // Enter non-terminating loop to wait for children
+ while (terminateFlag) {
+ printf("*");
+ sleep(1);
+ }
+
+ // Print results of first totalsize child
+ read(pipeT1toR[0], byteSum, sizeof(byteSum)); close(pipeT1toR[0]);
+ sscanf(byteSum, " %s ", byteSum);
+ printf("\nA total of %s ", byteSum);
+
+ if ((envar = getenv("UNITS")) == NULL || !(envar[0] != 'k' || envar[0] != 'K')) {
+ printf("bytes ");
+ }
+
+ printf("are in regular files not accessed for %s days.\n----------\n", argv[1]);
+
+ // Print results of second totalsize child
+ read(pipeT2toR[0], byteSum, sizeof(byteSum)); close(pipeT2toR[0]);
+ sscanf(byteSum, " %s ", byteSum);
+ printf("A total of %s ", byteSum);
+
+ if ((envar = getenv("UNITS")) == NULL || !(envar[0] != 'k' || envar[0] != 'K')) {
+ printf("bytes ");
+ }
+
+ printf("are in regular files accessed within %s days.\n\n", argv[1]);
+ exit(0);
+}
diff --git a/pgm3/totalsize.c b/pgm3/totalsize.c
new file mode 100644
index 0000000..c15a72d
--- /dev/null
+++ b/pgm3/totalsize.c
@@ -0,0 +1,126 @@
+#include <errno.h>
+#include <math.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <time.h>
+#include <unistd.h>
+
+#define FALSE 0
+#define FILE_BUFF 4096
+#define TRUE 1
+
+struct NODE {
+ int inode;
+ long size;
+ struct NODE *next;
+};
+
+int main() {
+ /*
+ * totalsize takes in a list of filenames on its stdin and adds up the
+ * total size of those files (using stat) and prints the results as
+ * either bytes or kilobytes. It checks the UNITS environment variable to
+ * know whether to print in bytes or kilobytes. It checks the TSTALL
+ * environment variable for an integer to use as a delay before checking
+ * for files. It also checks the TMOM environment variable for the
+ * process ID of a parent process to send a SIGUSR1 signal to.
+ *
+ * totalsize builds a linked list out of the entered filenames and then
+ * goes through the unique, regular files and uses stat() to grab
+ * information about those files (inode, size).
+ */
+ char *envar = NULL;
+ char filename[FILE_BUFF];
+ int inList = FALSE;
+ int sigPID;
+ int sleepTime;
+ long long byteSum = 0;
+ struct NODE *currentNode = NULL;
+ struct NODE *head = NULL;
+ struct NODE *newNode = NULL;
+ struct stat statData;
+
+ // Check TSTALL for time delay
+ errno = 0;
+
+ if ((envar = getenv("TSTALL")) != NULL
+ && (sleepTime = strtol(envar, NULL, 10)) > 0
+ && errno == 0) {
+ sleep(sleepTime);
+ }
+
+ // Take in standard input and build linked list.
+ while (scanf(" %s", filename) == 1) {
+
+ if (stat(filename, &statData) == 0 && S_ISREG(statData.st_mode)) {
+ inList = FALSE;
+
+ for (currentNode = head; currentNode != NULL; currentNode = currentNode->next) {
+
+ if (currentNode->inode == statData.st_ino) {
+ inList = TRUE;
+ }
+
+ }
+
+ if (!inList) {
+ newNode = (struct NODE *) malloc(sizeof(struct NODE));
+ newNode->inode = statData.st_ino;
+ newNode->size = statData.st_size;
+ newNode->next = head;
+ head = newNode;
+ }
+
+ }
+
+ // Check TSTALL for time delay
+ errno = 0;
+
+ if ((envar = getenv("TSTALL")) != NULL
+ && (sleepTime = strtol(envar, NULL, 10)) > 0
+ && errno == 0) {
+ sleep(sleepTime);
+ }
+
+ }
+
+ // Add up the number of bytes and print out the results
+ byteSum = 0;
+
+ for (currentNode = head; currentNode != NULL; currentNode = currentNode->next) {
+ byteSum += currentNode->size;
+ }
+
+ if ((envar = getenv("UNITS")) != NULL
+ && (envar[0] == 'k' || envar[0] == 'K')
+ && envar[1] == '\0') {
+ byteSum /= 1024;
+ printf("%lldkB\n", byteSum);
+ }
+ else {
+ printf("%lld\n", byteSum);
+ }
+
+ // Free list
+ while (currentNode != NULL) {
+ currentNode = head;
+ head = head->next;
+ free(currentNode);
+ }
+
+ errno = 0;
+
+ // Send SIGNUSR1 signal to calling parent
+ if ((envar = getenv("TMOM")) != NULL
+ && (sigPID = strtol(envar, NULL, 10)) > 0
+ && errno == 0) {
+ kill(sigPID, SIGUSR1);
+ }
+
+ exit(0);
+}