#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static void close_pipe(int pipefds[2])
{
	close(pipefds[1]);
	close(pipefds[0]);
}

int main(int argc, char **argv)
{
	// set up pipes for the standard in and error streams of the `sudo -S` sub-process
	// `sudo -S` will print the password prompt to its standard error stream and read the password from its standard in
	int in_pipefds[2], err_pipefds[2];
	if (pipe(in_pipefds) == -1) {
		return EXIT_FAILURE;
	}

	if (pipe(err_pipefds) == -1) {
		close_pipe(in_pipefds);
		return EXIT_FAILURE;
	}

	pid_t child_pid = fork();
	
	if (child_pid < 0) {
		close_pipe(err_pipefds);
		close_pipe(in_pipefds);
		return EXIT_FAILURE;
	}
	else if (child_pid == 0) { // code for child
		close(in_pipefds[1]);
		close(err_pipefds[0]);
		
		int fd = dup2(in_pipefds[0], STDIN_FILENO);
		if (fd == -1) {
			_exit(EXIT_FAILURE);
		}
		in_pipefds[0] = fd;

		fd = dup2(err_pipefds[1], STDERR_FILENO);
		if (fd == -1) {
			_exit(EXIT_FAILURE);
		}
		err_pipefds[1] = fd;

		if (setsid() == -1) // this is important. Otherwise, `sudo` will still print the prompt to `/dev/tty`.
			_exit(EXIT_FAILURE);
		
		execlp("sudo", "-S", "-p", "MY PASSWORD: \n" /* the newline is important */, "--", "wronly", "TEST.txt", (char*)NULL);
		_exit(EXIT_FAILURE);
	}
	else { // code for parent
		close(in_pipefds[0]);
		close(err_pipefds[1]);
		
		char prompt[1024] = {'\0'};
		FILE *child_stderr = fdopen(err_pipefds[0], "rb");
		if (NULL == fgets(prompt, 1024, child_stderr)) {
			// `sudo` did not require a password
			printf("`sudo` did not require a password.\n");
		}
		
		FILE *child_stdin = fdopen(in_pipefds[1], "wb");
		if (*prompt != '\0') {
			char *p = strrchr(prompt, '\n');
			assert(p != NULL);
			*p = '\0'; // trim the trailing newline
			char *pass = getpass(prompt);
			fputs(pass, child_stdin);
			fputc('\n', child_stdin);
		}
		
		fputc('a', child_stdin);
		fputc('b', child_stdin);
		fputc('c', child_stdin);
		fclose(child_stdin);
		
		int stat;
		waitpid(child_pid, &stat, 0);
	}
	
	return EXIT_SUCCESS;
}

