[keramida at ceid.upatras.gr: Re: Utility to kill a program after n seconds]

Giorgos Keramidas keramida at ceid.upatras.gr
Sun Sep 1 17:47:01 EEST 2002


Κλασικά, πάτησα το λάθος send...
Το παρακάτω έπρεπε να πάει και στη λίστα,
αλλά τελικά πήγε μόνο προσωπικά.

----- Forwarded message from Giorgos Keramidas <keramida at ceid.upatras.gr> -----

Date: Sun, 1 Sep 2002 17:20:24 +0300
From: Giorgos Keramidas <keramida at ceid.upatras.gr>
Subject: Re: Utility to kill a program after n seconds
To: Nikos Kanellopoulos <nkan at panafonet.gr>

On 2002-09-01 16:42 +0000, Giorgos Keramidas wrote:
> On 2002-09-01 13:16 +0000, Nikos Kanellopoulos wrote:
> > Μετά από παρακίνηση του Κώστα του Μαϊστρέλη, έγραψα ένα προγραμματάκι
> > που τρέχει ένα πρόγραμμα και το σκοτώνει (πρώτα SIGTERM και αν δεν πιάσει,
> > SIGKILL) μετά από το χρόνο που καθορίζει ο χρήστης.

Με λίγες αλλαγές κάνει compile με εξαιρετικά αυστηρά warnings :)
Το patch ξεκινάει και τελειώνει με %%% στην αρχή μιας γραμμής.

    charon at hades[16:58]/a/timek$ make WARNS=5 WFORMAT=1 clean all
    rm -f timek timek.o
    Warning: Object directory not changed from original /home/charon/a/timek
    cc -O -Werror -Wall -Wno-format-y2k -W -Wstrict-prototypes \
      -Wmissing-prototypes -Wpointer-arith -Wreturn-type -Wcast-qual \
      -Wwrite-strings -Wswitch -Wshadow -Wcast-align -Wuninitialized \
      -Wformat=2 -Wno-format-nonliteral -Werror -c timek.c
    cc -O -Werror -Wall -Wno-format-y2k -W -Wstrict-prototypes \
      -Wmissing-prototypes -Wpointer-arith -Wreturn-type -Wcast-qual \
      -Wwrite-strings -Wswitch -Wshadow -Wcast-align -Wuninitialized \
      -Wformat=2 -Wno-format-nonliteral -Werror -o timek timek.o \
    charon at hades[16:58]/a/timek$

* Changelog:
------------

- Μετακίνησα το <sys/types.h> πριν από τα υπόλοιπα headers.  Τα <sys/
  headers πρέπει να είναι πριν από τα υπόλοιπα κανονικά.

- Το NSEC_KILL είναι ο χρόνος που θα περιμένει το πρόγραμμα ανάμεσα
  από τα SIGTERM->SIGKILL.  Γενικά καλό θα ήταν να του βάλεις getopt()
  κάποια στιγμή και να παίρνει τους χρόνους με κατάλληλα options αντί
  να "μαντεύει" από τη θέση τους στο command line πάντως.

- Η atoi() είναι ισοδύναμη με strtol(str, NULL, 10) και μπορεί να
  `διαβάσει' μόνο δεκαδικούς ακεραίους.  Την μετέτρεψα σε strtol(str,
  NULL, 0) που μπορεί να διαβάσει και οκταδικά και δεκαεξαδικά κα
  κάμποσα άλλα.

- Δεν υπήρχε έλεγχος για το αποτέλεσμα της atoi().  Τον έβαλα.

- Αν ο χρήστης δώσει μηδέν δευτερόλεπτα σαν χρόνο τί κάνεις; Προς το
  παρόν το έβαλα να περιμένει έτσι κι αλλιώς τουλάχιστον ένα
  δευτερόλεπτο πριν κάνει kill().

- Η perror() ξέρει πως να τυπώσει το μήνυμά της.  Μην την καλείς με
  strings όπως "\n...".

- Όλη εκείνη η φάση με το for() loop και το param[] δεν χρειάζεται.
  Μπορείς πολύ απλά να καλέσεις την execvp() με το ίδιο το argv[] σαν
  όρισμα.  Απλά αντιγράφω στο argv[1] (που δεν το χρειάζομαι πλέον)
  τον δείκτη argv[2] και καλώ την execvp(argv[1], &(argv[1]));

- Στο σημείο που κάνεις kill(SIGTERM) αν αποτύχει πρέπει να στείλεις
  απλά ένα SIGKILL και να τερματίσεις.  Δεν υπάρχει λόγος να
  περιμένεις μετά με sleep(2).

- Αν το kill(SIGTERM, pid) αποτύχει (γιατί π.χ. δεν είναι δικό σου το
  process, και δεν είσαι ο superuser) τότε μόνο θα δοκιμάσει το
  πρόγραμμα να κάνει kill(SIGKILL, pid).  Αλλιώς απλά στέλνει ένα
  SIGTERM και περιμένει με sleep(2) πριν κάνει reset το τερματικό.
  Γι' αυτό πρόσθεσα το NSEC_KILL και ένα κατάλληλο κομμάτι στο τέλος.

- Απαγορεύεται να κάνεις system("reset") σε πρόγραμμα που δεν ξέρει
  πριν κάνει reset σε τι κατάσταση ήταν το τερματικό.  Δεν έχει καμία
  δουλειά να στείλει reset στο τερματικό, αφού δεν μπορεί ούτε να
  ελέγξει (λόγω της system()) αν πέτυχε ή όχι το reset, αλλά ούτε και
  να επαναφέρει το τερματικό στην προηγούμενή του κατάσταση αν τελικά
  αυτό αποτύχει.

%%%
--- timek.c.orig	Sun Sep  1 13:16:28 2002
+++ timek.c	Sun Sep  1 16:54:19 2002
@@ -9,45 +9,55 @@
  *   http://www.himaira.net
  */
 
+#include <sys/types.h>
+
+#include <errno.h>
 #include <unistd.h>
 #include <stdio.h>
-#include <sys/types.h>
+#include <stdlib.h>
 #include <signal.h>
 
-int main (int argc, char* argv[]) {
-	int i;
-	int secs_to_sleep;
-	char* param[30];
+#define NSEC_MIN	1		/* Minimum number of wait seconds. */
+#define NSEC_KILL	3		/* Seconds before SIGKILL. */
+
+int
+main (int argc, char* argv[])
+{
 	pid_t pid;
+	unsigned int nsec;
 
 	if (argc < 3) {
-		printf("\tUsage: %s <seconds until kill> <program to run>\n", argv[0]);
+		printf("Usage: %s nsec cmd [args...]\n", argv[0]);
 		exit(1);
 	}
 
-	if (argc > 1)
-		secs_to_sleep = atoi(argv[1]);
-
-	for (i=0; i<argc; i++)
-		param[i] = argv[i+2];
-
-	param[++i] = 0;
+	errno = 0;
+	nsec = (unsigned int)strtol(argv[1], NULL, 0);
+	if (errno != 0) {
+		perror("strtol");
+		return (1);
+	}
+	if (nsec == 0)
+		nsec = NSEC_MIN;
 
 	pid = fork();
-
-	if (pid == -1) {  /* fork failed! */
-		perror("\nFork failed! Exiting.\n");
+	if (pid == -1) {
+		perror("fork");
 		exit(1);
-	} else if (pid == 0) {  	/* child process */
-		//printf("\nInside child, pid=%i\n", pid);
-		execvp ( argv[2], param);
-	} else {			/* parent process */
-		//printf("\nInside parent, pid=%i\n", pid);
-		sleep(secs_to_sleep);
-		if (kill (pid, SIGTERM) == -1)
-			kill (pid, SIGKILL);
-		sleep(2); system("reset");	/* reset terminal */
-		exit(0);
+	} else if (pid == 0) {
+		argv[1] = argv[2];
+		execvp(argv[1], &(argv[1]));
+		exit(1);
+	} else {
+		sleep(nsec);
+		if (kill(pid, SIGTERM) == -1) {
+			perror("kill");
+			kill(pid, SIGKILL);
+			return (1);
+		}
+		sleep(NSEC_KILL);
+		kill (pid, SIGKILL);
+		return(0);
 	}
-
 }
%%%

----- End forwarded message -----



More information about the Linux-greek-users mailing list