Ejemplo n.º 1
0
/*
 * Executes a shell command entered by the user
 * 
 * Parameters:
 *   argc - number of arguments in the command
 *   argv - the user's command
 *   mods - special modifiers for the command
 *
 * Returns:
 *   0 on success, -1 otherwise
 */
int execute_cmd(size_t argc, char *const argv[], const mods_t *const mods)
{
  // Builtin command received
  if (is_builtin(argv[0]))
    return execute_builtin(argc, argv, mods);

  // Non builtin command received
  int ret = fork();
  if (ret == -1)
  {
    // fork() failed in the parent
    perror("ERROR: fork():");
  }
  else if (ret == 0)
  {
    // Child code
    printf("[%d] %s\n", getpid(), argv[0]);
    if (mods->out_file != NULL && redirect_stdout(mods->out_file) == -1)
      return -1;
    execvp(argv[0], argv);
    printf("ERROR: Cannot exec '%s'\n", argv[0]);
    return -1;
  } 
  else 
  {
    // Parent code
    if (mods->bg == 0)
      check_child_status(ret, 0);
  }

  return 0;
}
Ejemplo n.º 2
0
/* Arguements:
   -(struct node*): The List of Commands
   Returns (void)
*/
void run_commands(struct node* commands)
{
  while (commands)
  {
    char **array = 0;
    struct node* list = 0;

    // Redirect append
    if ( strstr( commands->data, ">>" ) )
    {
      array = split_on_append(commands->data);
      redirect_append(array);
    }
    // Redirect stdout
    else if ( strstr( commands->data, ">" ) )
    {
      array = split_on_stdout(commands->data);
      redirect_stdout(array);
    }
    // Redirect stdin
    else if ( strstr( commands->data, "<" ) )
    {
      array = split_on_stdin(commands->data);
      redirect_stdin(array);
    }
    // Pipe
    else if ( strstr( commands->data, "|" ) )
    {
      list = split_on_pipe(commands->data);
      redirect_pipe(list);
    }
    // Normal Execution
    else
    {
      array = arguementify(commands->data);
      execute_command(array);
    }

    // Cleanup
    free_list(list);
    free_string_array(array);

    // Continue
    commands = commands->next;
  }
}
Ejemplo n.º 3
0
void redirect_m(int numb_of_params, char* params[]) {
	char * commands[COMMAND_COUNT];
	PARAMS=params;
	N_params=numb_of_params;
	int pars_res = parse(numb_of_params, params, commands);
	if (pars_res != 0) {
		printf("error parsing 'redirect' comand.\n");
		return;
	}
// ---------------------------------------------------------
	if (strcmp(commands[1], ">") == 0 || strcmp(commands[1], ">>") == 0) {
		redirect_stdout(commands[0], commands[1], commands[2]);
	} else {
		if (strcmp(commands[1], "<") == 0 && strcmp(commands[3], "\0") == 0) {
			redirect_stdin(commands[0], commands[1], commands[2]);
		} else if (strcmp(commands[1], "<") == 0 && (strcmp(commands[3], ">") == 0 || strcmp(commands[3], ">>") == 0)) {
			redirect_stdin_stdout(commands[0], commands[1], commands[2], commands[3], commands[4]);
		}
	}
} 
int main(int argc, char **argv)
{
   int status;
   int nrx_fd;
   int host_rfd;
   int host_wfd;
   int use_stdin = 0;
   char * ser_dev = NULL;
   int port = 12345;
   char * filename = default_filename;
   void * handle = NULL;
   int host_flash = 0;
   int input_baudrate = 115200;
   speed_t baudrate = B115200;
   int opt;

   struct ifreq ifr;
   struct nanoioctl nr;
   
   while((opt = getopt(argc, argv, "d:s:p:f:b:i")) != -1) {
      switch(opt) {
         case 'b':
            input_baudrate = atoi(optarg);
            switch(input_baudrate) {
               case 9600: baudrate = B9600; break;
               case 19200: baudrate = B19200; break;
               case 38400: baudrate = B38400; break;
               case 57600: baudrate = B57600; break;
               case 115200: baudrate = B115200; break;
               default: usage();
            }
            break;
         case 'd':
            debug = atoi(optarg);
            break;
         case 'f':
            filename = optarg;
            break;
         case 'i':
            use_stdin = 1;
            break;
         case 'p':
            port = atoi(optarg);
            break;
         case 's':
            ser_dev = optarg;
            break;
         default:
            break;
      }
   }
   if(optind == argc)
      usage();

   strcpy(ifr.ifr_name, argv[optind]);
   ifr.ifr_data = (char *)&nr;
   memset(&nr,0,sizeof(nr));
   nr.magic = NR_MAGIC;

   APP_INFO("Nanoradio network interface: %s\n", ifr.ifr_name);
   APP_INFO("Saving persistent MIB data of type HOST to: %s\n", filename);

   if(use_stdin) {
      APP_INFO("Using stdin/stdout as client interface\n");
      host_wfd = host_rfd = open_terminal();
      redirect_stdout("/tmp/hic_proxy.log");
   } else if(ser_dev) 
      {
	APP_INFO("Using %s (baudrate = %d) as serial client interface\n", ser_dev,input_baudrate);
	host_wfd = host_rfd = open_serial(ser_dev, baudrate);
      }
   else 
      {
         APP_INFO("Using ethernet as client interface\n");
         host_wfd = host_rfd = open_socket(port);
      }
    
   nrx_fd = socket(AF_INET, SOCK_DGRAM, 0);
   if(nrx_fd < 0) err(1, "socket");

   for(;;) {      
      status = poll_host(host_rfd, &ifr);
      if(status) {
	
         
         if((nr.data[TYPE_INDEX] ==  HIC_MESSAGE_TYPE_FLASH_PRG))
            {
               APP_DEBUG("flash cmd recieved\n");

               //examine flash cmd
               handle = flash_cmd(&ifr,handle,filename);
 
               if(handle)
                  {
                     //send local host flash cmd reply
                     host_write(host_wfd, nr.data, nr.length);
                  }
               else
                  {
                     //forward to target
                     nrx_write(nrx_fd, &ifr);
                  }
            }
         else
            {
               //forward to target
               nrx_write(nrx_fd, &ifr);
            }
      }
	
      status = poll_target(nrx_fd, &ifr);
  
      if(status)
         host_write(host_wfd, nr.data, nr.length);

      usleep(5000);
   }

   if(!use_stdin) {
      close(host_rfd);
   }
   close(nrx_fd);
}
Ejemplo n.º 5
0
Archivo: wat.c Proyecto: jkoz/wat
int
main(int argc, const char **argv){
	if (1 == argc) usage();
	int interval = DEFAULT_INTERVAL;

	int len = 0;
	int interpret = 1;
	char *args[ARGS_MAX] = {0};

	for (int i = 1; i < argc; ++i) {
		const char *arg = argv[i];
		if (!interpret) goto arg;

		// -h, --help
		if (option("-h", "--help", arg)) usage();

		// -q, --quiet
		if (option("-q", "--quiet", arg)) {
			quiet = 1;
			continue;
		}

		// -x, --halt
		if (option("-x", "--halt", arg)) {
			halt = 1;
			continue;
		}

		// -v, --version
		if (option("-v", "--version", arg)) {
			printf("%s\n", VERSION);
			exit(1);
		}

		// -i, --interval <n>
		if (option("-i", "--interval", arg)) {
			if (argc-1 == i) {
				fprintf(stderr, "\n  --interval requires an argument\n\n");
				exit(1);
			}

			arg = argv[++i];
			char last = arg[strlen(arg) - 1];
			// seconds or milliseconds
			interval = last >= 'a' && last <= 'z'
				? string_to_milliseconds(arg)
				: atoi(arg) * 1000;
			continue;
		}

		// cmd args
		if (len == ARGS_MAX) {
			fprintf(stderr, "number of arguments exceeded %d\n", len);
			exit(1);
		}

	arg:
		args[len++] = (char *) arg;
		interpret = 0;
	}

	// <cmd>
	if (!len) {
		fprintf(stderr, "\n  <cmd> required\n\n");
		exit(1);
	}

	// cmd
	char *val = join(args, len, " ");
	char *cmd[4] = { "sh", "-c", val, 0 };

	// exec loop
	loop: {
		  pid_t pid;
		  int status;
		  switch (pid = fork()) {
			  // error
			  case -1:
				  perror("fork()");
				  exit(1);
				  // child
			  case 0:
				  if (quiet) redirect_stdout("/dev/null");
				  execvp(cmd[0], cmd);
				  // parent
			  default:
				  if (waitpid(pid, &status, 0) < 0) {
					  perror("waitpid()");
					  exit(1);
				  }

				  // exit > 0
				  if (WEXITSTATUS(status)) {
					  fprintf(stderr, "\033[90mexit: %d\33[0m\n\n", WEXITSTATUS(status));
					  if (halt) exit(WEXITSTATUS(status));
				  }

				  mssleep(interval);
				  goto loop;
		  }
	  }

	  return 0;
}
Ejemplo n.º 6
0
/*
 * Executes a builtin shell command
 * 
 * Parameters:
 *   argc - number of arguments in the command
 *   argv - the user's command
 *   mods - special modifiers for the command
 *
 * Returns:
 *   0 on success, -1 otherwise
 */
int execute_builtin(size_t argc, char *const argv[], const mods_t *const mods)
{
  // Handle file redirection
  int fd;
  if (mods->out_file != NULL && (fd = redirect_stdout(mods->out_file)) == -1)
    return -1;

  // HELP
  if (strcmp(argv[0], "help") == 0)
  {
    print_help();
  }
  // EXIT
  else if (strcmp(argv[0], "exit") == 0)
  {
    return -1;
  }
  // PID
  else if (strcmp(argv[0], "pid") == 0)
  {
    printf("[%d] shell\n", getpid());	
  }
  // PPID
  else if (strcmp(argv[0], "ppid") == 0)
  {
    printf("[%d] parent\n", getppid());
  } 
  // PWD
  else if (strcmp(argv[0], "pwd") == 0)
  {
    char dir[PATH_MAX];
    if (getcwd(dir, sizeof(dir)) == NULL)
      perror("ERROR: getcwd():");	
    else
      printf("%s\n", dir);
  }
  // CD
  else if (strcmp(argv[0], "cd") == 0)
  {
    int err = 0;
    if (argc > 1) 
      err = chdir(argv[1]); 
    else 
      err = chdir(getenv("HOME"));
    if (err != 0)
      perror("ERROR: chdir():");
  }
  // GET
  else if (strcmp(argv[0], "get") == 0)
  {
    if (argc > 1)
    {
      char *var = getenv(argv[1]);
      if (var == NULL) 
        printf("ERROR: Unknown variable '%s'.\n", argv[1]);
      else 
        printf("%s\n", var); 
    }
    else
      printf("Usage: get <var>.\n");
  }
  // SET
  else if (strcmp(argv[0], "set") == 0)
  {
    if (argc == 1)
      printf("Usage: set <var> <value>\n"); 
    else if (argc == 2 && unsetenv(argv[1]) == -1)
      perror("ERROR: unsetenv():");
    else if (setenv(argv[1], argv[2], 1) == -1)
      perror("ERROR: setenv():");
  }

  // Revert file redirection
  if (mods->out_file != NULL && restore_stdout(fd) == -1)
    return -1;

  return 0;
}
Ejemplo n.º 7
0
int tardiffmerge(int argc, char *argv[], char *flags)
{
    int n, num_diffs;
    struct File *files, *file;
    bool input_ok, output_ok, order_files;

    num_diffs = argc - 1;
    input_ok = output_ok = false;
    order_files = (strchr(flags, 'f') == NULL);

    /* Verify arguments are all diff files: */
    input_ok = identify_files((const char**)argv, num_diffs, NULL, &files);
    for (file = files; file != NULL; file = file->next)
    {
        if (file->type == FILE_INVALID)
        {
            fprintf(stderr, "%s: %s\n", file->path, file->invalid.error);
        }
        else
        if (file->type != FILE_DIFF)
        {
            fprintf(stderr, "%s: not a differences file\n", file->path);
            input_ok = false;
        }
        else  /* file->type == FILE_DIFF */
        {
            static uint8_t zero_digest[DS];
            if (order_files &&
                memcmp(file->diff.digest1, zero_digest, DS) == 0)
            {
                fprintf(stderr, "Input contains version 1.0 difference files; "
                                "merge order cannot be determined.\n");
                input_ok = false;
            }
        }
    }

    if (input_ok && order_files)
    {
        mark_usable(files);
        if (!order_input(&files))
        {
            fprintf(stderr, "Input files could not be ordered!\n");
            input_ok = false;
        }
    }

    if (input_ok)
    {
        /* Redirect output (if necessary) */
        if (strcmp(argv[argc - 1], "-") != 0) redirect_stdout(argv[argc - 1]);

        n = 0;
        for (file = files; file != NULL; file = file->next)
        {
            InputStream *is;
            char magic[MAGIC_LEN];

            /* Try to open again */
            is = OpenFileInputStream(file->path);
            if (is == NULL)
            {
                fprintf(stderr, "%s: could not be opened.\n", file->path);
                break;
            }

            /* Save pointer here, so we can close it later. */
            is_diff[n++] = is;

            /* Verify magic again */
            read_data(is, magic, MAGIC_LEN);
            if (memcmp(magic, MAGIC_STR, MAGIC_LEN) != 0)
            {
                fprintf(stderr, "%s: not a differences file\n", file->path);
                break;
            }

            /* Process entire file */
            process_input(is);
        }

        if (file == NULL)
        {
            output_ok = generate_output();
        }

        /* Close open streams: */
        while (n-- > 0) is_diff[n]->close(is_diff[n]);

        munmap(last_blocks, last_num_blocks*sizeof(BlockRef));
    }
    free_files(files);

    return (input_ok && output_ok) ? EXIT_SUCCESS : EXIT_FAILURE;
}
Ejemplo n.º 8
0
/*===================================================
=				Programa principal        			=
===================================================*/
int main()
{
	char* argumentos[MAX_ARGS];		//	Argumentos dos executáveis
	char buffer[BUFFER_SIZE];		//	Buffer que guarda os dados da leitura do pipe
	int input;		 				// 	Descritor de ficheiro para o pipe que recebe input dos terminais
	/**
	 * 	Inicializar as variáveis e estruturas da par-shell
	 */
	initialize_variables();	
	/**
	 * 	Atualizar as informações do log da par-shell
	 */
	update_log_values();
	/**
	 * 	Catch do signal ctrl+c
	 */
	if(signal(SIGINT, sig_handler) == SIG_ERR){
		perror("Erro no signal: ");
	}

    while(1){
    	/**
    	 * 	Abrir o pipe que recebe input dos terminais
    	 */
    	if((inputdesc = open(inputpipe,O_RDONLY)) < 0){
    		perror("Erro no open do pipe: ");
    		exit(EXIT_FAILURE);
    	} 
    	/**
    	 * 	Ler informações do pipe
    	 */
    	if((input = read(inputdesc,buffer,BUFFER_SIZE)) <= 0){
    		//	Fechar o pipe apos a leitura
    		close(inputdesc);
    		//	Não lê nada mas tambem não dá erro, continua o ciclo (e.g press enter) 
    		if(input == 0){
    			continue;
    		}
    		perror("Erro no read do input");
    	}
    	else{
    		buffer[input] = '\0';
			if(strcmp(buffer,"exit-global") == 0) {
				/**
				 * 	Sair da par-shell
				 */
				exit_par_shell();
			}
			
			if (sscanf(buffer, "/tmp/terminal-%d", &pidterminal) > 0) {
				/**
				 *	Registar um terminal especifico e o seu pipe
				 */
				printf("Terminal %d criado\n",pidterminal);
				if(fflush(stdout) < 0)
				    perror("Erro no fflush de escrita no par-shell na criação de terminal: ");
				//	Inserir pid do terminal na lista de terminais
				insert_new_terminal(lista_terminais,pidterminal);  
				continue;
			}
			
			if(sscanf(buffer,"stats %d",&pidterminal) > 0){
				/**
				 * 	Enviar o número de processos filhos em execução e 
				 *  o tempo total de execução da par-shell para o terminal
				 */
				//	Construir strings de output e do nome do pipe do terminal
				sprintf(output,"Número de filhos em execução: %d \nTempo total: %g",nfilhos,tempo_total_execucao);
				sprintf(terminalpipe,"/tmp/terminal-%d",pidterminal);
				//	Abrir o pipe do terminal para escrita
				if((fd_write = open(terminalpipe, O_WRONLY)) < 0){
					perror("Erro no open do stats da par-shell: ");
					exit(EXIT_FAILURE); 
				}    
				//	Escrever no pipe do terminal             
				if(write(fd_write,output,strlen(output)) < 0){
					perror("Erro no write do stats da par-shell: ");
				}
				//	Fechar o pipe do terminal
				if(close(fd_write) < 0){
					perror("Erro no close do stats da par-shell: ");
				}
				strcpy(output,"\0");
				continue;
			}
			else {
				int i;		//	Inteiro temporário usado no ciclo de processamento dos argumentos 
				int pid;	//	Pid do processo filho criado com fork
				/**
				 * 	Processar todos os argumentos que poderá receber
				 */
				argumentos[0] = strtok(buffer," ");
				for(i = 1; i < MAX_ARGS; i++){ 
					argumentos[i] = strtok(NULL," ");
				}
				/**
				 * 	Confirmar se podem ser criados filhos
				 */
				mutex_lock();
				while (! (nfilhos < MAXPAR))
					if(pthread_cond_wait(&podeCriarFilhos,&mutex) != 0){
						perror("Erro no pthread_cond_wait na par-shell: ");
					}
				mutex_unlock();

				/**
				 * 	Criar processo filho usando fork
				 */
				pid = fork(); 					
				//	Registar tempo de inicio do processo filho
				time_t starttime = time(NULL);  
				if (pid < 0) {
					perror("Erro no fork: ");
					continue;
				}
				/**
				 * 	Código do processo filho
				 */
				if (pid == 0) {  		
					// 	Redirecionar o output do processo filho		
					redirect_stdout();
					// 	Evitar que o ctrl+c se propague para o processo filho -> signal é ignorado
					signal(SIGINT,SIG_IGN);
					//	Trocar código do processo filho pelo do executável	
					if(execv(argumentos[0], argumentos) < 0){
						perror("Erro no execv:");
						exit(EXIT_FAILURE);
					}
				}
				/**
				 * 	Código do processo pai
				 */
				mutex_lock();		
				nfilhos++;
				if(pthread_cond_signal(&podeMonitorizar) != 0){
					perror("Erro no pthread_cond_signal na par-shell: ");
				}
				insert_new_process(list,pid,starttime);
				mutex_unlock();
			}
		}	
	}
	return 0;
}
Ejemplo n.º 9
0
int tarpatch(int argc, char *argv[], const char *flags)
{
    InputStream *is_file1, *is_diff;
    void (*patch_func)(InputStream *, InputStream *, uint8_t[DS]);
    char magic_buf[MAGIC_LEN];
    uint8_t digest_expected[DS], digest_computed[DS];

    assert(MD5_DIGEST_LENGTH == DS);
    assert(argc == 3);

    /* Open file 1 */
    is_file1 = (strcmp(argv[0], "-") == 0) ? OpenStdinInputStream()
                                           : OpenFileInputStream(argv[0]);
    if (is_file1 == NULL)
    {
        fprintf(stderr, "Cannot open file 1 (%s) for reading!\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    /* Open diff file */
    is_diff  = (strcmp(argv[1], "-") == 0) ? OpenStdinInputStream()
                                           : OpenFileInputStream(argv[1]);
    if (is_diff == NULL)
    {
        fprintf(stderr, "Cannot open diff file (%s) for reading!\n", argv[1]);
        exit(EXIT_FAILURE);
    }

    /* Redirect output (if necessary) */
    if (strcmp(argv[2], "-") != 0) redirect_stdout(argv[2]);

    if (is_file1->seek(is_file1, 0))
        patch_func = patch_forward;
    else
    if (fseeko(stdout, 0, SEEK_SET) == 0)
        patch_func = patch_backward;
    else
    {
        fprintf(stderr, "Neither file 1 nor file 2 is seekable!\n");
        exit(EXIT_FAILURE);
    }

    /* Read and verify file magic number */
    if ( is_diff->read(is_diff, magic_buf, MAGIC_LEN) != MAGIC_LEN ||
         memcmp(magic_buf, MAGIC_STR, MAGIC_LEN) != 0 )
    {
        fprintf(stderr, "Not a diff file!\n");
        exit(EXIT_FAILURE);
    }

    patch_func(is_file1, is_diff, digest_computed);

    /* Read and compare output file digest */
    read_data(is_diff, digest_expected, DS);
    if (memcmp(digest_expected, digest_computed, DS) != 0)
    {
        char expected_str[2*DS + 1],
             computed_str[2*DS + 1];

        hexstring(expected_str, digest_expected, DS);
        hexstring(computed_str, digest_computed, DS);

        fprintf(stderr, "Output file verification failed!\n"
                        "Original file hash:  %s (expected)\n"
                        "New file hash:       %s (computed)\n",
                        expected_str, computed_str );
        exit(EXIT_FAILURE);
    }

    return EXIT_SUCCESS;
}
Ejemplo n.º 10
0
 bool redirect() {
   return redirect_stdout(out_pipe_) && redirect_stdin(in_pipe_);
 }
Ejemplo n.º 11
0
 bool redirect() { return redirect_stdout(pipe_) != -1; }
Ejemplo n.º 12
0
int monitor(int argc, char *argv[])
{
    ty_board *board = NULL;
    int outfd = -1;
    int r;

    int c;
    while ((c = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
        switch (c) {
        HANDLE_COMMON_OPTIONS(c, print_monitor_usage);

        case 's':
            terminal_flags |= TY_TERMINAL_SILENT;
            break;
        case 'r':
            terminal_flags |= TY_TERMINAL_RAW;
            break;

        case 'D':
            if (strcmp(optarg, "input") == 0) {
                directions = DIRECTION_INPUT;
            } else if (strcmp(optarg, "output") == 0) {
                directions = DIRECTION_OUTPUT;
            } else if (strcmp(optarg, "both") == 0) {
                directions = DIRECTION_INPUT | DIRECTION_OUTPUT;
            } else {
                ty_log(TY_LOG_ERROR, "--direction must be one off input, output or both");
                print_monitor_usage(stderr);
                return EXIT_FAILURE;
            }
            break;

        case 'b':
            errno = 0;
            device_rate = (uint32_t)strtoul(optarg, NULL, 10);
            if (errno) {
                ty_log(TY_LOG_ERROR, "--baud requires a number");
                print_monitor_usage(stderr);
                return EXIT_FAILURE;
            }
            break;
        case 'd':
           device_flags &= ~HS_SERIAL_MASK_CSIZE;
            if (strcmp(optarg, "5") == 0) {
                device_flags |= HS_SERIAL_CSIZE_5BITS;
            } else if (strcmp(optarg, "6") == 0) {
                device_flags |= HS_SERIAL_CSIZE_6BITS;
            } else if (strcmp(optarg, "7") == 0) {
                device_flags |= HS_SERIAL_CSIZE_7BITS;
            } else if (strcmp(optarg, "8") != 0) {
                ty_log(TY_LOG_ERROR, "--databits must be one off 5, 6, 7 or 8");
                print_monitor_usage(stderr);
                return EXIT_FAILURE;
            }
        case 'f':
            device_flags &= ~HS_SERIAL_MASK_FLOW;
            if (strcmp(optarg, "x") == 0 || strcmp(optarg, "xonxoff") == 0) {
                device_flags |= HS_SERIAL_FLOW_XONXOFF;
            } else if (strcmp(optarg, "h") == 0 || strcmp(optarg, "rtscts") == 0) {
                device_flags |= HS_SERIAL_FLOW_RTSCTS;
            } else if (strcmp(optarg, "n") != 0 && strcmp(optarg, "none") == 0) {
                ty_log(TY_LOG_ERROR, "--flow must be one off x (xonxoff), h (rtscts) or n (none)");
                print_monitor_usage(stderr);
                return EXIT_FAILURE;
            }
            break;
        case MONITOR_OPTION_NORESET:
            device_flags |= HS_SERIAL_CLOSE_NOHUP;
            break;
        case 'p':
            device_flags &= ~HS_SERIAL_MASK_PARITY;
            if (strcmp(optarg, "o") == 0 || strcmp(optarg, "odd") == 0) {
                device_flags |= HS_SERIAL_PARITY_ODD;
            } else if (strcmp(optarg, "e") == 0 || strcmp(optarg, "even") == 0) {
                device_flags |= HS_SERIAL_PARITY_EVEN;
            } else if (strcmp(optarg, "n") != 0 && strcmp(optarg, "none") != 0) {
                ty_log(TY_LOG_ERROR, "--parity must be one off o (odd), e (even) or n (none)");
                print_monitor_usage(stderr);
                return EXIT_FAILURE;
            }
            break;

        case 'R':
            reconnect = true;
            break;

        case MONITOR_OPTION_TIMEOUT_EOF:
            errno = 0;
            timeout_eof = (int)strtol(optarg, NULL, 10);
            if (errno) {
                ty_log(TY_LOG_ERROR, "--timeout requires a number");
                print_monitor_usage(stderr);
                return EXIT_FAILURE;
            }
            if (timeout_eof < 0)
                timeout_eof = -1;
            break;
        }
    }

    if (argc > optind) {
        ty_log(TY_LOG_ERROR, "No positional argument is allowed");
        print_monitor_usage(stderr);
        return EXIT_FAILURE;
    }

    if (ty_standard_get_modes(TY_STANDARD_INPUT) & TY_DESCRIPTOR_MODE_TERMINAL) {
#ifdef _WIN32
        if (terminal_flags & TY_TERMINAL_RAW && !(terminal_flags & TY_TERMINAL_SILENT)) {
            terminal_flags |= TY_TERMINAL_SILENT;

            if (ty_standard_get_modes(TY_STANDARD_OUTPUT) & TY_DESCRIPTOR_MODE_TERMINAL)
                fake_echo = true;
        }

        /* Unlike POSIX platforms, Windows does not implement the console line editing behavior
         * at the tty layer. Instead, ReadFile() takes care of it and blocks until return is hit.
         * The problem is that the Wait functions will return the stdin descriptor as soon as
         * something is typed but then, ReadFile() will block until return is pressed.
         * Overlapped I/O cannot be used because it is not supported on console descriptors.
         *
         * So the best way I found is to have a background thread handle the blocking ReadFile()
         * and pass the lines in a buffer. When a new line is entered, the input_available
         * event is set to signal the poll in loop(). I also tried to use an anonymous pipe to
         * make it simpler, but the Wait functions do not support them. */
        if (directions & DIRECTION_OUTPUT && !(terminal_flags & TY_TERMINAL_RAW)) {
            r = start_stdin_thread();
            if (r < 0)
                goto cleanup;
        }
#endif

        r = ty_terminal_setup(terminal_flags);
        if (r < 0)
            goto cleanup;
    }

    r = redirect_stdout(&outfd);
    if (r < 0)
        goto cleanup;

    r = get_board(&board);
    if (r < 0)
        goto cleanup;

    r = loop(board, outfd);

cleanup:
#ifdef _WIN32
    stop_stdin_thread();
#endif
    ty_board_unref(board);
    return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}