#define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include #include #include #include #include #include "error.h" #include "color.h" #include "constante.h" #define MAX_CMD_SIZE 50 typedef long long int llint; typedef unsigned long long ull; typedef struct{ char* path; //Chemin vers le dossier du processus /./proc/[pid]/ int pid; //Le pid int uid; //Le uid du proprietaire char state; //L'etat char* cmd; //La commande llint tty; llint cpu; ull start; llint vsz; llint rss; }processus; /** * Indique si une string est un nombre * @param char* Le string * @return Vrai/Faux */ boolean is_numeric(const char* str){ while(*str){ if(*str < '0' || *str > '9'){ return false; } str++; } return true; } /** * Tri les processus par pid croissant * @param processus** Le tableau de processus */ void sort_pid(processus** proc, int size){ processus* tmp; int index; for(int i = 1; i < size; i++){ index = i; while(index > 0 && proc[index]->pid < proc[index - 1]->pid){ tmp = proc[index]; proc[index] = proc[index - 1]; proc[index - 1] = tmp; index--; } } } int get_uptime() { FILE* procUptime; int sec, ssec; procUptime = fopen("/proc/uptime", "r"); int tmp = fscanf(procUptime, "%d.%ds", &sec, &ssec); tmp++; //Pour ne pas avoir de warning fclose(procUptime); return (sec * sysconf(_SC_CLK_TCK)) + ssec; } /** * Liste les processus actifs * @param int* Le nombre de processus actif * @return processus** La liste */ processus** list_process(int* nb){ struct dirent** dir; struct stat info; int nbRes; int length, compteur = 0; char* path; processus** result; //Recup les dossiers if((nbRes = scandir("/./proc/", &dir, 0, alphasort)) == ERR){ addperror("Impossible de scanner le dossier"); return NULL; } //Compte le nombre de resultat for(int i = 0; i < nbRes; i++){ //Création chemin length = strlen(dir[i]->d_name) + 10; path = malloc(sizeof(char) * length); memset(path, 0, length); snprintf(path, length, "/./proc/%s/", dir[i]->d_name); //Recup info if(stat(path, &info) == ERR){ //Pas un dossier continue; } //Ne regarde que les dossiers dont le nom est un nombre if(S_ISDIR(info.st_mode) && is_numeric(dir[i]->d_name)){ compteur++; } free(path); } //Allocation resultat result = malloc(sizeof(processus*) * compteur); //Ajout des resultats compteur = 0; for(int i = 0; i < nbRes; i++){ //Création chemin length = strlen(dir[i]->d_name) + 10; path = malloc(sizeof(char) * length); memset(path, 0, length); snprintf(path, length, "/./proc/%s/", dir[i]->d_name); //Recup info if(stat(path, &info) == ERR){ //Pas un dossier continue; } //Ne regarde que les dossiers dont le nom est un nombre if(S_ISDIR(info.st_mode) && is_numeric(dir[i]->d_name)){ result[compteur] = malloc(sizeof(processus)); result[compteur]->path = path; result[compteur]->pid = atoi(dir[i]->d_name); result[compteur]->uid = info.st_uid; compteur++; continue; } free(path); } //Libere memoire while(nbRes--){ free(dir[nbRes]); } free(dir); //Retour if(nb != NULL){ *nb = compteur; } return result; } /** * Lecture du fichier status d'un processus * @param processus* Le processus * @return Reussite */ boolean read_status(processus* proc){ char* file; FILE* f; int length, tmp; char buffer[BUFFER_SIZE]; llint trash; //Recup nom du fichier length = strlen(proc->path) + 5; file = malloc(sizeof(char) * length); memset(file, 0, length); snprintf(file, length, "%sstat", proc->path); //Ouverture fichier f = fopen(file, "r");; if(!f){ free(file); return false; } free(file); //Lecture des informations tmp = fscanf(f, "%lld ", &trash); tmp = fscanf(f, "%s ", buffer); tmp = fscanf(f, "%c ", &proc->state); for (int i = 0; i < 3; i++){ tmp = fscanf(f, "%lld ", &trash); } tmp = fscanf(f, "%lld ", &proc->tty); for (int i = 0; i < 6; i++){ tmp = fscanf(f, "%lld ", &trash); } tmp = fscanf(f, "%lld ", &proc->cpu); for (int i = 0; i < 7; i++){ tmp = fscanf(f, "%lld ", &trash); } tmp = fscanf(f, "%llu ", &proc->start); tmp = fscanf(f, "%lld ", &proc->vsz); tmp = fscanf(f, "%lld ", &proc->rss); tmp++; //Pour ne pas avoir de warning fclose(f); return true; } /** * Lecture du fichier comm d'un processus * @param processus* Le processus * @return Reussite */ boolean read_comm(processus* proc){ char* file; int length, fd; int size = 0; char buf = ' '; char* buffer; boolean first = true; //Recup nom du fichier length = strlen(proc->path) + 5; file = malloc(sizeof(char) * length); memset(file, 0, length); snprintf(file, length, "%scomm", proc->path); //Ouverture fichier fd = open(file, O_RDONLY); if(fd == ERR){ free(file); return false; } free(file); //Compte la taille du mot while(buf != '\n' && buf != '\0' && buf != EOF){ if(read(fd, &buf, sizeof(char)) == ERR){ return false; } //Au 1er tour if(first){ //Si fichier vide if(buf == ' '){ if(close(fd) == ERR){ //Rien de particulier } return false; } first = false; } size++; } size--; //Revient au debut if(lseek(fd, 0L, SEEK_SET) == ERR){ return false; } //Lecture commande buffer = malloc(sizeof(char) * (size + 3)); memset(buffer, 0, size + 3); buffer[0] = '['; if(read(fd, buffer + 1, size) == ERR){ return false; } buffer[strlen(buffer)] = ']'; proc->cmd = buffer; //Fermeture if(close(fd) == ERR){ //Rien de particulier } return true; } /** * Lecture du fichier cmdline d'un processus * @param processus* Le processus * @return Reussite */ boolean read_cmd(processus* proc){ char* file; int length, fd; int size = 0; char buf = ' '; char* buffer; boolean first = true; //Recup nom du fichier length = strlen(proc->path) + 8; file = malloc(sizeof(char) * length); memset(file, 0, length); snprintf(file, length, "%scmdline", proc->path); //Ouverture fichier fd = open(file, O_RDONLY); if(fd == ERR){ free(file); return false; } free(file); //Compte la taille du mot while(buf != '\n' && buf != '\0' && buf != EOF){ if(read(fd, &buf, sizeof(char)) == ERR){ return false; } //Au 1er tour if(first){ //Si fichier vide if(buf == ' '){ if(close(fd) == ERR){ //Rien de particulier } return read_comm(proc); } first = false; } size++; //On evite les boucles infini if(size > MAX_CMD_SIZE){ break; } } size--; //Revient au debut if(lseek(fd, 0L, SEEK_SET) == ERR){ return false; } //Lecture commande buffer = malloc(sizeof(char) * (size + 1)); memset(buffer, 0, size + 1); if(read(fd, buffer, size) == ERR){ return false; } proc->cmd = buffer; //Fermeture if(close(fd) == ERR){ //Rien de particulier } return true; } /** * Affiche les infos d'un processus * @param processus* Le processus */ void printps(processus* proc){ struct passwd* user; boolean color = false; llint vsize; char start[BUFFER_SIZE]; //Recup le nom de l'utilisateur user = getpwuid(proc->uid); if(user == NULL){ addperror("Impossible de récupérer le nom de l'utilisateur"); return; } //VSZ vsize = proc->vsz / 1024; //Debut int uptime = get_uptime(); int running = uptime - proc->start; time_t runningTime = time(NULL) - (running / sysconf(_SC_CLK_TCK)); strftime(start, sizeof(start), "%H:%M", localtime(&runningTime)); //Couleur if(proc->state == 's'){ printf(RED); } if(proc->state == 'r'){ printf(MAGENTA); } switch(proc->state){ case 'S': printf(RED); color = true; break; case 'R': printf(YELLOW); color = true; break; case 'N': printf(BLUE); color = true; break; case 'Z': printf(GREEN); color = true; break; case 'T': printf(MAGENTA); color = true; break; case 'D': printf(CYAN); color = true; break; } //Affiche (Manque %CPU, %MEM, TIME) printf("%s %d %lld %lld %lld %c %s %s\n", user->pw_name, proc->pid, vsize, proc->rss, proc->tty, proc->state, start, proc->cmd); if(color){ printf(RESET); } } int main(){ int total; processus** proc = list_process(&total); //Tri des processus par rapport à leur pid sort_pid(proc, total); if(total > 0){ printf("USER PID VSZ RSS TTY STAT START COMMAND \n"); } for(int i = 0; i < total; i++){ //Recup info manquante if(!read_status(proc[i])){ free(proc[i]->path); free(proc[i]); continue; } if(!read_cmd(proc[i])){ free(proc[i]->path); free(proc[i]); continue; } //Affiche printps(proc[i]); //Supprime free(proc[i]->path); free(proc[i]->cmd); free(proc[i]); } free(proc); return EXIT_SUCCESS; }