packages: rc-scripts-user/run-fast-or-hide.c (NEW) - NEW: Waits some time f...

sparky sparky at pld-linux.org
Mon Jan 31 19:28:03 CET 2011


Author: sparky                       Date: Mon Jan 31 18:28:03 2011 GMT
Module: packages                      Tag: HEAD
---- Log message:
- NEW: Waits some time for child process to finish and returns its
  exit code. If child process keeps running just exit with code 250.

---- Files affected:
packages/rc-scripts-user:
   run-fast-or-hide.c (NONE -> 1.1)  (NEW)

---- Diffs:

================================================================
Index: packages/rc-scripts-user/run-fast-or-hide.c
diff -u /dev/null packages/rc-scripts-user/run-fast-or-hide.c:1.1
--- /dev/null	Mon Jan 31 19:28:03 2011
+++ packages/rc-scripts-user/run-fast-or-hide.c	Mon Jan 31 19:27:58 2011
@@ -0,0 +1,201 @@
+/*
+ * run-fast-or-hide:
+ *	Waits some time for child process to finish and returns its
+ * exit code. If child process keeps running just exit with code 250.
+ *
+ * 2011 (c) Przemysław Iskra <sparky at pld-linux.org>
+ *	This program is free software,
+ *  you may distribute it under GPL v2 or newer.
+ *
+ * $Id$
+ */
+
+#include <signal.h> /* sigaction */
+#include <stdlib.h> /* exit */
+#include <unistd.h> /* fork, usleep, set*id */
+#include <sys/types.h> /* waitpid */
+#include <sys/wait.h> /* waitpid */
+#include <sys/time.h> /* gettimeofday */
+#include <getopt.h> /* getopt_long */
+#include <pwd.h> /* getpwnam */
+#include <grp.h> /* initgroups */
+#include <stdio.h>
+#include <fcntl.h> /* O_RDWR */
+
+static pid_t our_child = 0;
+
+static void
+cb_sigchld( int signum )
+{
+	int status;
+	pid_t got_child;
+
+	while ( ( got_child = waitpid( 0, &status, WNOHANG ) ) > 0 ) {
+		if ( got_child == our_child ) {
+			int code = WEXITSTATUS( status );
+			exit( code == 250 ? 251 : code );
+		}
+	}
+}
+
+static void
+set_sigchld( void )
+{
+	struct sigaction action_child;
+	action_child.sa_handler = cb_sigchld;
+	action_child.sa_flags = SA_NOCLDSTOP;
+	sigemptyset( &action_child.sa_mask );
+
+	sigaction( SIGCHLD, &action_child, NULL );
+}
+
+/* usleep will be interrupted by sigchld, this thing makes sure we wait
+ * specified ammount of time if there was no child, or it wasn't the right one */
+static void
+mysleep( long int sleep_usec )
+{
+	struct timeval t_start, t_test;
+	long int slept_usec = 0;
+
+	if ( gettimeofday( &t_start, NULL ) != 0 ) {
+		usleep( sleep_usec );
+		return;
+	}
+
+	do {
+		usleep( sleep_usec - slept_usec );
+		if ( gettimeofday( &t_test, NULL ) != 0 )
+			return;
+
+		slept_usec = t_test.tv_usec - t_start.tv_usec
+			+ 1000000 * ( t_test.tv_sec - t_start.tv_sec );
+	} while ( sleep_usec > slept_usec + 10000 );
+
+	return;
+}
+
+int
+run_child( int verbose, struct passwd *pw, int nicelevel, char * const *argv )
+{
+	if ( nicelevel )
+		nice( nicelevel );
+
+	if ( pw != NULL ) {
+ 		if ( setgid( pw->pw_gid ) )
+			exit( 1 );
+		if ( initgroups( pw->pw_name, pw->pw_gid ) )
+			exit( 1 );
+		if ( setuid( pw->pw_uid ) )
+			exit( 1 );
+		if ( chdir( pw->pw_dir ) )
+			exit( 1 );
+	}
+
+	if ( ! verbose ) {
+		int null_fd = open( "/dev/null", O_RDWR );
+		dup2( null_fd, 0);
+		dup2( null_fd, 1);
+		dup2( null_fd, 2);
+	}
+
+	execvp( argv[0], argv );
+	return 127;
+}
+
+void
+die( const char *msg )
+{
+	fprintf(stderr, "ERROR: %s\n", msg);
+	exit( 127 );
+}
+
+void
+show_help( void )
+{
+	printf(
+"Usage: run-fast-or-hide [options] -- <command> <arguments>\n"
+" Run command and detach if it takes too long to execute.\n"
+"\n"
+"\n"
+"Options:\n"
+"  -h, --help                     show this help\n"
+"  -u, --user <username>          run as <username>, chdir to its home directory\n"
+"  -n, --nice <incr>              add incr to the process's nice level\n"
+"  -s, --sleep <usec>             wait <usec> microseconds before detaching\n"
+"  -v, --verbose                  don't close standard input and output\n"
+"\n"
+"Exit status:\n"
+"     0 - child exited normally\n"
+"   250 - child didn't exit yet\n"
+"   127 - execution failed\n"
+" other - exit status of the child process (it exited before timeout)\n"
+"   [*] - if child exits with code 250 it is modified to 251.\n"
+"\n"
+"Przemyslaw Iskra <sparky at pld-linux.org>, GPL v2+.\n"
+);
+
+}
+
+int
+main( int argc, char **argv )
+{
+	struct passwd *pw = NULL;
+	int nicelevel = 0;
+	int verbose = 0;
+	long int sleep_time = 500000;
+
+	static const struct option longopts[] = {
+		{ "help",	  0, NULL, 'h' },
+		{ "sleep",	  1, NULL, 's' },
+		{ "user",	  1, NULL, 'u' },
+		{ "nice",	  1, NULL, 'n' },
+		{ "quiet",	  0, NULL, 'q' },
+		{ NULL,		0, NULL, 0 }
+	};
+
+	int c;
+
+	for (;;) {
+		c = getopt_long(argc, argv, "hvs:u:n:", longopts, NULL);
+		if (c == -1)
+			break;
+		switch (c) {
+			case 'h':
+				show_help();
+				exit( 0 );
+			case 's':
+				sleep_time = atol( optarg );
+				if ( sleep_time < 1000 )
+					die( "invalid sleep time" );
+				break;
+			case 'u':
+				pw = getpwnam( optarg );
+				if ( pw == NULL )
+					die( "invalid user" );
+				break;
+			case 'n':
+				nicelevel = atoi( optarg );
+				break;
+			case 'v':
+				verbose = 1;
+				break;
+			default:
+				die( "unknown option" );
+		}
+	}
+
+	if ( argc <= optind ) {
+		die( "command is missing" );
+	}
+
+	set_sigchld();
+	our_child = fork();
+
+	if ( our_child ) {
+		mysleep( sleep_time );
+		return 250;
+	} else {
+		signal( SIGCHLD, SIG_IGN );
+		return run_child( verbose, pw, nicelevel, argv + optind );
+	}
+}
================================================================


More information about the pld-cvs-commit mailing list