Olej писал(а):
- запуск в фоновом режиме ... типа:
Остаётся добавить...
В принципе, самое первое,
черновое решение:
Код: Выделить всё
[olej@dell 6]$ cat +shell_d.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h> // расширение стандарта C99
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <sys/wait.h>
#include <fcntl.h>
#define MAXPIPE 10 // max. длина конвейера
#define MAXARGS 20 // max. число аргументов
#define ARGLEN 100 // max. длина аргумента
static void handler( int signo ) {
printf( "\n> " );
fflush( stdout );
}
char *delim[] = { "<", ">>", ">" };
const int ndlm = sizeof( delim ) / sizeof( delim[ 0 ] );
typedef struct command { // отдельная команда конвейера
char *arglist[ MAXARGS + 1 ];
char *finout[ sizeof( delim ) / sizeof( delim[ 0 ] ) ];
bool bground;
} command_t;
void set_cmd( command_t *cmd, char *b ) { // разбор команды
for( int i = 0; i < ndlm; i++ ) cmd->finout[ i ] = NULL;
cmd->bground = false;
int narg = 0;
while( true ) {
char arg[ ARGLEN + 1 ] = "";
if( strchr( b, ' ' ) )
strncpy( arg, b, strchr( b, ' ' ) - b );
else
strcpy( arg, b );
bool bdir = false;
for( int i = 0; i < ndlm; i++ ) { // переадресация
char *p = strstr( arg, delim[ i ] );
if( p ) {
bdir = true;
p += strlen( delim[ i ] );
char file[ 256 ] = "";
cmd->finout[ i ] = strdup( strchr( p, ' ' ) ?
strncpy( file, p, strchr( p, ' ' ) - p ) :
strcpy( file, p ) );
break;
}
}
if( 0 == strcmp( arg, "&" ) ) { // фоновый режим
cmd->bground = true;
bdir = true;
}
if( !bdir )
cmd->arglist[ narg++ ] = strdup( arg );
if( strchr( b, ' ' ) ) {
b = strchr( b, ' ' );
b += strspn( b, " " );
}
else break;
}
cmd->arglist[ narg ] = NULL;
}
void free_cmd( command_t *cmd ) {
for( int i = 0; i < MAXARGS + 1 && cmd->arglist[ i ] != NULL; i++ ) {
free( cmd->arglist[ i ] );
cmd->arglist[ i ] = NULL;
}
for( int i = 0; i < ndlm; i++ )
if( cmd->finout[ i ] )
free( cmd->finout[ i ] );
}
void print_cmd( command_t *cmd ) {
printf( "args: " );
for( int i = 0; i < MAXARGS + 1 && cmd->arglist[ i ] != NULL; i++ )
printf( "[%s] ", cmd->arglist[ i ] );
bool bdir = false;
for( int i = 0; i < ndlm; i++ )
if( cmd->finout[ i ] ) {
bdir = true;
break;
}
if( bdir) {
printf( " | " );
for( int i = 0; i < ndlm; i++ )
if( cmd->finout[ i ] )
printf( "%s%s ", delim[ i ], cmd->finout[ i ] );
printf( "|" );
}
if( cmd->bground )
printf( " &" );
printf( "\n" );
}
int main( int argc, char **argv, char **envp ) {
int debug_level = 0, c;
while( -1 != ( c = getopt( argc, argv, "v" ) ) )
switch( c ) {
case 'v': debug_level++; break;
default : return 1;
}
signal( SIGINT, handler );
signal( SIGQUIT, handler );
command_t pipeline[ MAXPIPE ];
while( true ) {
char buf[ 1024 ];
printf( "> " );
fflush( stdout );
if( !fgets( buf, sizeof( buf ), stdin ) ) {
printf( "\n" );
break;
}
*strrchr( buf, '\n' ) = '\0';
if( !strlen( buf ) ) continue;
if( strstr( buf, "exit" ) == buf || strstr( buf, "quit" ) == buf )
break;
int npipe = 0;
char *b = buf + strspn( buf, " " );
while( true ) { // разделение конвейера на команды
const char *delim = " | ";
char cmd[ 256 ] = "";
if( strstr( b, " | " ) )
strncpy( cmd, b, strstr( b, " | " ) - b );
else
strcpy( cmd, b );
set_cmd( pipeline + npipe, cmd );
npipe++;
if( strstr( b, " | ") ) {
b = strstr( b, " | ") + strlen( delim );
b += strspn( b, " " );
}
else break;
}
if( debug_level )
for( int i = 0; i < npipe; i++ )
print_cmd( pipeline + i );
int nwait = npipe;
{ int fd[ npipe ][ 2 ]; // VLA !
for( int i = 0; i < npipe; i++ ) {
if( pipe( fd[ i ] ) < 0 ) {
perror( "pipe failed" );
return 1;
}
pid_t pid = fork(); // выполняется команда конвейера
if( pid < 0 ) {
perror( "fork failed" );
return 1;
}
if( 0 == pid ) { // старт команды (дочерний процесс)
if( pipeline[ i ].finout[ 0 ] != NULL ) { // <
close( 0 );
int fdi = open( pipeline[ i ].finout[ 0 ], O_RDONLY );
if( fdi < 0 ) {
perror( "input channel" );
return 1;
}
}
if( pipeline[ i ].finout[ 1 ] != NULL ) { // >>
close( 1 );
int fdo = open( pipeline[ i ].finout[ 1 ], O_WRONLY | O_CREAT | O_APPEND,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
if( fdo < 0 ) {
perror( "output channel" );
return 1;
}
}
if( pipeline[ i ].finout[ 2 ] != NULL ) { // >
close( 1 );
int fdo = open( pipeline[ i ].finout[ 2 ], O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
if( fdo < 0 ) {
perror( "output channel" );
return 1;
}
}
if( i < npipe - 1 ) { // переадресация SYSOUT в канал
dup2( fd[ i ][ 1 ], 1 );
close( fd[ i ][ 0 ] );
close( fd[ i ][ 1 ] );
}
if( i > 0 ) { // переадресация SYSIN в канал
dup2( fd[ i - 1 ][ 0 ], 0 );
close( fd[ i - 1 ][ 0 ] );
close( fd[ i - 1 ][ 1 ] );
}
if( pipeline[ i ].bground ) {
close( 0 ); close( 1 ); close( 2 );
int fd0 = open( "/dev/null", O_RDWR ),
fd1 = dup( 0 ),
fd2 = dup( 0 );
if( fd0 != 0 || fd1 != 1 || fd2 != 2 )
printf( "demonize error!\n" );
}
execvp( pipeline[ i ].arglist[ 0 ], pipeline[ i ].arglist );
perror( "execvp failed" );
return 1;
}
if( pipeline[ i ].bground ) {
printf( "[%u]\n", pid );
nwait--;
}
if( i > 0 ) { // родительский shell
close( fd[ i - 1 ][ 0 ] );
close( fd[ i - 1 ][ 1 ] );
}
} // for по конвейеру
} // block {...}
for( int i = 0; i < npipe; i++ ) // осовободить текст конвейера
free_cmd( pipeline + i );
for( int i = 0; i < nwait; i++ ) { // ожидать выполнения
int exitstatus;
wait( &exitstatus );
}
}
return EXIT_SUCCESS;
}
Проверяем (ним же запускаем - ним же и смотрим):
Код: Выделить всё
[olej@dell 6]$ ./+shell_d
> ./bgr &
[17731]
> ps -A | grep bgr
17731 pts/6 00:00:00 bgr
> ps -A | grep bgr
17731 pts/6 00:00:00 bgr
> ps -A | grep bgr
17731 pts/6 00:00:00 bgr
> ps -A | grep bgr
> exit
Запускаем такую бэкграундную тест программу:
Код: Выделить всё
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main( int argc, char *argv[] ) {
int delay = 1 == argc ? 30 : atoi( argv[ 1 ] );
sleep( delay );
return 0;
}
Для сравнения - как тот же бэкграунд выполняет стандартный bash: