/* ftpstat - Web page generator for wuftpd statistics This program is public domain. No reponsibility is take for it's use by the author. You can feel free to use any part of it however you wish. This version will probably only compile on irix systems, but it should be easy enough to change that by adjusting the header files. Notes: The direction flag, while parse, is basically ignored. You'll need to replace all instances of UNKNOWN with an appropriate value. */ #define HOURLYLOGFILE "UNKNOWN/xferlog" #define DAILYLOGFILE "UNKNOWN/xferlog0" #define LOGSTORAGE "UNKNOWN/ftplog%d.stor" #define DEFTARGET "UNKNOWN/public_html/ftpstat.html" #define DIRROOT "UNKNOWN/ftp" #include #include #include #include #include #include #include #include #include #define HTTPFOOTER "\n\n\n" #define HTTPHEADER \ "\n\n\ FTP Statistics page \n\ \n\ \n\ \n\ \n\ \n\ \n
\n\ \n\ \n\
\ Ms Haruna's Homeroom\n\ \ Directly to FTP\n\ \ Quick Start\n\ \ ICE Online's Homepage\n\ \ Siggy's Homepage\n\
\n\
\n\

Recent Statistics for Siggy's FTP Server

\n" #define TODAYHEADER "

Today

\n(Updated hourly)
\n" #define THISWEEKHEADER "

Last Week

\n" #define LASTWEEKHEADER "

Previous Week

\n" typedef struct ftpstat_struct { off_t size; int number; int dir; char path[ MAXPATHLEN ]; } FTPSTAT; typedef struct daily_struct { FTPSTAT *list; int length; } daily_t; #define BUFGET 8192 char * readline( int sf ) { static char buf[ 8192 ] = ""; static char *cur = buf; static int left = 0; char *c; int res = 0; c = cur; cur = memchr( c, '\n', left ); if( !cur ) { if( left ) memmove( buf, c, left ); c = buf; res = read( sf, buf + left, BUFGET - left ); left += res; if( res < 0 ) { left = 0; perror( "read(sf)" ); return( NULL ); } cur = memchr( c, '\n', left ); if( !cur ) { if( !left ) c = NULL; left = 0; return( c ); } } *cur = 0; cur++; left -= cur - c; return( c ); } FTPSTAT * makeentry ( int sf ) { static FTPSTAT stat; char *line, *path, *size, *dir; line = readline( sf ); if( !line ) return( NULL ); size = strtok( line, " " ); // DDD if( !size ) { fprintf( stderr, "Faulty line!\n" ); return( NULL ); } size = strtok( NULL, " " ); // MMM if( !size ) { fprintf( stderr, "Faulty line!\n" ); return( NULL ); } size = strtok( NULL, " " ); // dd if( !size ) { fprintf( stderr, "Faulty line!\n" ); return( NULL ); } size = strtok( NULL, " " ); // hh:mm:ss if( !size ) { fprintf( stderr, "Faulty line!\n" ); return( NULL ); } size = strtok( NULL, " " ); // YYYY if( !size ) { fprintf( stderr, "Faulty line!\n" ); return( NULL ); } size = strtok( NULL, " " ); // transfer time if( !size ) { fprintf( stderr, "Faulty line!\n" ); return( NULL ); } size = strtok( NULL, " " ); // remote host if( !size ) { fprintf( stderr, "Faulty line!\n" ); return( NULL ); } size = strtok( NULL, " " ); // file size if( !size ) { fprintf( stderr, "Faulty line!\n" ); return( NULL ); } path = strtok( NULL, " " ); // file name if( !path ) { fprintf( stderr, "Faulty line!\n" ); return( NULL ); } dir = strtok( NULL, " " ); // transfer type if( !dir ) { fprintf( stderr, "Faulty line!\n" ); return( NULL ); } dir = strtok( NULL, " " ); // special-action-flag if( !dir ) { fprintf( stderr, "Faulty line!\n" ); return( NULL ); } dir = strtok( NULL, " " ); // direction if( !dir ) { fprintf( stderr, "Faulty line!\n" ); return( NULL ); } stat.dir = ( *dir == 'o' ? 0 : 1 ); stat.number = 1; stat.size = atol( size ) / 1024; bzero( stat.path, MAXPATHLEN ); strcpy( stat.path, DIRROOT ); strncpy( stat.path + strlen( DIRROOT ), path, MAXPATHLEN - strlen( DIRROOT ) ); stat.path[ MAXPATHLEN - 1 ] = 0; return( &stat ); } void updatestat( daily_t *today, FTPSTAT *new ) { int size; if( !today || !new ) { fprintf( stderr, "updatestat error\n" ); return; } for( size = 0; size < today->length; size++ ) if( !strcmp( today->list[ size ].path, new->path ) && new->dir == today->list[ size ].dir ) { today->list[ size ].number += new->number; return; } today->length++; today->list = realloc( today->list, sizeof( FTPSTAT ) * today->length ); memcpy( today->list + size, new, sizeof( FTPSTAT ) ); } void mergeday( daily_t *lastwk, daily_t prday ) { int i; for( i = 0; i < prday.length; i++ ) updatestat( lastwk, prday.list + i ); } int writedaily ( daily_t today ) { int df, size; char nbuf[ MAXPATHLEN ]; sprintf( nbuf, LOGSTORAGE, 0 ); df = open( nbuf, O_WRONLY | O_CREAT | O_TRUNC, 0644 ); if( df < 0 ) { perror( "open(logstor,write)" ); return( -1 ); } if( write( df, &(today.length), sizeof( int ) ) != sizeof( int ) ) { perror( "write(dailylength)" ); close( df ); return( -1 ); } size = sizeof( FTPSTAT ) * today.length; if( write( df, today.list, size ) != size ) { perror( "write(dailybody)" ); close( df ); return( -1 ); } close( df ); return( 0 ); } int readdaily ( int day, daily_t *today ) { int df, size; char nbuf[ MAXPATHLEN ]; sprintf( nbuf, LOGSTORAGE, day ); df = open( nbuf, O_RDONLY ); if( df < 0 ) { today->length = 0; perror( "open(logstor,read)" ); return( -1 ); } if( read( df, &(today->length), sizeof( int ) ) != sizeof( int ) ) { today->length = 0; perror( "read(dailylength)" ); close( df ); return( -1 ); } size = sizeof( FTPSTAT ) * today->length; today->list = malloc( size ); if( read( df, today->list, size ) != size ) { perror( "read(dailylength)" ); close( df ); return( -1 ); } close( df ); return( 0 ); } int statcomp ( const void *a, const void *b ) { int res = ((FTPSTAT *)b)->number - ((FTPSTAT *)a)->number; if( res ) return( res ); return( strcmp( ((FTPSTAT *)a)->path, ((FTPSTAT *)b)->path ) ); } void displaystat ( int df, daily_t *output, int numtoprint ) { int size, res, printed; long long tmegs = 0; int tdl = 0; char buf[ 2000 ]; qsort( output->list, output->length, sizeof( FTPSTAT ), statcomp ); for( size = 0; size < output->length; size++ ) { tdl += output->list[ size ].number; tmegs += output->list[ size ].number * output->list[ size ].size; } tmegs /= 1024l; res = sprintf( buf, "%d Downloads
\n", tdl ); write( df, buf, res ); res = sprintf( buf, "%lld M Transfered
\n", tmegs ); write( df, buf, res ); res = sprintf( buf, "\n\n", numtoprint ); write( df, buf, res ); res = sprintf( buf, "\n\n

Top %d Downloads

Downloads\nFile Size\nFile Path\n" ); write( df, buf, res ); for( printed = 0, size = 0; size < output->length && printed < numtoprint; size++ ) { if( strstr( output->list[ size ].path, "index.txt" ) || strstr( output->list[ size ].path, "README" ) ) continue; printed++; res = sprintf( buf, "
%d\n%d K\n%s\n", output->list[ size ].number, (int)output->list[ size ].size, &output->list[ size ].path[ strlen( DIRROOT ) ], &output->list[ size ].path[ strlen( DIRROOT ) ] ); write( df, buf, res ); } res = sprintf( buf, "
\n" ); write( df, buf, res ); } int main ( int argc, char *argv[] ) { int sf, df = 0; char *dstfile = DEFTARGET; FTPSTAT *stat; daily_t today = { NULL, 0 }, tempday = { NULL, 0 }; daily_t lastwk = { NULL, 0 }, prevwk = { NULL, 0 }; nice( 20 ); if( argc != 1 ) if( argc !=2 || strcmp( argv[ 1 ], "daily" ) ) { fprintf( stderr, "usage: ftpstat [daily]\n" ); return( 1 ); } else df = 1; sf = open( HOURLYLOGFILE, O_RDONLY ); if( sf < 0 ) { perror( "open sourcefile" ); return( -1 ); } while( (stat = makeentry( sf )) ) updatestat( &today, stat ); close( sf ); sf = open( DAILYLOGFILE, O_RDONLY ); if( sf < 0 ) { perror( "open sourcefile" ); return( -1 ); } while( (stat = makeentry( sf )) ) updatestat( &lastwk, stat ); close( sf ); if( df ) writedaily( lastwk ); for( sf = 1; sf < 7; sf++ ) if( readdaily( sf, &tempday ) >= 0 ) { mergeday( &lastwk, tempday ); free( tempday.list ); } for( sf = 7; sf < 14; sf++ ) if( readdaily( sf, &tempday ) >= 0 ) { mergeday( &prevwk, tempday ); free( tempday.list ); } df = open( dstfile, O_WRONLY|O_CREAT|O_TRUNC, 0644 ); if( df < 0 ) { perror( "open destfile" ); return( -1 ); } write( df, HTTPHEADER, strlen( HTTPHEADER ) ); write( df, TODAYHEADER, strlen( TODAYHEADER ) ); displaystat( df, &today, 5 ); if( today.list ) free( today.list ); write( df, THISWEEKHEADER, strlen( THISWEEKHEADER ) ); displaystat( df, &lastwk, 20 ); if( lastwk.list ) free( lastwk.list ); write( df, LASTWEEKHEADER, strlen( LASTWEEKHEADER ) ); displaystat( df, &prevwk, 20 ); if( prevwk.list ) free( prevwk.list ); write( df, HTTPFOOTER, strlen( HTTPFOOTER ) ); close( df ); return( 0 ); }