Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:18

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @brief RTEMS std redirector.
0007  */
0008 
0009 /*
0010  * Copyright (C) 2014 Chris Johns (chrisj@rtems.org)
0011  *
0012  * Redistribution and use in source and binary forms, with or without
0013  * modification, are permitted provided that the following conditions
0014  * are met:
0015  * 1. Redistributions of source code must retain the above copyright
0016  *    notice, this list of conditions and the following disclaimer.
0017  * 2. Redistributions in binary form must reproduce the above copyright
0018  *    notice, this list of conditions and the following disclaimer in the
0019  *    documentation and/or other materials provided with the distribution.
0020  *
0021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0025  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0026  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0027  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0030  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0031  * POSSIBILITY OF SUCH DAMAGE.
0032  */
0033 
0034 #include <errno.h>
0035 #include <stdio.h>
0036 #include <stdlib.h>
0037 #include <string.h>
0038 #include <strings.h>
0039 #include <sys/types.h>
0040 #include <unistd.h>
0041 
0042 #include <rtems/thread.h>
0043 #include <rtems/error.h>
0044 #include <rtems/stdio-redirect.h>
0045 
0046 #define RTEMS_STDIO_REDIRECT_RUNNING  (1 << 0)
0047 #define RTEMS_STDIO_REDIRECT_FINISHED (1 << 1)
0048 
0049 static void
0050 rtems_stdio_redirect_lock(rtems_stdio_redirect* sr)
0051 {
0052   rtems_mutex_lock(&sr->lock);
0053 }
0054 
0055 static void
0056 rtems_stdio_redirect_unlock(rtems_stdio_redirect* sr)
0057 {
0058   rtems_mutex_unlock(&sr->lock);
0059 }
0060 
0061 static void
0062 rtems_stdio_redirect_write (rtems_stdio_redirect* sr, const char* buf, ssize_t len)
0063 {
0064   rtems_stdio_redirect_lock(sr);
0065 
0066   if (sr->buffer)
0067   {
0068     if (len >= sr->buffer_size)
0069     {
0070       ssize_t offset = len - sr->buffer_size;
0071       memcpy (sr->buffer, buf + offset, sr->buffer_size);
0072       sr->in  = 0;
0073       sr->full = true;
0074     }
0075     else
0076     {
0077       if ((sr->in + len) > sr->buffer_size)
0078       {
0079         ssize_t bytes = sr->buffer_size - sr->in;
0080         memcpy (sr->buffer + sr->in, buf, bytes);
0081         buf += bytes;
0082         len -= bytes;
0083         sr->in = 0;
0084         sr->full = true;
0085       }
0086       else
0087       {
0088         memcpy (sr->buffer + sr->in, buf, len);
0089         sr->in += len;
0090       }
0091     }
0092   }
0093 
0094   if (sr->handler)
0095     sr->handler(buf, len);
0096 
0097   rtems_stdio_redirect_unlock(sr);
0098 }
0099 
0100 static rtems_task
0101 rtems_stdio_redirect_reader(rtems_task_argument arg)
0102 {
0103   rtems_stdio_redirect* sr = (rtems_stdio_redirect*) arg;
0104 
0105   while (sr->state & RTEMS_STDIO_REDIRECT_RUNNING)
0106   {
0107     ssize_t r = read (sr->pipe[0], sr->input, sr->input_size);
0108 
0109     if (r <= 0)
0110       break;
0111 
0112     if (sr->echo)
0113       write (sr->fd_dup, sr->input, r);
0114 
0115     rtems_stdio_redirect_write (sr, sr->input, r);
0116   }
0117 
0118   sr->state |= RTEMS_STDIO_REDIRECT_FINISHED;
0119 
0120   rtems_task_exit();
0121 }
0122 
0123 rtems_stdio_redirect*
0124 rtems_stdio_redirect_open(int                          fd,
0125                           rtems_task_priority          priority,
0126                           size_t                       stack_size,
0127                           ssize_t                      input_size,
0128                           ssize_t                      buffer_size,
0129                           bool                         echo,
0130                           rtems_stdio_redirect_handler handler)
0131 {
0132   rtems_stdio_redirect* sr;
0133   rtems_name            name;
0134   rtems_status_code     sc;
0135 
0136   sr = malloc(sizeof(*sr));
0137   if (!sr)
0138   {
0139     fprintf(stderr, "error: stdio-redirect: no memory\n");
0140     return NULL;
0141   }
0142 
0143   memset(sr, 0, sizeof(*sr));
0144 
0145   sr->input_size = input_size;
0146   sr->input = malloc(input_size);
0147   if (!sr->input)
0148   {
0149     fprintf(stderr, "error: stdio-redirect: no memory for input\n");
0150     free(sr);
0151     return NULL;
0152   }
0153 
0154   if (buffer_size)
0155   {
0156     sr->buffer_size = buffer_size;
0157     sr->buffer = malloc(buffer_size);
0158     if (!sr->buffer)
0159     {
0160       fprintf(stderr, "error: stdio-redirect: no memory for buffer\n");
0161       free(sr->input);
0162       free(sr);
0163       return NULL;
0164     }
0165   }
0166 
0167   sr->fd = fd;
0168 
0169   sr->fd_dup = dup(fd);
0170   if (sr->fd_dup < 0)
0171   {
0172     fprintf(stderr, "error: stdio-redirect: dup: %s\n", strerror(errno));
0173     free(sr->buffer);
0174     free(sr->input);
0175     free(sr);
0176     return NULL;
0177   }
0178 
0179   if (pipe(sr->pipe) < 0)
0180   {
0181     fprintf(stderr, "error: stdio-redirect: pipe create: %s\n", strerror(errno));
0182     free(sr->buffer);
0183     free(sr->input);
0184     free(sr);
0185     return NULL;
0186 
0187   }
0188 
0189   sr->echo = echo;
0190   sr->handler = handler;
0191 
0192   rtems_mutex_init(&sr->lock, "stdio-redirect");
0193 
0194   name = rtems_build_name ('S', 'R', '0' + (fd / 10), '0' + (fd % 10));
0195   sc = rtems_task_create (name,
0196                           priority,
0197                           stack_size,
0198                           RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR,
0199                           RTEMS_LOCAL | RTEMS_NO_FLOATING_POINT,
0200                           &sr->reader);
0201   if (sc != RTEMS_SUCCESSFUL)
0202   {
0203     fprintf(stderr, "error: stdio-redirect: reader create: %s\n", rtems_status_text(sc));
0204     rtems_mutex_destroy(&sr->lock);
0205     free(sr->buffer);
0206     free(sr->input);
0207     free(sr);
0208     return NULL;
0209   }
0210 
0211   sr->state |= RTEMS_STDIO_REDIRECT_RUNNING;
0212 
0213   if (dup2 (sr->pipe[1], fd) < 0)
0214   {
0215     fprintf(stderr, "error: stdio-redirect: dup2: %s\n", strerror(errno));
0216     free(sr->buffer);
0217     free(sr->input);
0218     free(sr);
0219     return NULL;
0220   }
0221 
0222   sc = rtems_task_start (sr->reader,
0223                          rtems_stdio_redirect_reader,
0224                          (rtems_task_argument) sr);
0225 
0226   if (sc != RTEMS_SUCCESSFUL)
0227   {
0228     fprintf(stderr, "error: stdio-redirect: reader start: %s\n", rtems_status_text(sc));
0229     rtems_task_delete(sr->reader);
0230     rtems_mutex_destroy(&sr->lock);
0231     free(sr->buffer);
0232     free(sr->input);
0233     free(sr);
0234     return NULL;
0235   }
0236 
0237   return sr;
0238 }
0239 
0240 void
0241 rtems_stdio_redirect_close(rtems_stdio_redirect* sr)
0242 {
0243   rtems_stdio_redirect_lock(sr);
0244 
0245   sr->state &= ~RTEMS_STDIO_REDIRECT_RUNNING;
0246   close(sr->pipe[0]);
0247 
0248   rtems_stdio_redirect_unlock(sr);
0249 
0250   while (sr->state & RTEMS_STDIO_REDIRECT_FINISHED)
0251   {
0252     usleep(250UL * 1000000UL);
0253   }
0254 
0255   rtems_stdio_redirect_lock(sr);
0256 
0257   dup2(sr->fd, sr->fd_dup);
0258 
0259   free(sr->buffer);
0260   free(sr->input);
0261 
0262   rtems_stdio_redirect_unlock(sr);
0263 
0264   rtems_mutex_destroy(&sr->lock);
0265 
0266   free(sr);
0267 }
0268 
0269 ssize_t
0270 rtems_stdio_redirect_read(rtems_stdio_redirect* sr,
0271                           char*                 buffer,
0272                           ssize_t               length)
0273 {
0274   ssize_t written = 0;
0275 
0276   rtems_stdio_redirect_lock(sr);
0277 
0278   if (sr->buffer)
0279   {
0280     ssize_t rem = 0;
0281 
0282     if (sr->full)
0283     {
0284       if (length < sr->buffer_size)
0285       {
0286         if (length > sr->in)
0287         {
0288           rem = length - sr->in;
0289           memcpy (buffer, sr->buffer + sr->buffer_size - rem, rem);
0290         }
0291 
0292         memcpy (buffer + rem, sr->buffer, sr->in);
0293         written = length;
0294       }
0295       else
0296       {
0297         rem = sr->buffer_size - sr->in;
0298         memcpy (buffer, sr->buffer + sr->in, rem);
0299         memcpy (buffer + rem, sr->buffer, sr->in);
0300         written = sr->buffer_size;
0301       }
0302 
0303       sr->full = false;
0304     }
0305     else if (length < sr->in)
0306     {
0307       rem = sr->in - length;
0308       memcpy (buffer, sr->buffer + rem, length);
0309       written = length;
0310     }
0311     else
0312     {
0313       memcpy (buffer, sr->buffer, sr->in);
0314       written = sr->in;
0315     }
0316   }
0317 
0318   rtems_stdio_redirect_unlock(sr);
0319 
0320   return written;
0321 }