/* Ce programme génére des menus * pour fvwm à partir d'un fichier * qui contient une base de donnée * des application existantes. * Auteur Philippe Pepiot * Contact : <philux (at) tuxfamily (dot) org> * http://fvwm.tuxfamily.org * N'hésitez pas à me contacter si vous * avez des question, ou des commentaires * ou encore des idées d'amélioration. * Ce code est sous la même licence que * fvwm. */ /* Les includes qui font bien */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <dirent.h> #include <assert.h> #include <errno.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/mman.h> #include <sys/wait.h> /* VARIABLES GLOBALES */ /* La chaine qui contient la valeur de $PATH */ char *PATH; /* La longeur de PATH */ size_t path_len; /* La liste des menus (pour la destruction */ typedef struct liste_menus liste_menus; struct liste_menus { char *name; struct liste_menus *next; }; typedef liste_menus* llist; llist menu_list = NULL; /* Déclaration externes */ char *get_current_dir_name(void); /* Déclaration diverses et variées */ void make_appli(char *ptr, const char *sudo_gui); int make_popup(char *str); int which_cmd(char *str); llist add_menu(llist liste, char *name); int test_menu(llist liste, char *name); void free_liste(llist liste); int FvwmCommand(char *cmd); typedef unsigned short ushort; int main(int argc, char* const argv[]) { if (argc != 2) { printf("Usage : %s <input_file>\n", argv[0]); exit(1); } int fd; char* buffer; struct stat buf; if (-1 == (fd = open(argv[1], O_RDONLY))) { fprintf(stderr, "\033[34mVous ne pouvez pas ouvrir ce fichier en lecture seule\n\033[37m"); exit(1); } if (-1 == stat(argv[1], &buf)) { perror("stat() "); close(fd); exit(1); } /* on mappe le fichier en mémoire */ buffer = (char*)mmap(0, (int)buf.st_size, PROT_READ, MAP_SHARED, fd, 0); if ((char*)-1 == buffer) { perror("mmap() "); close(fd); exit(1); } close(fd); /***************************/ /* Le path root est ajouté pour permettre de tester * les application à lancer en root (via sudo ou gksu/kdesu */ const char *PATH_ROOT = "/usr/local/sbin:/usr/sbin:/sbin"; PATH = malloc(sizeof(char) * (1+strlen(getenv("PATH"))+strlen(PATH_ROOT))); sprintf(PATH, "%s:%s", getenv("PATH"), PATH_ROOT); path_len = strlen(PATH); /* On teste si sudo gksu kdesu sont présents sur le systeme */ if (which_cmd("sudo") != 0) fprintf(stderr, "\033[36mATTENTION : sudo n'est pas présent dans votre PATH\033[37m\n"); char sudo_gui[6]; if (which_cmd("gksu") == 0) { strcpy(sudo_gui, "gksu"); printf("\033[36mUtilisation de gksu\033[37m\n"); } else if(which_cmd("kdesu") == 0) { strcpy(sudo_gui, "kdesu"); printf("\033[36mUtilisation de kdesu\033[37m\n"); } else { fprintf(stderr, "\033[36mATTENTION : kdesu ou gksu ne sont pas présents dans votre PATH, on utilisera sudo\033[37m\n"); strcpy(sudo_gui, "sudo"); } make_appli(buffer, sudo_gui); free_liste(menu_list); free(PATH); /***************************/ munmap(buffer, (int)buf.st_size); return 0; } /* Fonction récursive */ void make_appli(char *ptr, const char *sudo_gui) { char *p; char *p_tmp; char *str; char *argv[5]; int i = 0, j; /* La commande finale */ char *cmd_final; size_t size_cmd_final; /* Tout d'abord on copie la ligne courante * dans str */ p = strchr(ptr, '\n'); /* Si p == NULL, c'est que c'est * la fin du fichier */ if (p == NULL) return; /* Si c'est un commentaire */ if(ptr[0] == '#') return make_appli(p+1, sudo_gui); str = malloc(sizeof(char) * (1+p-ptr)); memcpy(str, ptr, p-ptr); str[p-ptr] = '\0'; /* Injection directe */ if (str[0] == '>') { printf("\033[34mAjout direct \033[36m\"%s\"\n\033[37m", str+1); FvwmCommand(str+1); free(str); return make_appli(p+1, sudo_gui); } if(str[0] == '@') { make_popup(str); free(str); return make_appli(p+1, sudo_gui); } p_tmp = strtok(str, ":"); while((p_tmp != NULL)) { argv[i] = malloc(sizeof(char) * (1+strlen(p_tmp))); assert(argv[i] != NULL); strcpy(argv[i], p_tmp); i++; p_tmp = strtok(NULL, ":"); } free(str); if (i != 5) { fprintf(stderr, "\033[31mErreur d'analyse de la ligne '"); for(j = 0; j < i; j++) { fprintf(stderr, "%s:", argv[j]); free(argv[j]); } fprintf(stderr, "\n\033[37m"); return make_appli(p+1, sudo_gui); } char *cmd; p_tmp = strchr(argv[1], ' '); if (p_tmp != NULL) { cmd = malloc(sizeof(char) * (1+p_tmp-argv[1])); assert(cmd != NULL); memcpy(cmd, argv[1], p_tmp-argv[1]); cmd[p_tmp-argv[1]] = '\0'; } else { cmd = malloc(sizeof(char) * (1+strlen(argv[1]))); assert(cmd != NULL); strcpy(cmd, argv[1]); } if ((cmd[0] == '$') &&(strchr(cmd, '/') == NULL)) { p_tmp = getenv(cmd+1); if (p_tmp != NULL) cmd = p_tmp; } /* Si la commande existe */ if ((which_cmd(cmd) == 0) || (strchr(cmd, '/') != NULL)) { size_cmd_final = 60+2*strlen(argv[1])+3*strlen(argv[0])+strlen(sudo_gui); cmd_final = malloc(sizeof(char) * size_cmd_final); assert(cmd_final != NULL); if(test_menu (menu_list, argv[0]) == 1) { menu_list = add_menu (menu_list, argv[0]); printf("\033[34mDestroyMenu \033[36m%s\n\033[37m", argv[0]); sprintf(cmd_final, "DestroyMenu %s", argv[0]); FvwmCommand(cmd_final); sprintf(cmd_final, "AddToMenu %s \"%%16x16/%s.png%%%s\" Title", argv[0], argv[0], argv[0]); FvwmCommand(cmd_final); } printf("\033[34mAdd \033[31m%s \033[37m-> \033[36m%s\033[37m\n", argv[1], argv[0]); sprintf(cmd_final, "AddToMenu %s \"%%32x32/%s.png%%%s\" Exec exec"\ , argv[0], cmd, argv[2]); int s = atoi(&argv[4][0]); int t = atoi(&argv[3][0]); if (s&&t) strcat(cmd_final, " sudo $[fvwm_term] -e"); else if(s&&!t) { strcat(cmd_final, " "); strcat(cmd_final, sudo_gui); } else if(!s&&t) strcat(cmd_final, " $[fvwm_term] -e"); strcat(cmd_final, " "); strcat(cmd_final, argv[1]); FvwmCommand(cmd_final); free(cmd_final); } for(i = 0; i < 5; i++) free(argv[i]); return make_appli(p+1, sudo_gui); } int make_popup(char *str) { char *argv[4]; int i = 0, j; char *p; p = strtok(str+1, ":"); while((p != NULL)) { argv[i] = malloc(sizeof(char) * (1+strlen(p))); assert(argv[i] != NULL); strcpy(argv[i], p); i++; p = strtok(NULL, ":"); } if(i != 4) { fprintf(stderr, "\033[31mErreur d'analyse sur le popup '"); for(j = 0; j < i; j++) { fprintf(stderr, "%s:", argv[j]); free(argv[j]); } fprintf(stderr, "\n\033[37m"); return -1; } char *cmd_final = malloc(sizeof(char) * (60+strlen(argv[0])+strlen(argv[1])+strlen(argv[2])+strlen(argv[3]))); assert(cmd_final != NULL); sprintf(cmd_final, "AddToMenu %s \"%%32x32/%s%%%s\" Popup %s", \ argv[0], argv[2], argv[3], argv[1]); printf("\033[34mAdd \033[34mPopup \033[36m%s \033[37m-> \033[36m%s\n\033[37m", \ argv[0], argv[1]); FvwmCommand(cmd_final); free(cmd_final); for(i = 0; i < 4; i++) free(argv[i]); return 0; } /* Cette fonction est * l'équivalent de la commande * shell which. Elle cherche * si str est un executable * dans $PATH. * Renvoie 0 si dans le PATH * 1 sinon */ int which_cmd(char *str) { /* On copie le PATH dans une variable locale */ char *contenu_path = NULL; contenu_path = malloc (sizeof(char) * (1+path_len)); assert(contenu_path != NULL); strcpy(contenu_path, PATH); char *nom_dossier = strtok(contenu_path, ":"); DIR *dossier; struct dirent *contenu_dossier; /* La boucle qui cherche l'executable dans le PATH */ while (nom_dossier != NULL) { if ((dossier = opendir(nom_dossier)) != NULL) { while ((contenu_dossier = readdir(dossier)) != NULL) if (!strcmp(contenu_dossier->d_name, str)) { free(contenu_path); return 0; } closedir(dossier); if (errno == EBADF) fprintf(stderr, "\033[31mérreur de fermeture du repertoire %s\n\033[37m", nom_dossier); } nom_dossier = strtok(NULL, ":"); } /* Si on est arrivé jusqu'ici, c'est qu'on a rien trouvé */ free(contenu_path); return 1; } /* La fonction d'ajout à la liste chainée des menus */ llist add_menu(llist liste, char *name) { liste_menus* new = malloc(sizeof(liste_menus)); new->name = malloc(sizeof(char) * (1+strlen(name))); strcpy(new->name, name); new->next = liste; return new; } int test_menu(llist liste, char *name) { liste_menus *tmp = liste; while(tmp != NULL) { if (!strcmp(tmp->name, name)) return 0; tmp = tmp->next; } return 1; } void free_liste(llist liste) { liste_menus *tmp = liste; while(tmp != NULL) { free(tmp->name); tmp = tmp->next; } return; } int FvwmCommand(char *cmd) { #ifdef DEBUG printf("%s\n", cmd); #endif pid_t pid; char *argv[] = {"FvwmCommand", cmd, NULL}; pid = fork(); if (pid == 0) { execvp("FvwmCommand", argv); exit(1); } else if(pid != -1) wait(NULL); else perror("Impossible de créer le fork()\n"); return 0; }