#define _POSIX_C_SOURCE 200809L #include "exec/ast_exec_redirs.h" #include #include #include #include #include #include #include #include #include "ast/ast.h" #include "ast/ast_accessors.h" #include "ast/ast_redirect.h" #include "utils/env.h" #include "utils/libstring.h" inline static long _get_open_max(void) { return sysconf(_SC_OPEN_MAX); } static bool _file_exists(char *filename) { struct stat s; return stat(filename, &s) == 0; } inline static bool _is_a_digit(char c) { return c >= '0' && c <= '9'; } static bool _is_a_number(struct string *s) { size_t i = 0; while (i < s->length && _is_a_digit(s->data[i])) { i++; } return i == s->length; } /** * @brief Assigns the fd described by s to out_fd if s * describes an integer which is less than _SC_OPEN_MAX. */ static void _assign_if_valid_int_fd(struct string *s, int *out_fd) { if (_is_a_number(s)) { int fd = atoi(s->data); if (fd < _get_open_max()) { *out_fd = fd; return; } } *out_fd = BAD_FD; } /** * @brief Assigns the fd described by s to out_fd if s * describes an integer which is less than _SC_OPEN_MAX. * s can also be exactly '-', in which case out_fd contains * the value CLOSE_FD. */ static void _assign_if_valid_fd_and(struct string *s, int *out_fd) { if (_is_a_number(s)) { int fd = atoi(s->data); int cpy_fd = dup(fd); *out_fd = cpy_fd; return; } if (s->length == 1 && s->data[0] == '-') { *out_fd = CLOSE_FD; return; } *out_fd = BAD_FD; } void find_fds(struct redirect r, int *left_fd, int *right_fd) { char *rd = r.redir->data; static const int filemode = 0644; // Default value is no valid left fd is passed in `r`. *left_fd = BAD_FD; *right_fd = BAD_FD; if (STRINGS_ARE_EQUAL(rd, ">")) { // Sec. 2.7.2: noclobber must avoid overwritting on an existing file if (env_get("noclobber") != NULL && _file_exists(r.file->data)) { fprintf(stderr, "redirection: Unable to overwrite on %s.\n", r.file->data); return; } *right_fd = open(r.file->data, O_WRONLY | O_CREAT | O_TRUNC, filemode); _assign_if_valid_int_fd(r.fd, left_fd); } if (STRINGS_ARE_EQUAL(rd, ">>")) { *right_fd = open(r.file->data, O_WRONLY | O_CREAT | O_APPEND, filemode); _assign_if_valid_int_fd(r.fd, left_fd); } if (STRINGS_ARE_EQUAL(rd, ">|")) { // Sec. 2.7.2: this redir bypasses noclobber *right_fd = open(r.file->data, O_WRONLY | O_CREAT | O_TRUNC, filemode); _assign_if_valid_int_fd(r.fd, left_fd); } if (STRINGS_ARE_EQUAL(rd, ">&")) { _assign_if_valid_int_fd(r.fd, left_fd); _assign_if_valid_fd_and(r.file, right_fd); if (*right_fd == BAD_FD) { // Sure why not after all, // Because when it is about bash posix // 'undefined' in the SCL means: // OH <&{filename} is AMBIGUOUS // BUT >&{filename} is PERFECTLY FINE *right_fd = open(r.file->data, O_WRONLY | O_CREAT | O_TRUNC, filemode); } } if (STRINGS_ARE_EQUAL(rd, "<")) { *right_fd = open(r.file->data, O_RDONLY); _assign_if_valid_int_fd(r.fd, left_fd); } if (STRINGS_ARE_EQUAL(rd, "<&")) { _assign_if_valid_int_fd(r.fd, left_fd); _assign_if_valid_fd_and(r.file, right_fd); } if (STRINGS_ARE_EQUAL(rd, "<>")) { *right_fd = open(r.file->data, O_RDWR | O_CREAT, filemode); _assign_if_valid_int_fd(r.fd, left_fd); } }