Changeset 9bfb74a in mainline for uspace/app/bdsh/input.c


Ignore:
Timestamp:
2024-11-28T23:11:39Z (3 days ago)
Author:
GitHub <noreply@…>
Parents:
12dd36c (diff), 12f5a1be (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
git-author:
Manuele Conti <conti.manuele@…> (2024-11-28 23:11:39)
git-committer:
GitHub <noreply@…> (2024-11-28 23:11:39)
Message:

Merge 12f5a1be9347ae8a4c87b277c612c58c71f5f5fc into 12dd36c50ddb4a9f3ef61157afc0eaba800ce4ad

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/bdsh/input.c

    r12dd36c r9bfb74a  
    5656#include "tok.h"
    5757
     58#define MAX_PIPES 10U
     59
    5860extern volatile unsigned int cli_quit;
    5961
     
    6365/* Private helpers */
    6466static int run_command(char **, cliuser_t *, iostate_t *);
    65 static void print_pipe_usage(void);
    6667
    6768typedef struct {
     
    7980
    8081        return false;
     82}
     83
     84static errno_t find_alias(char **cmd, list_t *alias_hups, alias_t **data)
     85{
     86        errno_t rc = EOK;
     87
     88        /* test if the passed cmd is an alias */
     89        odlink_t *alias_link = odict_find_eq(&alias_dict, (void *)cmd[0], NULL);
     90        if (alias_link != NULL) {
     91                *data = odict_get_instance(alias_link, alias_t, odict);
     92                /* check if the alias already has been resolved once */
     93                if (! find_alias_hup(*data, alias_hups)) {
     94                        alias_hup_t *hup = (alias_hup_t *)calloc(1, sizeof(alias_hup_t));
     95                        if (hup == NULL) {
     96                                cli_error(CL_EFAIL, "%s: cannot allocate alias structure\n", PACKAGE_NAME);
     97                                rc = ENOMEM;
     98                                goto exit;
     99                        }
     100                        hup->alias = *data;
     101                        list_append(&hup->alias_hup_link, alias_hups);
     102                }
     103        }
     104
     105exit:
     106        return rc;
     107}
     108
     109static errno_t replace_alias(token_t *tokens, unsigned int tokens_start, unsigned int tokens_len, alias_t *data, char **cmd, char **line)
     110{
     111        errno_t rc = EOK;
     112        const size_t input_length = str_size(*line) - str_size(cmd[0]) + str_size(data->value) + 1;
     113        char *newline = (char *)malloc(input_length);
     114        if (newline == NULL) {
     115                cli_error(CL_EFAIL, "%s: cannot allocate input structure\n", PACKAGE_NAME);
     116                rc = ENOMEM;
     117                goto exit;
     118        }
     119
     120        newline[0] = '\0';
     121
     122        unsigned int cmd_replace_index = tokens_start;
     123        for (unsigned int i = 0; i < tokens_len; i++) {
     124                if (i == cmd_replace_index) {
     125                        /* if there is a pipe symbol than cmd_token_start will point at the SPACE after the pipe symbol */
     126                        if (tokens[i].type == TOKTYPE_SPACE) {
     127                                tokens_start++;
     128                                str_append(*line, input_length, tokens[i].text);
     129                                continue;
     130                        }
     131
     132                        str_append(newline, input_length, data->value);
     133                } else {
     134                        str_append(newline, input_length, tokens[i].text);
     135                }
     136        }
     137
     138        *line = newline;
     139exit:
     140        return rc;
    81141}
    82142
     
    88148static errno_t process_input_nohup(cliuser_t *usr, list_t *alias_hups, size_t count_executed_hups)
    89149{
     150        char *cmd[WORD_MAX];
     151        size_t cmd_argc = 0;
     152        errno_t rc = EOK;
     153        tokenizer_t tok;
     154        unsigned int i, pipe_count;
     155        unsigned int pipe_pos[MAX_PIPES];
     156        char *redir_from = NULL;
     157        char *redir_to = NULL;
     158
    90159        if (count_executed_hups >= HUBS_MAX) {
    91160                cli_error(CL_EFAIL, "%s: maximal alias hubs reached\n", PACKAGE_NAME);
     
    98167        token_t *tokens = tokens_buf;
    99168
    100         char *cmd[WORD_MAX];
    101         errno_t rc = EOK;
    102         tokenizer_t tok;
    103         unsigned int i, pipe_count, processed_pipes;
    104         unsigned int pipe_pos[2];
    105         char *redir_from = NULL;
    106         char *redir_to = NULL;
    107 
    108169        if (usr->line == NULL) {
    109170                free(tokens_buf);
     
    131192        }
    132193
    133         /*
    134          * Until full support for pipes is implemented, allow for a simple case:
    135          * [from <file> |] command [| to <file>]
    136          *
    137          * First find the pipes and check that there are no more
    138          */
     194        cmd_argc = tokens_length;
     195        unsigned wait_from = 0;
     196        unsigned wait_to = 0;
    139197        for (i = 0, pipe_count = 0; i < tokens_length; i++) {
    140                 if (tokens[i].type == TOKTYPE_PIPE) {
    141                         if (pipe_count >= 2) {
    142                                 print_pipe_usage();
    143                                 rc = ENOTSUP;
    144                                 goto finit;
    145                         }
    146                         pipe_pos[pipe_count] = i;
    147                         pipe_count++;
    148                 }
     198                switch (tokens[i].type) {
     199                case  TOKTYPE_PIPE:
     200                        pipe_pos[pipe_count++] = i;
     201                        cmd_argc = i;
     202                        redir_from = redir_to = tmpnam(NULL);
     203                        break;
     204
     205                case TOKTYPE_RDIN:
     206                        wait_from = 1;
     207                        cmd_argc = i;
     208                        break;
     209
     210                case TOKTYPE_RDOU:
     211                        wait_to = 1;
     212                        cmd_argc = i;
     213                        break;
     214
     215                case TOKTYPE_TEXT:
     216                        if (wait_from) {
     217                                redir_from = tokens[i].text;
     218                                wait_from = 0;
     219                        }
     220                        if (wait_to) {
     221                                redir_to = tokens[i].text;
     222                                wait_to = 0;
     223                        }
     224                        break;
     225
     226                default:
     227                        break;
     228                }
     229
     230                if (pipe_count > MAX_PIPES) {
     231                        rc = ENOTSUP;
     232                        goto finit;
     233                }
     234        }
     235
     236        if (wait_from || wait_to) {
     237                printf("Parse error near `\\n'\n");
     238                goto finit;
    149239        }
    150240
    151241        unsigned int cmd_token_start = 0;
    152         unsigned int cmd_token_end = tokens_length;
    153 
    154         processed_pipes = 0;
    155 
    156         /* Check if the first part (from <file> |) is present */
    157         if (pipe_count > 0 && (pipe_pos[0] == 3 || pipe_pos[0] == 4) && str_cmp(tokens[0].text, "from") == 0) {
    158                 /* Ignore the first three tokens (from, file, pipe) and set from */
    159                 redir_from = tokens[2].text;
    160                 cmd_token_start = pipe_pos[0] + 1;
    161                 processed_pipes++;
    162         }
    163 
    164         /* Check if the second part (| to <file>) is present */
    165         if ((pipe_count - processed_pipes) > 0 &&
    166             (pipe_pos[processed_pipes] == tokens_length - 4 ||
    167             (pipe_pos[processed_pipes] == tokens_length - 5 &&
    168             tokens[tokens_length - 4].type == TOKTYPE_SPACE)) &&
    169             str_cmp(tokens[tokens_length - 3].text, "to") == 0) {
    170                 /* Ignore the last three tokens (pipe, to, file) and set to */
    171                 redir_to = tokens[tokens_length - 1].text;
    172                 cmd_token_end = pipe_pos[processed_pipes];
    173                 processed_pipes++;
    174         }
    175 
    176         if (processed_pipes != pipe_count) {
    177                 print_pipe_usage();
    178                 rc = ENOTSUP;
    179                 goto finit;
    180         }
    181 
    182         /* Convert tokens of the command to string array */
    183         unsigned int cmd_pos = 0;
    184         for (i = cmd_token_start; i < cmd_token_end; i++) {
    185                 if (tokens[i].type != TOKTYPE_SPACE) {
    186                         cmd[cmd_pos++] = tokens[i].text;
    187                 }
    188         }
    189         cmd[cmd_pos++] = NULL;
    190 
    191         if (cmd[0] == NULL) {
    192                 print_pipe_usage();
    193                 rc = ENOTSUP;
    194                 goto finit;
    195         }
    196 
    197         /* test if the passed cmd is an alias */
    198         odlink_t *alias_link = odict_find_eq(&alias_dict, (void *)cmd[0], NULL);
    199         if (alias_link != NULL) {
    200                 alias_t *data = odict_get_instance(alias_link, alias_t, odict);
    201                 /* check if the alias already has been resolved once */
    202                 if (!find_alias_hup(data, alias_hups)) {
    203                         alias_hup_t *hup = (alias_hup_t *)calloc(1, sizeof(alias_hup_t));
    204                         if (hup == NULL) {
    205                                 cli_error(CL_EFAIL, "%s: cannot allocate alias structure\n", PACKAGE_NAME);
    206                                 rc = ENOMEM;
    207                                 goto finit;
    208                         }
    209 
    210                         hup->alias = data;
    211                         list_append(&hup->alias_hup_link, alias_hups);
    212 
    213                         char *oldLine = usr->line;
    214                         const size_t input_length = str_size(usr->line) - str_size(cmd[0]) + str_size(data->value) + 1;
    215                         usr->line = (char *)malloc(input_length);
    216                         if (usr->line == NULL) {
    217                                 cli_error(CL_EFAIL, "%s: cannot allocate input structure\n", PACKAGE_NAME);
    218                                 rc = ENOMEM;
    219                                 goto finit;
    220                         }
    221 
    222                         usr->line[0] = '\0';
    223 
    224                         unsigned int cmd_replace_index = cmd_token_start;
    225                         for (i = 0; i < tokens_length; i++) {
    226                                 if (i == cmd_replace_index) {
    227                                         /* if there is a pipe symbol than cmd_token_start will point at the SPACE after the pipe symbol */
    228                                         if (tokens[i].type == TOKTYPE_SPACE) {
    229                                                 cmd_replace_index++;
    230                                                 str_append(usr->line, input_length, tokens[i].text);
    231                                                 continue;
    232                                         }
    233 
    234                                         str_append(usr->line, input_length, data->value);
    235                                 } else {
    236                                         str_append(usr->line, input_length, tokens[i].text);
    237                                 }
    238                         }
    239 
    240                         /* reprocess input after string replace */
    241                         rc = process_input_nohup(usr, alias_hups, count_executed_hups + 1);
    242                         usr->line = oldLine;
    243                         goto finit;
    244                 }
    245         }
     242        unsigned int cmd_token_end = cmd_argc;
    246243
    247244        iostate_t new_iostate = {
     
    254251        FILE *to = NULL;
    255252
    256         if (redir_from) {
    257                 from = fopen(redir_from, "r");
    258                 if (from == NULL) {
    259                         printf("Cannot open file %s\n", redir_from);
    260                         rc = errno;
    261                         goto finit_with_files;
    262                 }
    263                 new_iostate.stdin = from;
    264         }
    265 
    266         if (redir_to) {
    267                 to = fopen(redir_to, "w");
    268                 if (to == NULL) {
    269                         printf("Cannot open file %s\n", redir_to);
    270                         rc = errno;
    271                         goto finit_with_files;
    272                 }
    273                 new_iostate.stdout = to;
    274         }
    275 
    276         if (run_command(cmd, usr, &new_iostate) == 0) {
    277                 rc = EOK;
    278         } else {
    279                 rc = EINVAL;
     253
     254        for (unsigned p = 0; p <= pipe_count; p++) {
     255                /* Convert tokens of the command to string array */
     256                unsigned int cmd_pos = 0;
     257                for (i = cmd_token_start; i < cmd_token_end; i++) {
     258                        if (tokens[i].type != TOKTYPE_SPACE) {
     259                                cmd[cmd_pos++] = tokens[i].text;
     260                        }
     261                }
     262                cmd[cmd_pos] = NULL;
     263
     264                if (cmd[0] == NULL) {
     265                        printf("Command not found.\n");
     266                        rc = ENOTSUP;
     267                        goto finit;
     268                }
     269
     270                alias_t *data = NULL;
     271                rc = find_alias(cmd, alias_hups, &data);
     272                if (rc != EOK) {
     273                        goto finit;
     274                }
     275
     276                if (data != NULL) {
     277                        rc = replace_alias(tokens, cmd_token_start, tokens_length, data, cmd, &usr->line);
     278                        if (rc == EOK) {
     279                                /* reprocess input after string replace */
     280                                rc = process_input_nohup(usr, alias_hups, count_executed_hups + 1);
     281                        }
     282                        goto finit;
     283                }
     284
     285                if (redir_to) {
     286                        if ((p < pipe_count) || (pipe_count == 0)) {
     287                                to = fopen(redir_to, "w");
     288                                if (to == NULL) {
     289                                        printf("Cannot open file %s\n", redir_to);
     290                                        rc = errno;
     291                                        goto finit_with_files;
     292                                }
     293                                new_iostate.stdout = to;
     294                        }
     295                }
     296
     297                if (redir_from) {
     298                        if ((p && p == pipe_count) || (pipe_count == 0)) {
     299                                from = fopen(redir_from, "r");
     300                                if (from == NULL) {
     301                                        printf("Cannot open file %s\n", redir_from);
     302                                        rc = errno;
     303                                        goto finit_with_files;
     304                                }
     305                                new_iostate.stdin = from;
     306                        }
     307                }
     308
     309                if (run_command(cmd, usr, &new_iostate) == 0) {
     310                        rc = EOK;
     311                } else {
     312                        rc = EINVAL;
     313                }
     314
     315                if (to) {
     316                        fclose(to);
     317                        to = NULL;
     318                }
     319                if (from) {
     320                        fclose(from);
     321                        from = NULL;
     322                }
     323                // Restore the Standard Input, Output and Error file descriptors
     324                new_iostate.stdin = stdin;
     325                new_iostate.stdout = stdout;
     326                new_iostate.stderr = stderr;
     327
     328                cmd_token_start = cmd_token_end + 1;
     329                cmd_token_end = (p < pipe_count - 1) ? pipe_pos[p + 1] : tokens_length;
    280330        }
    281331
     
    312362
    313363        return rc;
    314 }
    315 
    316 void print_pipe_usage(void)
    317 {
    318         printf("Invalid syntax!\n");
    319         printf("Usage of redirection (pipes in the future):\n");
    320         printf("from filename | command ...\n");
    321         printf("from filename | command ... | to filename\n");
    322         printf("command ... | to filename\n");
    323 
    324364}
    325365
Note: See TracChangeset for help on using the changeset viewer.