myps.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. #define _POSIX_C_SOURCE 200809L
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <dirent.h>
  5. #include <string.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>
  10. #include <pwd.h>
  11. #include <time.h>
  12. #include "error.h"
  13. #include "color.h"
  14. #include "constante.h"
  15. #define MAX_CMD_SIZE 50
  16. typedef long long int llint;
  17. typedef unsigned long long ull;
  18. typedef struct{
  19. char* path; //Chemin vers le dossier du processus /./proc/[pid]/
  20. int pid; //Le pid
  21. int uid; //Le uid du proprietaire
  22. char state; //L'etat
  23. char* cmd; //La commande
  24. llint tty;
  25. llint cpu;
  26. ull start;
  27. llint vsz;
  28. llint rss;
  29. }processus;
  30. /**
  31. * Indique si une string est un nombre
  32. * @param char* Le string
  33. * @return Vrai/Faux
  34. */
  35. boolean is_numeric(const char* str){
  36. while(*str){
  37. if(*str < '0' || *str > '9'){
  38. return false;
  39. }
  40. str++;
  41. }
  42. return true;
  43. }
  44. /**
  45. * Tri les processus par pid croissant
  46. * @param processus** Le tableau de processus
  47. */
  48. void sort_pid(processus** proc, int size){
  49. processus* tmp;
  50. int index;
  51. for(int i = 1; i < size; i++){
  52. index = i;
  53. while(index > 0 && proc[index]->pid < proc[index - 1]->pid){
  54. tmp = proc[index];
  55. proc[index] = proc[index - 1];
  56. proc[index - 1] = tmp;
  57. index--;
  58. }
  59. }
  60. }
  61. int get_uptime() {
  62. FILE* procUptime;
  63. int sec, ssec;
  64. procUptime = fopen("/proc/uptime", "r");
  65. int tmp = fscanf(procUptime, "%d.%ds", &sec, &ssec);
  66. tmp++; //Pour ne pas avoir de warning
  67. fclose(procUptime);
  68. return (sec * sysconf(_SC_CLK_TCK)) + ssec;
  69. }
  70. /**
  71. * Liste les processus actifs
  72. * @param int* Le nombre de processus actif
  73. * @return processus** La liste
  74. */
  75. processus** list_process(int* nb){
  76. struct dirent** dir;
  77. struct stat info;
  78. int nbRes;
  79. int length, compteur = 0;
  80. char* path;
  81. processus** result;
  82. //Recup les dossiers
  83. if((nbRes = scandir("/./proc/", &dir, 0, alphasort)) == ERR){
  84. addperror("Impossible de scanner le dossier");
  85. return NULL;
  86. }
  87. //Compte le nombre de resultat
  88. for(int i = 0; i < nbRes; i++){
  89. //Création chemin
  90. length = strlen(dir[i]->d_name) + 10;
  91. path = malloc(sizeof(char) * length);
  92. memset(path, 0, length);
  93. snprintf(path, length, "/./proc/%s/", dir[i]->d_name);
  94. //Recup info
  95. if(stat(path, &info) == ERR){
  96. //Pas un dossier
  97. continue;
  98. }
  99. //Ne regarde que les dossiers dont le nom est un nombre
  100. if(S_ISDIR(info.st_mode) && is_numeric(dir[i]->d_name)){
  101. compteur++;
  102. }
  103. free(path);
  104. }
  105. //Allocation resultat
  106. result = malloc(sizeof(processus*) * compteur);
  107. //Ajout des resultats
  108. compteur = 0;
  109. for(int i = 0; i < nbRes; i++){
  110. //Création chemin
  111. length = strlen(dir[i]->d_name) + 10;
  112. path = malloc(sizeof(char) * length);
  113. memset(path, 0, length);
  114. snprintf(path, length, "/./proc/%s/", dir[i]->d_name);
  115. //Recup info
  116. if(stat(path, &info) == ERR){
  117. //Pas un dossier
  118. continue;
  119. }
  120. //Ne regarde que les dossiers dont le nom est un nombre
  121. if(S_ISDIR(info.st_mode) && is_numeric(dir[i]->d_name)){
  122. result[compteur] = malloc(sizeof(processus));
  123. result[compteur]->path = path;
  124. result[compteur]->pid = atoi(dir[i]->d_name);
  125. result[compteur]->uid = info.st_uid;
  126. compteur++;
  127. continue;
  128. }
  129. free(path);
  130. }
  131. //Libere memoire
  132. while(nbRes--){
  133. free(dir[nbRes]);
  134. }
  135. free(dir);
  136. //Retour
  137. if(nb != NULL){
  138. *nb = compteur;
  139. }
  140. return result;
  141. }
  142. /**
  143. * Lecture du fichier status d'un processus
  144. * @param processus* Le processus
  145. * @return Reussite
  146. */
  147. boolean read_status(processus* proc){
  148. char* file;
  149. FILE* f;
  150. int length, tmp;
  151. char buffer[BUFFER_SIZE];
  152. llint trash;
  153. //Recup nom du fichier
  154. length = strlen(proc->path) + 5;
  155. file = malloc(sizeof(char) * length);
  156. memset(file, 0, length);
  157. snprintf(file, length, "%sstat", proc->path);
  158. //Ouverture fichier
  159. f = fopen(file, "r");;
  160. if(!f){
  161. free(file);
  162. return false;
  163. }
  164. free(file);
  165. //Lecture des informations
  166. tmp = fscanf(f, "%lld ", &trash);
  167. tmp = fscanf(f, "%s ", buffer);
  168. tmp = fscanf(f, "%c ", &proc->state);
  169. for (int i = 0; i < 3; i++){
  170. tmp = fscanf(f, "%lld ", &trash);
  171. }
  172. tmp = fscanf(f, "%lld ", &proc->tty);
  173. for (int i = 0; i < 6; i++){
  174. tmp = fscanf(f, "%lld ", &trash);
  175. }
  176. tmp = fscanf(f, "%lld ", &proc->cpu);
  177. for (int i = 0; i < 7; i++){
  178. tmp = fscanf(f, "%lld ", &trash);
  179. }
  180. tmp = fscanf(f, "%llu ", &proc->start);
  181. tmp = fscanf(f, "%lld ", &proc->vsz);
  182. tmp = fscanf(f, "%lld ", &proc->rss);
  183. tmp++; //Pour ne pas avoir de warning
  184. fclose(f);
  185. return true;
  186. }
  187. /**
  188. * Lecture du fichier comm d'un processus
  189. * @param processus* Le processus
  190. * @return Reussite
  191. */
  192. boolean read_comm(processus* proc){
  193. char* file;
  194. int length, fd;
  195. int size = 0;
  196. char buf = ' ';
  197. char* buffer;
  198. boolean first = true;
  199. //Recup nom du fichier
  200. length = strlen(proc->path) + 5;
  201. file = malloc(sizeof(char) * length);
  202. memset(file, 0, length);
  203. snprintf(file, length, "%scomm", proc->path);
  204. //Ouverture fichier
  205. fd = open(file, O_RDONLY);
  206. if(fd == ERR){
  207. free(file);
  208. return false;
  209. }
  210. free(file);
  211. //Compte la taille du mot
  212. while(buf != '\n' && buf != '\0' && buf != EOF){
  213. if(read(fd, &buf, sizeof(char)) == ERR){
  214. return false;
  215. }
  216. //Au 1er tour
  217. if(first){
  218. //Si fichier vide
  219. if(buf == ' '){
  220. if(close(fd) == ERR){
  221. //Rien de particulier
  222. }
  223. return false;
  224. }
  225. first = false;
  226. }
  227. size++;
  228. }
  229. size--;
  230. //Revient au debut
  231. if(lseek(fd, 0L, SEEK_SET) == ERR){
  232. return false;
  233. }
  234. //Lecture commande
  235. buffer = malloc(sizeof(char) * (size + 3));
  236. memset(buffer, 0, size + 3);
  237. buffer[0] = '[';
  238. if(read(fd, buffer + 1, size) == ERR){
  239. return false;
  240. }
  241. buffer[strlen(buffer)] = ']';
  242. proc->cmd = buffer;
  243. //Fermeture
  244. if(close(fd) == ERR){
  245. //Rien de particulier
  246. }
  247. return true;
  248. }
  249. /**
  250. * Lecture du fichier cmdline d'un processus
  251. * @param processus* Le processus
  252. * @return Reussite
  253. */
  254. boolean read_cmd(processus* proc){
  255. char* file;
  256. int length, fd;
  257. int size = 0;
  258. char buf = ' ';
  259. char* buffer;
  260. boolean first = true;
  261. //Recup nom du fichier
  262. length = strlen(proc->path) + 8;
  263. file = malloc(sizeof(char) * length);
  264. memset(file, 0, length);
  265. snprintf(file, length, "%scmdline", proc->path);
  266. //Ouverture fichier
  267. fd = open(file, O_RDONLY);
  268. if(fd == ERR){
  269. free(file);
  270. return false;
  271. }
  272. free(file);
  273. //Compte la taille du mot
  274. while(buf != '\n' && buf != '\0' && buf != EOF){
  275. if(read(fd, &buf, sizeof(char)) == ERR){
  276. return false;
  277. }
  278. //Au 1er tour
  279. if(first){
  280. //Si fichier vide
  281. if(buf == ' '){
  282. if(close(fd) == ERR){
  283. //Rien de particulier
  284. }
  285. return read_comm(proc);
  286. }
  287. first = false;
  288. }
  289. size++;
  290. //On evite les boucles infini
  291. if(size > MAX_CMD_SIZE){
  292. break;
  293. }
  294. }
  295. size--;
  296. //Revient au debut
  297. if(lseek(fd, 0L, SEEK_SET) == ERR){
  298. return false;
  299. }
  300. //Lecture commande
  301. buffer = malloc(sizeof(char) * (size + 1));
  302. memset(buffer, 0, size + 1);
  303. if(read(fd, buffer, size) == ERR){
  304. return false;
  305. }
  306. proc->cmd = buffer;
  307. //Fermeture
  308. if(close(fd) == ERR){
  309. //Rien de particulier
  310. }
  311. return true;
  312. }
  313. /**
  314. * Affiche les infos d'un processus
  315. * @param processus* Le processus
  316. */
  317. void printps(processus* proc){
  318. struct passwd* user;
  319. boolean color = false;
  320. llint vsize;
  321. char start[BUFFER_SIZE];
  322. //Recup le nom de l'utilisateur
  323. user = getpwuid(proc->uid);
  324. if(user == NULL){
  325. addperror("Impossible de récupérer le nom de l'utilisateur");
  326. return;
  327. }
  328. //VSZ
  329. vsize = proc->vsz / 1024;
  330. //Debut
  331. int uptime = get_uptime();
  332. int running = uptime - proc->start;
  333. time_t runningTime = time(NULL) - (running / sysconf(_SC_CLK_TCK));
  334. strftime(start, sizeof(start), "%H:%M", localtime(&runningTime));
  335. //Couleur
  336. if(proc->state == 's'){
  337. printf(RED);
  338. }
  339. if(proc->state == 'r'){
  340. printf(MAGENTA);
  341. }
  342. switch(proc->state){
  343. case 'S':
  344. printf(RED);
  345. color = true;
  346. break;
  347. case 'R':
  348. printf(YELLOW);
  349. color = true;
  350. break;
  351. case 'N':
  352. printf(BLUE);
  353. color = true;
  354. break;
  355. case 'Z':
  356. printf(GREEN);
  357. color = true;
  358. break;
  359. case 'T':
  360. printf(MAGENTA);
  361. color = true;
  362. break;
  363. case 'D':
  364. printf(CYAN);
  365. color = true;
  366. break;
  367. }
  368. //Affiche (Manque %CPU, %MEM, TIME)
  369. 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);
  370. if(color){
  371. printf(RESET);
  372. }
  373. }
  374. int main(){
  375. int total;
  376. processus** proc = list_process(&total);
  377. //Tri des processus par rapport à leur pid
  378. sort_pid(proc, total);
  379. if(total > 0){
  380. printf("USER PID VSZ RSS TTY STAT START COMMAND \n");
  381. }
  382. for(int i = 0; i < total; i++){
  383. //Recup info manquante
  384. if(!read_status(proc[i])){
  385. free(proc[i]->path);
  386. free(proc[i]);
  387. continue;
  388. }
  389. if(!read_cmd(proc[i])){
  390. free(proc[i]->path);
  391. free(proc[i]);
  392. continue;
  393. }
  394. //Affiche
  395. printps(proc[i]);
  396. //Supprime
  397. free(proc[i]->path);
  398. free(proc[i]->cmd);
  399. free(proc[i]);
  400. }
  401. free(proc);
  402. return EXIT_SUCCESS;
  403. }