/**************************************************************************** * * * Copyright 2004-2011 NetApp Inc. All rights reserved. This file is * * confidential and a trade secret of NetApp Inc. The receipt or * * possession of this file does not convey any rights to reproduce or * * disclose its contents or to manufacture, use, or sell anything it may * * describe, in whole, or in part, without the specific written consent of * * LSI Corporation. * * * ****************************************************************************/ /**************************************************************************** * * * NAME fwdCmdSvr.c * * SUMMARY * * VERSION %version: % * * UPDATE DATE %date_modified: % * * PROGRAMMER %created_by: Merck Hung % * * * * Copyright 2002-2011 NetApp Inc. All Rights Reserved. * * * * DESCRIPTION: * * * ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include "fwdCmd.h" int exeCmdAndOutputToBuffer(char *cmd_str, char *buffer, int buffer_length) { FILE *fp; fp = popen(cmd_str, "r"); if(fp==NULL) { return -1; } int c; int buf_len; buf_len = buffer_length -1; //reserv for null char if output is large than buffer size while(((c=fgetc(fp))!=EOF)&&(buf_len>0)) { buffer += sprintf(buffer, "%c", c); buf_len--; } pclose(fp); return buffer_length - buf_len; } void usage( void ) { fprintf( stderr, "\n" ); fprintf( stderr, FWD_CMD_SVR_NAME "\n" ); fprintf( stderr, "Usage: " FWD_CMD_SVR_NAME " -i IPADDR | [-h] | [-c] | [-v]\n" ); fprintf( stderr, "\t-h\tprint this message\n" ); fprintf( stderr, "\t-i\tIPv4 address\n" ); fprintf( stderr, "\t-c\tdo not run as daemon\n" ); fprintf( stderr, "\t-v\tverbose\n" ); fprintf( stderr, "\n" ); } unsigned char isIPv4Format( const char *str ) { int i, j, pos[ 3 ], len; char buf[ IP_STR_BUF ]; unsigned int addr[ 4 ]; unsigned char valid = TRUE; // Length check len = strlen( str ); if( len > IP_STR_LEN || len < IP_STR_LEN_MIN ) return FALSE; strncpy( buf, str, IP_STR_BUF ); // Look for positions of delimiters for( i = 0, j = 0 ; i < len ; i++ ) { if( buf[ i ] == '.' ) { // Exceed the limit if( j >= 3 ) return FALSE; // Record & Terminate string pos[ j ] = i; buf[ i ] = 0; j++; } } // Must have 3 dots at least or at most if( j != 3 ) return FALSE; // Convert strings addr[ 0 ] = strtol( (const char *)&buf[ 0 ], NULL, 10 ); addr[ 1 ] = strtol( (const char *)&buf[ pos[ 0 ] + 1 ], NULL, 10 ); addr[ 2 ] = strtol( (const char *)&buf[ pos[ 1 ] + 1 ], NULL, 10 ); addr[ 3 ] = strtol( (const char *)&buf[ pos[ 2 ] + 1 ], NULL, 10 ); // Check range for( i = 0 ; i < 4 ; i++ ) if( addr[ i ] > 255 ) { valid = FALSE; break; } // Not ZERO snprintf( buf, IP_STR_BUF, "%d.%d.%d.%d", addr[ 0 ], addr[ 1 ], addr[ 2 ], addr[ 3 ] ); if( strcmp( buf, str ) ) valid = FALSE; return valid; } int main( int argc, char **argv ) { int sfd, cfd, ret = 0; struct sockaddr_in servaddr, cliaddr; socklen_t clilen = sizeof( struct sockaddr_in ); pid_t pid, sid; int sockopt_on = 1, verbose = 0; int c; char daemon = 1; char *ipaddr = NULL, ipbuf[ IP_STR_BUF + 1 ]; unsigned int size = DEFAULT_BUFSIZE; char wbuf[ DEFAULT_BUFSIZE ]; char rbuf[ DEFAULT_BUFSIZE ]; int wbytes; int rbytes; // Handle parameters while( (c = getopt( argc, argv, "i:vch" )) != EOF ) { switch( c ) { case 'i': strncpy( ipbuf, optarg, sizeof( ipbuf ) ); if( isIPv4Format( ipbuf ) == TRUE ) ipaddr = ipbuf; break; case 'c': daemon = 0; break; case 'v': verbose = 1; break; case 'h': default: usage(); return -1; } } // Sanity check if( !size ) { fprintf( stderr, FWD_CMD_SVR_NAME ": Invalid size(%d)\n", size ); return -1; } if( !ipaddr ) { fprintf( stderr, FWD_CMD_SVR_NAME ": Invalid ip addr\n" ); return -1; } // Become Daemon if( daemon ) { // Fork a child process pid = fork(); if( pid < 0 ) { fprintf( stderr, FWD_CMD_SVR_NAME ": Cannot fork child process.\n" ); exit( 1 ); } // Terminate parent process if( pid > 0 ) exit( 0 ); umask( 0 ); // Set SID sid = setsid(); if( sid < 0 ) { exit( 1 ); } // Change location to root if( chdir( "/" ) < 0 ) { exit( 1 ); } // Close standard input, output, and error close( 0 ); close( 1 ); close( 2 ); } signal(SIGCHLD, SIG_IGN); // avoid defunct child process whith wait() in parent process // Main procedure sfd = socket( PF_INET, SOCK_STREAM, 0 ); if( sfd < 0 ) { fprintf( stderr, FWD_CMD_SVR_NAME ": Cannot open socket\n" ); return 1; } // Reusable if( setsockopt( sfd, SOL_SOCKET, SO_REUSEADDR, &sockopt_on, sizeof( int ) ) == -1 ) { fprintf( stderr, FWD_CMD_SVR_NAME ": Cannot make reusable\n" ); goto errexit; } // Set address memset( &servaddr, 0, sizeof( struct sockaddr_in ) ); servaddr.sin_family = PF_INET; servaddr.sin_port = htons( PORT_NUM ); ret = inet_aton( ipaddr, &servaddr.sin_addr ); if( ret < 0 ) { fprintf( stderr, FWD_CMD_SVR_NAME ": Cannot set IP address %s\n", ipaddr ); goto errexit; } // Bind network port ret = bind( sfd, (struct sockaddr *)&servaddr, sizeof( struct sockaddr_in ) ); if( ret < 0 ) { fprintf( stderr, FWD_CMD_SVR_NAME ": Cannot bind network port %d\n", PORT_NUM ); goto errexit; } // Listen network port ret = listen( sfd, 10 ); if( ret < 0 ) { fprintf( stderr, FWD_CMD_SVR_NAME ": Cannot listen network port %d\n", PORT_NUM ); goto errexit; } // Handle incoming connections while( 1 ) { // Accept new connection cfd = accept( sfd, (struct sockaddr *)&cliaddr, &clilen ); if( cfd < 0 ) continue; // Fork a child process if( 0==fork()) { close(sfd); // Clear buffer memset( rbuf, 0, DEFAULT_BUFSIZE ); // Read incoming data rbytes = read( cfd, rbuf, size ); if( rbytes < 0 ) { close(cfd); exit(0); } // Child process, execute command and exit if(0==strncmp(rbuf, "popen", 5)) { memset(wbuf, 0, sizeof(wbuf)); wbytes = exeCmdAndOutputToBuffer(rbuf+5, wbuf, sizeof(wbuf)); write(cfd,wbuf, wbytes); } else { sprintf(rbuf, "%s > /dev/null", rbuf); system( rbuf ); } // Close this connection close( cfd ); exit( 0 ); } else { close(cfd); } } errexit: // Close socket close( sfd ); return ret; }