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 <[email protected]>
+ *     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 <[email protected]>, 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 );
+       }
+}
================================================================
_______________________________________________
pld-cvs-commit mailing list
[email protected]
http://lists.pld-linux.org/mailman/listinfo/pld-cvs-commit

Reply via email to