Coverage Report

Created: 2026-04-09 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebsockets/lib/system/stdin.c
Line
Count
Source
1
/*
2
 * libwebsockets - small server side websockets and web server implementation
3
 *
4
 * Copyright (C) 2010 - 2025 Andy Green <andy@warmcat.com>
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to
8
 * deal in the Software without restriction, including without limitation the
9
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10
 * sell copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22
 * IN THE SOFTWARE.
23
 */
24
25
#include "private-lib-core.h"
26
27
static int
28
callback_system_stdin(struct lws *wsi, enum lws_callback_reasons reason, void *user,
29
         void *in, size_t len)
30
0
{
31
0
  struct lws_context *cx;
32
0
  char buf[256];
33
0
  ssize_t n;
34
0
  int fd;
35
36
0
  switch (reason) {
37
38
0
  case LWS_CALLBACK_RAW_CLOSE_FILE:
39
0
    cx = wsi->a.context;
40
0
    if (!(cx->stdin_flags & LWS_SAS_FLAG__APPEND_COMMANDLINE)) {
41
0
      if (!cx->system_ops || !cx->system_ops->stdin_rx)
42
0
        return -1;
43
0
      cx->system_ops->stdin_rx(cx, NULL, 0);
44
0
    } else {
45
0
      char *p, *end, *s, esc = 0;
46
0
      int m;
47
48
      /*
49
       * Bring in the process argv 
50
       */
51
52
0
      if (cx->argc > (int)LWS_ARRAY_SIZE(cx->stdin_argv)) {
53
0
        lwsl_err("%s: Too many commandline args\n", __func__);
54
0
        return -1;
55
0
      }
56
57
0
      for (m = 0; m < cx->argc; m++)
58
0
        cx->stdin_argv[cx->stdin_argc++] = cx->argv[m];
59
60
      /*
61
       * linearize stdin
62
       */
63
64
0
      cx->stdin_linear_size = lws_buflist_total_len(&cx->stdin_buflist);
65
0
      cx->stdin_linear = lws_malloc(cx->stdin_linear_size, __func__);
66
0
      if (!cx->stdin_linear) {
67
0
        lws_buflist_destroy_all_segments(&cx->stdin_buflist);
68
0
        return -1;
69
0
      }
70
0
      lws_buflist_linear_use(&cx->stdin_buflist, (uint8_t *)cx->stdin_linear,
71
0
                 cx->stdin_linear_size);
72
73
      /*
74
       * segment the linear buffer
75
       */
76
77
0
      s = p = cx->stdin_linear;
78
0
      end = p + cx->stdin_linear_size;
79
0
      while (p < end) {
80
0
        if (esc) {
81
0
          esc = 0;
82
0
          goto next;
83
0
        }
84
0
        if (*p == '\\') {
85
0
          esc = 1;
86
0
          goto next;
87
0
        }
88
0
        if (*p == '\n' || *p == ' ') {
89
0
          *p = '\0';
90
0
          cx->stdin_argv[cx->stdin_argc++] = s;
91
0
          if (cx->stdin_argc >= (int)LWS_ARRAY_SIZE(cx->stdin_argv) - 1) {
92
0
            lwsl_err("%s: reached stdin argv limit\n", __func__);
93
0
            break;
94
0
          }
95
0
          s = p + 1;
96
0
        }
97
0
next:
98
0
        p++;
99
0
      }
100
0
      if (p != s)
101
0
        cx->stdin_argv[cx->stdin_argc++] = s;
102
103
0
    }
104
105
#if 0
106
    for (int m = 0; m < cx->stdin_argc; m++)
107
      lwsl_notice("%s: %d: '%s'\n", __func__, m, cx->stdin_argv[m]);
108
#endif
109
0
#if defined(LWS_WITH_SYS_STATE)
110
0
    lws_state_transition_steps(&cx->mgr_system, LWS_SYSTATE_OPERATIONAL);
111
0
#endif
112
0
    break;
113
114
0
  case LWS_CALLBACK_RAW_RX_FILE:
115
0
    cx = wsi->a.context;
116
0
    if (!(cx->stdin_flags & LWS_SAS_FLAG__APPEND_COMMANDLINE))
117
0
      if (!cx->system_ops || !cx->system_ops->stdin_rx)
118
0
        return -1;
119
120
0
    fd = (int)lws_get_socket_fd(wsi);
121
0
    if (fd < 0)
122
0
      return -1;
123
0
    n = read(fd, buf, sizeof(buf));
124
0
    if (n < 0)
125
0
      return -1;
126
127
0
    if (!(cx->stdin_flags & LWS_SAS_FLAG__APPEND_COMMANDLINE)) {
128
0
      if (cx->system_ops->stdin_rx(cx, buf, (size_t)n) || !n)
129
0
        return -1;
130
0
      break;
131
0
    }
132
133
0
    if (n && lws_buflist_append_segment(&cx->stdin_buflist, (const uint8_t *)buf, (size_t)n))
134
0
      return -1;
135
0
    break;
136
137
0
  default:
138
0
    break;
139
0
  }
140
141
0
  return 0;
142
0
}
143
144
struct lws_protocols lws_system_protocol_stdin = /* imported by lib/core/context.c */
145
  { "lws-stdin", callback_system_stdin, 0, 0, 0, NULL, 0 };
146
147
int
148
lws_system_adopt_stdin(struct lws_context *cx, unsigned int flags)
149
0
{
150
0
  lws_sock_file_fd_type sock;
151
0
  struct lws_vhost *vh;
152
153
0
  sock.filefd   = 0; /* stdin */
154
0
  cx->stdin_flags   = flags;
155
156
0
#if defined(LWS_WITH_SYS_STATE)
157
  /* if there's no stdin_rx callback, there's nothing for us to do */
158
159
0
  if (!cx->system_ops || !cx->system_ops->stdin_rx)
160
0
    lws_state_transition_steps(&cx->mgr_system, LWS_SYSTATE_OPERATIONAL);
161
0
#endif
162
163
0
  vh = lws_get_vhost_by_name(cx, "system");
164
0
  if (!vh) {
165
0
    lwsl_err("%s: unable to find system vh\n", __func__);
166
0
    return 1;
167
0
  }
168
169
0
  if (!lws_adopt_descriptor_vhost(vh, LWS_ADOPT_RAW_FILE_DESC, sock, "lws-stdin", NULL)) {
170
0
    lwsl_err("%s: stdin adoption failed\n", __func__);
171
0
    return 1;
172
0
  }
173
174
0
  return 0;
175
0
}
176