myps.c 8.8 KB

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