From c2b219f7a0381d9a88b2806265d2ca20000ce015 Mon Sep 17 00:00:00 2001 From: Pierre Valarcher Date: Wed, 29 Sep 2021 11:31:40 +0200 Subject: [PATCH] =?UTF-8?q?mise=20=C3=A0=20jour?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ASR31-Cours4.md | 160 +++++++++++++++++++++++++++++ Exemples/04-Exec/apresExec.c | 23 +++++ Exemples/04-Exec/avantExec.c | 22 ++++ Exemples/04-Exec/recouvrante.c | 18 ++++ Exemples/04-Exec/recouvre1.c | 16 +++ Exemples/04-Exec/recouvre2.c | 15 +++ Exemples/04-Exec/recouvrement_ls.c | 13 +++ Exemples/04-Exec/shellex.c | 99 ++++++++++++++++++ concurr.c => Exemples/concurr.c | 0 9 files changed, 366 insertions(+) create mode 100644 ASR31-Cours4.md create mode 100644 Exemples/04-Exec/apresExec.c create mode 100644 Exemples/04-Exec/avantExec.c create mode 100644 Exemples/04-Exec/recouvrante.c create mode 100644 Exemples/04-Exec/recouvre1.c create mode 100644 Exemples/04-Exec/recouvre2.c create mode 100644 Exemples/04-Exec/recouvrement_ls.c create mode 100644 Exemples/04-Exec/shellex.c rename concurr.c => Exemples/concurr.c (100%) diff --git a/ASR31-Cours4.md b/ASR31-Cours4.md new file mode 100644 index 0000000..cb1f70b --- /dev/null +++ b/ASR31-Cours4.md @@ -0,0 +1,160 @@ +# Cours 3 +La création de processus via la commande ```fork``` est intéressante mais son utilisation +est limitée. Le système fourni un compagnon à ```fork``` l'appel système ```exec```. Son rôle est +de permettre à un processus de _changer son code_ (recouvrir). On parle souvent des appels ```fork/exec```. + +## La famille ```exec``` +Il existe six primitives de préfixe commun ```exec``` qui se différencient : + +- par la manière dont les arguments récupérés via l’argument ```argv``` sont transmis. + + - soit directement sous forme d’un tableau ou vecteur (d’où le ```v```) contenant +les différents paramètres. Il s’agit des primitives ```execv```, ```execvp``` et ```execve``` qui ont un nombre fixe de paramètres ; + + - soit sous forme d’une liste (d’où le ```l```) ```arg0, arg1, ..., argn, NULL``` dans +les primitives ```execl```, ```execlp``` et ```execle``` qui ont ainsi un nombre variable de paramètres ; +- par la manière dont le fichier à charger est recherché dans le système de fichiers : + - avec ```execlp``` et ```execvp``` le fichier est recherché dans les répertoires spécifiés via la variable ```PATH``` de l’environnement (et dans l’ordre d’apparition) ; + - avec les autres primitives, le fichier, s’il n’est pas désigné par une référence absolue, n’est recherché que relativement au répertoire de travail du processus appelant ; +- par l’environnement conservé par le processus au cours du recouvrement : + - avec les primitives ```execve``` et ```execle``` un nouvel environnement transmis en +paramètre se substitue à l’ancien ; + - avec les autres primitives, l’environnement reste inchangé. + +Le code de retour peut-être $-1$ en cas d'erreur. + +### Description + +```c +int execl (const char *reference, const char *arg0, ..., NULL); +``` + +Le fichier de ```reference``` absolue ou relative (au répertoire de travail du processus) donnée est chargé et la fonction ```main``` correspondante est appelée avec les paramètres de la liste constituée par les autres paramètres. Le paramètre ```arg0``` est récupéré dans la fonction ```main``` dans ```argv[0]```. + +#### Par exemple + +```c +execl("/bin/ls", "ls", "-l", "/", NULL) +``` +correspond à ```ls -l /```. + + +```c +int execlp (const char *reference, const char *arg0, ..., NULL); +``` + +se comporte comme la précédente sauf que si la ```reference``` est relative la recherche de la référence se fait dasn les répertoires spécifiés dans la varaible ```PATH``` de votre environnement. + +```c +int execle (const char *reference, const char *arg0, ..., NULL, const char **arge); +``` + +même comportement que ```execl``` mais le dernier paramètre pointe sur un environnement à substituer à l'ancien. Un environnement est constitué d'un ensemble de pointeurs sur des chaines de la forme *nom=valeur* (la fin de la liste est marquée par le pointeur ```NULL```). + +#### Exemple + +```c +#include +#include + +extern char **environ; + +int main(int argc, char *argv[]) { + int ind; + char **ptr; + + for (ind = 0; ind < argc; ind++) printf("%s\n", argv[ind]); + + ptr = environ; + + while (*ptr != NULL) printf("%s\n", *ptr++); + + return EXIT_SUCCESS; +} +``` + +Dont voici une exécution : + +```sh +bash-4.4$ ./recouvrante a s d f fg g=8 +./recouvrante +a +s +d +f +fg +g=8 +CONDA_SHLVL=1 +CONDA_EXE=/anaconda3/bin/conda +LANG=fr_FR.UTF-8 +XPC_FLAGS=0x0 +DISPLAY=/private/tmp/com.apple.launchd.3687PRnHur/org.macosforge.xquartz:0 +TERM_SESSION_ID=03974C81-0A61-46AD-80DE-7F8E93D00974 +CONDA_PREFIX=/anaconda3 +SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.VXQ8jzyBiw/Listeners +USER=pvalarcher +PWD=/Users/pvalarcher/git/ASR31/notes_de_cours/Cours3 +HOME=/Users/pvalarcher +CONDA_PYTHON_EXE=/anaconda3/bin/python +TERM_PROGRAM=Apple_Terminal +TERM_PROGRAM_VERSION=421.2 +Apple_PubSub_Socket_Render=/private/tmp/com.apple.launchd.MVmgyBLeD8/Render +TMPDIR=/var/folders/fz/3908mpd559x0cywbp_kvkhx00000gn/T/ +CONDA_PROMPT_MODIFIER= +XPC_SERVICE_NAME=0 +TERM=xterm-256color +SHELL=/bin/bash +SECURITYSESSIONID=186aa +SHLVL=2 +LOGNAME=pvalarcher +PATH=/anaconda3/bin:/Library/Frameworks/Python.framework/Versions/3.7/bin:/Users/pvalarcher/anaconda/bin:/opt/local/bin:/opt/local/sbin:/opt/local/bin:/opt/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/TeX/texbin:/opt/X11/bin +CONDA_DEFAULT_ENV=base +_=./recouvrante +OLDPWD=/Users/pvalarcher/git/ASR31/notes_de_cours +bash-4.4$ +``` + + +```c +int execv(const char *reference, const char *argv[]); +``` + +charge ```reference``` et appelle ```main``` avec les paramètres ```argc``` et ```argv```. + + +#### Exemple + +```c +#include +#include +#define NMAX 5 +main() { + char *argv[NMAX]; /* NMAX > 3 */ + + argv[0] = "ls"; argv[1] = "-l"; argv[2]="/"; argv[3]=NULL; + + execv("/bin/ls", argv); + perror("execv"); +} +``` + + +#### Exercice +Montrer que ```argc``` contient bien la bonne valeur. + + + +```c +int execvp(const char *reference, const char *argv[]); +``` +comme ```execv``` mais avec recherche dans le cas ou ```reference``` est relative dans ```PATH```. + +```c +int execvp(const char *reference, const char *argv[], const char **arge); +``` + +comme ```execv``` mais avec installation d'un nouvel environnement. + +On peut modifier des attributs du processus après recouvrement. + + diff --git a/Exemples/04-Exec/apresExec.c b/Exemples/04-Exec/apresExec.c new file mode 100644 index 0000000..ed0b3f4 --- /dev/null +++ b/Exemples/04-Exec/apresExec.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include + +char tabRef[1000]; +int nbLu; +char c; + +int main(void) { + printf("Caractéristiques après recouvrement\n"); + printf(" => Identité du processus:%d\n",getpid()); + printf(" => Identité du processus père:%d\n",getppid()); + printf(" => Propriétaire réel : %d\n", getuid()); + printf(" => Propriétaire effectif : %d\n", geteuid()); + printf(" => Répertoire de travail:%s\n",getcwd(tabRef,1000)); + + if ((nbLu = read(STDIN_FILENO,&c,1)) == -1) + perror(" read"); + else + printf(" Valeur du read : %d\n", nbLu); + return EXIT_SUCCESS; +} diff --git a/Exemples/04-Exec/avantExec.c b/Exemples/04-Exec/avantExec.c new file mode 100644 index 0000000..da0269f --- /dev/null +++ b/Exemples/04-Exec/avantExec.c @@ -0,0 +1,22 @@ +#include +#include +#include + +char tabRef[1000]; + +main() { + printf("Caractéristiques avant recouvrement\n"); + printf(" Identité du processus : %d\n", getpid()); + printf(" Identité du processus père:%d\n",getppid()); + printf(" Propriétaire réel : %d\n", getuid()); + printf(" Propriétaire effectif : %d\n", geteuid()); + printf(" Répertoire de travail:%s\n",getcwd(tabRef,1000)); +/* demande de fermeture automatique de l’entrée standard au recouvrement */ + + fcntl(STDIN_FILENO, F_SETFD, fcntl(STDIN_FILENO,F_GETFD,0)|FD_CLOEXEC); + + execl("apresExec", "apresExec", NULL); + + perror("execl"); + +} diff --git a/Exemples/04-Exec/recouvrante.c b/Exemples/04-Exec/recouvrante.c new file mode 100644 index 0000000..436b2b3 --- /dev/null +++ b/Exemples/04-Exec/recouvrante.c @@ -0,0 +1,18 @@ +#include +#include + +extern char **environ; + +int main(int argc, char *argv[]) { + int ind; + char **ptr; + + for (ind = 0; ind < argc; ind++) + printf("%s\n", argv[ind]); + ptr = environ; + + while (*ptr != NULL) + printf("%s\n", *ptr++); + + return EXIT_SUCCESS; +} diff --git a/Exemples/04-Exec/recouvre1.c b/Exemples/04-Exec/recouvre1.c new file mode 100644 index 0000000..f64cb2b --- /dev/null +++ b/Exemples/04-Exec/recouvre1.c @@ -0,0 +1,16 @@ +/* binaire : recouvre1 */ +#include +#include +#include + +char *envp[3]; + +int main() { + envp[0] = "X=AAAAA"; envp[1] = "Y=BBB"; envp[2] = NULL; + + execl( "recouvrante", "recouvrante", "/tmp/ddd", NULL, envp); + + + perror("execl"); + return EXIT_FAILURE; +} diff --git a/Exemples/04-Exec/recouvre2.c b/Exemples/04-Exec/recouvre2.c new file mode 100644 index 0000000..e9535c0 --- /dev/null +++ b/Exemples/04-Exec/recouvre2.c @@ -0,0 +1,15 @@ +/* binaire : recouvre2 */ +#include +#include +#include + +char *envp[3]; + +int main() { + envp[0] = "X=AAAAA"; envp[1] = "Y=BBB"; envp[2] = NULL; + + execle( "recouvrante", "recouvrante", "/tmp/ddd", NULL, envp); + + perror("execle"); + return EXIT_FAILURE; +} diff --git a/Exemples/04-Exec/recouvrement_ls.c b/Exemples/04-Exec/recouvrement_ls.c new file mode 100644 index 0000000..c7d9f4d --- /dev/null +++ b/Exemples/04-Exec/recouvrement_ls.c @@ -0,0 +1,13 @@ +#include +#include + +#define NMAX 5 + +main() { + char *argv[NMAX]; /* NMAX > 3 */ + + argv[0] = "ls"; argv[1] = "-l"; argv[2]="/"; argv[3]=NULL; + + execv("/bin/ls", argv); + perror("execv"); +} diff --git a/Exemples/04-Exec/shellex.c b/Exemples/04-Exec/shellex.c new file mode 100644 index 0000000..4ab51ae --- /dev/null +++ b/Exemples/04-Exec/shellex.c @@ -0,0 +1,99 @@ +#include +#include +#include +#include +#include +#include + +#define MAXARGS 128 +#define MAXLINE 80 +#define FOREVER while(1) + +extern char **environ; + +void eval(char *cmdline); +int parseline(char *buf, char **argv); +int builtin_cmd(char **argv); + +int main() { + char cmdline[MAXLINE]; + + FOREVER { + printf("> "); + fgets(cmdline, MAXLINE, stdin); + if (feof(stdin)) exit(0); + + eval(cmdline); + } + return EXIT_SUCCESS; +} + + +void eval(char *cmdline) { + char *argv[MAXARGS]; + char buf[MAXLINE]; + int bg; + pid_t pid; + + strcpy(buf, cmdline); + bg = parseline(buf, argv); + if (argv[0] == NULL) { + return; + } + + if (!builtin_cmd(argv)) { + if ((pid = fork()) == 0) { + if (execvp(argv[0], argv) < 0) { + printf("%s: cette commande n'existe pas.\n", argv[0]); + exit(0); + } + } + + if (!bg) { + int status; + if (waitpid(pid, &status, 0) < 0) { + perror("waitfg: waitpid error"); exit(0); + } + } + else { + printf("%d %s", pid, cmdline); + } + } + return; +} + +int builtin_cmd(char **argv) { + if (!strcmp(argv[0], "quit")) + exit(0); + if (!strcmp(argv[0], "&")) + return 1; + return 0; +} + +int parseline(char *buf, char **argv) { + char *delim; + int argc; + int bg; + + buf[strlen(buf)-1] = ' '; + while (*buf && (*buf == ' ')) { + buf++; + } + + argc = 0; + while ((delim = strchr(buf, ' '))) { + argv[argc++] = buf; + *delim = '\0'; + buf = delim+1; + while (*buf && (*buf == ' ')) buf++; + } + argv[argc] = NULL; + + if (argc == 0) return 1; + + if ((bg = (*argv[argc-1] == '&')) != 0) { + argv[--argc] = NULL; + } + + return bg; +} \ No newline at end of file diff --git a/concurr.c b/Exemples/concurr.c similarity index 100% rename from concurr.c rename to Exemples/concurr.c