/* * visitas.c * * Escrito por: Cesar Kallas - cesarkallas (at) gmx.net - http://www.opensrc.co.nr * * O que esse codigo deveria fazer: analise total de logs do apache com grafico * O que esse codigo faz no momento: apenas da o numero de request de um determinado dia. * * Por favor, me faça: * - Diferenciar request de arquivos de request da pagina principal (visita++) * - Opcoes de entrada: -d (para dia), -m (para mes), -y (para ano), -a (para todos) * - Plotar um grafico com os dados pesquisados * * O que pode ser melhorado: * - Nao eh necessario armazenar os dados em uma lista ligada como eu fiz, eu fiz por prazer :)) * - To com medo de segment fault na funcao mesi(char); * * Atencao: Esse codigo segue o padrao de logs do apache 1.3.X (testado em Apache/1.3.29 (Unix) built: Nov 2 2003 21:12:41) * * Pode ser distribuido pela Licensa GPL, para mais detalhes www.gnu.org * * 20/06/2004 por Cesar * 02/11/2004 getopt_long, listagem por mes por Emanuel Valente emanuel (at) itaponet.com */ #include #include #include #include #include #include #define SIZE_OF_IP 15 #define SIZE_OF_DATA 25 typedef struct __database{ unsigned char ip[SIZE_OF_IP]; unsigned int dia; unsigned int mes; unsigned int ano; unsigned int hora; unsigned int minutos; unsigned int segundos; struct __database *proximo; } DATA_T; void imprime_uso(FILE* stream, char* nome_programa) { fprintf(stream, "Uso: %s -f [opçoes]... \n",nome_programa); fprintf(stream, "-f, --file Arquivo a ser analisado (obrigatorio)\n" "-m, --mes Imprime a saida por mes\n" "-a, --all Imprime todas as opcoes disponiveis\n" "-h, --help Mostra a ajuda do programa\n" "-o, --output Grava o resultado em um arquivo\n"); exit(0); } int difi(int i, int j, char* data) { /* Essa funcao capta um pedaco de uma string, delimitada inicialmente * por i e com tamanho total igual a j e retorna o pedaco como inteiro. * A string deve estar em data. */ if(j>0) { char flag[j]; int x=0; for(i; xip, ip); db->dia = difi(0, 2, data); db->ano = difi(7, 4, data); db->hora = difi(12, 2, data); db->minutos = difi(15, 2, data); db->segundos = difi(18, 2, data); char mes[4]; mes[0] = data[3]; mes[1] = data[4]; mes[2] = data[5]; mes[3] = '\0'; db->mes = mesi(mes); } DATA_T* novo_no() { return (DATA_T *) malloc(sizeof(DATA_T)); } long tamanho_do_arquivo(char* file) { struct stat st; if(!stat(file, &st)) return st.st_size; else return 0; } DATA_T* le_arquivo(DATA_T *db, char* log_acessos) { FILE* dados; dados = fopen(log_acessos, "rt"); if(dados == NULL) { printf("Atencao: Arquivo '%s' nao encontrado ou com problemas.", log_acessos); printf("\nUse apenas arquivo texto para a analise.\n"); exit(1); } if(tamanho_do_arquivo(log_acessos) > 1024000) { printf("O arquivo a ser analisado '%s' eh maior que 1Mb\n", log_acessos); printf("Você tem certeza que deseja continuar ? [S/N]: "); char sn; scanf("%c", &sn); if(sn == 'n' || sn == 'N' ) exit(1); } ler_dados(dados, &db); fclose(dados); return db; //imprimir_dados(db); //visitas_dia(db, 13, 6, 2004); } /* coloca o conteudo do arquivo em uma estrutura * organizada*/ ler_dados(FILE *dados, DATA_T **db) { DATA_T *novo, *aux; char ip[SIZE_OF_IP]; char data[SIZE_OF_DATA]; char ch; while(!feof(dados)) { fscanf(dados, "%s - - [%s]", &ip, &data); if(! *db) { *db = novo_no(); novo = novo_no(); organizar_dados(novo, ip, data); *db = novo; (*db)->proximo = NULL; } else { novo = novo_no(); organizar_dados(novo, ip, data); novo->proximo = *db; (*db) = novo; } do ch = getc(dados); while(ch!='\n' && ch!=EOF); //printf("\n linha: %4d %15s %2d %3s %4d %d:%d:%d", j++, novo->ip, novo->dia, novo->mes, novo->ano, novo->hora, novo->minutos, novo->segundos); } } void imprimir_dados(DATA_T *db) { int tdia=1; while(db->proximo) { printf("\n linha: %4d %15s %2d/%2d/%4d %d:%d:%d", tdia++, db->ip, db->dia, db->mes, db->ano, db->hora, db->minutos, db->segundos); db = db->proximo; } printf("\n linha: %4d %15s %2d/%2d/%4d %d:%d:%d", tdia++, db->ip, db->dia, db->mes, db->ano, db->hora, db->minutos, db->segundos); } void imprimir_dados_por_mes(DATA_T* db, char* opcao) { char mes=atoi(opcao); unsigned int visitas = 0; while(db->proximo) { if(db->mes == mes) visitas++; db = db->proximo; } if(visitas!=0) printf("Total de Visitas no mes %d foi de %d \n", mes, visitas); else printf("Nao houveram visitas no mes %d \n",mes); exit(0); } void visitas_dia(DATA_T *db, int dia, int mes, int ano) { unsigned long int visitas=0; unsigned int aux_m = db->mes; while(db->proximo) { if(mes==db->mes && dia==db->dia && ano==db->ano) visitas++; db = db->proximo; } printf("\n\n visitas = %d", visitas); } int main(int argc, char *argv[]) { const char* const opcoes_curtas = "f:m:aho:"; /*0->nao exige argumento 1-> exige argumento*/ const struct option opcoes_longas[] = { { "file", 1, NULL, 'f'}, { "mes", 1 , NULL, 'm'}, { "all", 0 , NULL, 'a'}, { "help", 0, NULL, 'h'}, { "output", 1, NULL, 'o'}, { NULL, 0, NULL, 0} }; char* nome_programa = argv[0]; char opcao; DATA_T *db; db = NULL; int gravar_no_arquivo = 0; do { /*getopt_long retorna o caracter da opcao curta, * se a opcao for invalida retorna '?' duvidas: man getopt_long*/ opcao = getopt_long(argc, argv, opcoes_curtas, opcoes_longas, NULL); switch(opcao) { case 'f': db=le_arquivo(db, optarg); break; case 'm': imprimir_dados_por_mes(db, optarg); break; case 'a': imprimir_dados(db); /*primeira implementacao: cesar*/ break; case 'h': imprime_uso(stdout, nome_programa); break; case 'o': gravar_no_arquivo = 1; break; case '?': imprime_uso(stderr, nome_programa); break; default: imprime_uso(stderr, nome_programa); } }while(opcao != -1); }