execrom.c (3343B)
1 /* 2 * Copyright (c) 2025 Loïc Daignault-Pichette <ldp@asteride.xyz> 3 * 4 * Ce fichier fait partie d'execrom, partagé sous la licence GPLv3 (seulement). 5 * Consultez le fichier LICENCE ou le site <https://www.gnu.org/licenses/> pour 6 * plus de détails. 7 */ 8 9 #include <dirent.h> 10 #include <errno.h> 11 #include <limits.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <unistd.h> 16 17 #ifndef NAME_MAX 18 #define NAME_MAX 255 19 #endif 20 21 extern char **environ; 22 23 int 24 main(int argc, char **argv) 25 { 26 size_t taille; /* Taille du nom de la ROM */ 27 char *chems; /* Pointeur vers le contenu d’EXECROM_CHEM */ 28 char *chem; /* Variable temporaire vers un chemin */ 29 char *chemrom; /* Chemin vers la ROM */ 30 char *interp; /* Nom de l’interpréteur */ 31 char nomrom[NAME_MAX+1]; /* nom de la ROM */ 32 char **args; /* Vecteur d’arguments à transmettre à l’interpréteur */ 33 DIR *dossier; 34 struct dirent *dp; 35 36 /* execrom a besoin du nom du programme, car c’est ce qui lui permet 37 d’identifier la ROM à lancer. */ 38 if (argc < 1) { 39 fprintf(stderr, "execrom: programme lancé sans nom\n"); 40 return 1; 41 } 42 43 /* La variable d’environnement EXECROM_CHEM doit contenir une liste de 44 chemins où trouver les ROMs. Il n’y a pas de chemin par défaut. */ 45 if ((chems = getenv("EXECROM_CHEM")) == NULL || chems[0] == '\0') { 46 fprintf(stderr, "execrom: EXECROM_CHEM est vide\n"); 47 return 1; 48 } 49 50 /* Ne conserver que le nom du fichier. Important, puisque le programme 51 peut être lancé à l’aide d’un chemin relatif, comme 52 ../catalogue/rom. */ 53 for (chem = strtok(argv[0], "/"); chem; chem = strtok(NULL, "/")) 54 argv[0] = chem; 55 56 /* La taille du nom de la ROM est fournie en argument à strncmp. */ 57 taille = strlen(argv[0]); 58 59 /* Chaque dossier contenu dans EXECROM_CHEM est parcouru. La recherche 60 s’arrête lorsqu’un fichier commence par argv[0], suivi d’un point 61 (« . ») */ 62 for (chem = strtok(chems, ":"); chem; chem = strtok(NULL, ":")) { 63 /* Tenter d’ouvrir le dossier. */ 64 if ((dossier = opendir(chem)) == NULL) { 65 fprintf(stderr, "execrom: %s: %s\n", 66 chem, strerror(errno)); 67 return 1; 68 } 69 70 while ((dp = readdir(dossier)) != NULL) { 71 if (strncmp(dp->d_name, argv[0], taille) != 0) 72 continue; 73 if (dp->d_name[taille] != '.') 74 continue; 75 if (strlen(dp->d_name) > NAME_MAX) { 76 fprintf(stderr, "execrom: %s: nom trop long\n", 77 dp->d_name); 78 return 1; 79 } 80 strcpy(nomrom, dp->d_name); 81 closedir(dossier); 82 interp = nomrom + taille + 1; 83 goto trouve; 84 } 85 86 closedir(dossier); 87 } 88 /* La ROM n’a pas été trouvée. */ 89 fprintf(stderr, "execrom: %s n’est pas dans EXECROM_CHEM\n", argv[0]); 90 return 1; 91 92 /* La ROM a été trouvée. */ 93 trouve: 94 /* Bâtir le chemin vers la ROM. */ 95 if ((chemrom = malloc(strlen(nomrom) + strlen(chem) + 2)) == NULL) 96 goto erreur; 97 strcpy(chemrom, chem); 98 strcat(chemrom, "/"); 99 strcat(chemrom, nomrom); 100 101 /* Remplir le vecteur d’arguments. */ 102 if ((args = malloc((argc + 2) * (sizeof(char*)))) == NULL) 103 goto erreur; 104 args[0] = interp; 105 args[1] = chemrom; 106 argc = 2; 107 while ((args[argc++] = *++argv) != NULL) 108 ; 109 110 if (execvp(interp, args) == -1) 111 goto erreur; 112 113 return 0; 114 115 erreur: 116 fprintf(stderr, "execrom: %s\n", strerror(errno)); 117 return 1; 118 }