/**
 * @file 2022-09-07
 * @author Alice Benatti (alice17bee@gmail.com)
 * @brief Prova pratica https://dynamik.vercel.app/sistemi-operativi/prove/pratica/scritto-2022-09-07-testo.pdf
 * @version 0.1
 * @date 2023-01-25
 * 
 * @copyright Copyright (c) 2023
 * 
 */
  
// Esercizio 0
// dalla tua directory e home personale
// chmod 700 ../../../public/alice.benatti4/


/* Esercizio 1 *
	Scrivere un programma C rilancia che esegua
	- il programma indicato in argv[1] con i relativi parametri in argv[2] e seguenti
		es: 	rilancia tr a-z A-Z 
			esegue il comando tr con i relativi parametri
	Se il programma lanciato termina senza errori (con valore 0 e non per colpa di un segnale) => rilancia deve rieseguire il programma con i medesimi parametri.
*/
/* include necessari */
#include <stdio.h>		/* printf */
#include <stdlib.h> 	/* exit */
#include <string.h> 	/* strlen, strcpy, */ 
#include <sys/types.h>
#include <sys/wait.h>	/* vedi: man wait */
typedef unsigned int pid_t;	/* pid */

int rilancia (int argc, char* argv[]){
	// devo avere almeno 2 argomenti
	if (argc < 2) {
		printf("ERROR: inserisci almeno 2 argomenti nel comando");
		exit(1);
	}
	pid_t pid;
	int wait_status;
	int return_value = 1;
	char* argo[argc];
	argo[argc - 1] = NULL;

	for (int i = 0; i < (argc - 1); i++) {
		argo[i] = malloc(sizeof(char)* strlen(argv[i + 1]));
		strcpy(argo[i], argv[i + 1]);
	}

	do {
		switch (pid = fork()) {
			case -1:
				exit(1);
				break;
			case 0:
				printf("Esecuzione da processo pid = %d\n", getpid());
				execvp(argo[0], argo);
				break;
			default:
				if (waitpid(pid, &wait_status, 0) == -1)
					exit(1);
				return_value = WEXITSTATUS(wait_status);
				break;
		}
	} while (return_value == 0 && !(WIFSIGNALED(wait_status)));

	printf("Process terminato con errore");
	for (int i = 0; i < argc - 1; i++) {
		free(argo[i]);
	}
	return 0;
}

/** Esercizio 2
 * Si esegue il programma dell'esercizio 1 con:
 * rilancia cat /etc/hostname
 * il comando cat viene eseeguito ripetuttamente all'infinito.
 * Modificare il programma rilancia per fare in modo che 
 * - se l'esecuzione del programma dura meno di un secondo => non si proceda alla riattivazione.
*/
# include <time.h> 	/* time, clock */

int rilancia2 (int argc, char* argv[]){
	// devo avere almeno 2 argomenti
	if (argc < 2) {
		printf("ERROR: inserisci almeno 2 argomenti nel comando");
		exit(1);
	}
	pid_t pid;
	int wait_status;
	int return_value = 1;
	char* argo[argc];
	argo[argc - 1] = NULL;
	clock_t start, end;		/* clock */
	double exec_time;		/* clock */

	for (int i = 0; i < (argc - 1); i++) {
		argo[i] = malloc(sizeof(char)* strlen(argv[i + 1]));
		strcpy(argo[i], argv[i + 1]);
	}

	do {
		switch (pid = fork()) {
			case -1:
				exit(1);
				break;
			case 0:
				printf("Esecuzione da processo pid = %d\n", getpid());
				start = clock();
				execvp(argo[0], argo);
				end = clock();
				exec_time = (double)(end - start) / CLOCKS_PER_SEC;
				if (exec_time < 1){
					printf("Esecuzione troppo breve, non si procede alla riattivazione");
					exit(0);
				}
				break;
			default:
				if (waitpid(pid, &wait_status, 0) == -1)
					exit(1);
				return_value = WEXITSTATUS(wait_status);
				break;
		}
	} while (return_value == 0 && !(WIFSIGNALED(wait_status)));
	if ((return_value != 0) || WIFSIGNALED(wait_status))
  		printf("Process terminato con errore");
	for (int i = 0; i < argc - 1; i++) {
		free(argo[i]);
	}
	return 0;
}