channel-func.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. /* channel-func.c -- SSH channel manipulation functions.
  2. *
  3. * Copyright (C) 2013, 2014, 2015 Artyom V. Poptsov <poptsov.artyom@gmail.com>
  4. *
  5. * This file is part of Guile-SSH.
  6. *
  7. * Guile-SSH is free software: you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation, either version 3 of the
  10. * License, or (at your option) any later version.
  11. *
  12. * Guile-SSH is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with Guile-SSH. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include <config.h>
  21. #include <assert.h>
  22. #include <libguile.h>
  23. #include <libssh/libssh.h>
  24. #include <libssh/server.h>
  25. #include "common.h"
  26. #include "error.h"
  27. #include "channel-type.h"
  28. #include "session-type.h"
  29. #ifdef HAVE_LIBSSH_0_7_3
  30. #define ssh_forward_listen ssh_channel_listen_forward
  31. #define ssh_forward_cancel ssh_channel_cancel_forward
  32. #endif
  33. /* Procedures */
  34. SCM_DEFINE (guile_ssh_channel_open_session, "channel-open-session", 1, 0, 0,
  35. (SCM channel),
  36. "\
  37. Open a new session and mark the channel CHANNEL as opened port.\n\
  38. Return value is undefined.\
  39. ")
  40. #define FUNC_NAME s_guile_ssh_channel_open_session
  41. {
  42. struct channel_data *data = _scm_to_channel_data (channel);
  43. int res;
  44. GSSH_VALIDATE_CHANNEL_DATA (data, channel, FUNC_NAME);
  45. res = ssh_channel_open_session (data->ssh_channel);
  46. if (res != SSH_OK)
  47. {
  48. ssh_session session = ssh_channel_get_session (data->ssh_channel);
  49. guile_ssh_session_error1 (FUNC_NAME, session, channel);
  50. }
  51. SCM_SET_CELL_TYPE (channel, SCM_CELL_TYPE (channel) | SCM_OPN);
  52. return SCM_UNDEFINED;
  53. }
  54. #undef FUNC_NAME
  55. /* Run a shell command CMD without an interactive shell. */
  56. SCM_DEFINE (guile_ssh_channel_request_exec, "channel-request-exec", 2, 0, 0,
  57. (SCM channel, SCM cmd),
  58. "\
  59. Run a shell command CMD without an interactive shell.\
  60. ")
  61. #define FUNC_NAME s_guile_ssh_channel_request_exec
  62. {
  63. struct channel_data *data = _scm_to_channel_data (channel);
  64. int res;
  65. char *c_cmd; /* Command to execute. */
  66. GSSH_VALIDATE_OPEN_CHANNEL (channel, SCM_ARG1, FUNC_NAME);
  67. SCM_ASSERT (scm_is_string (cmd), cmd, SCM_ARG2, FUNC_NAME);
  68. c_cmd = scm_to_locale_string (cmd);
  69. res = ssh_channel_request_exec (data->ssh_channel, c_cmd);
  70. free (c_cmd);
  71. if (res != SSH_OK)
  72. {
  73. ssh_session session = ssh_channel_get_session (data->ssh_channel);
  74. guile_ssh_session_error1 (FUNC_NAME, session, scm_list_2 (channel, cmd));
  75. }
  76. return SCM_UNDEFINED;
  77. }
  78. #undef FUNC_NAME
  79. SCM_DEFINE (guile_ssh_channel_get_exit_status,
  80. "channel-get-exit-status", 1, 0, 0,
  81. (SCM channel),
  82. "\
  83. Get the exit status of the channel (error code from the executed \
  84. instruction). Return the exist status, or #f if no exit status has been \
  85. returned (yet). \
  86. ")
  87. #define FUNC_NAME s_guile_ssh_channel_get_exit_status
  88. {
  89. struct channel_data *cd = _scm_to_channel_data (channel);
  90. int res;
  91. GSSH_VALIDATE_OPEN_CHANNEL (channel, SCM_ARG1, FUNC_NAME);
  92. res = ssh_channel_get_exit_status (cd->ssh_channel);
  93. return (res == SSH_ERROR) ? SCM_BOOL_F : scm_from_int (res);
  94. }
  95. #undef FUNC_NAME
  96. SCM_DEFINE (guile_ssh_channel_request_send_exit_status,
  97. "channel-request-send-exit-status", 2, 0, 0,
  98. (SCM channel, SCM exit_status),
  99. "\
  100. Send the exit status to the remote process (as described in RFC 4254, section\n\
  101. 6.10).\n\
  102. Return value is undefined.\
  103. ")
  104. #define FUNC_NAME s_guile_ssh_channel_request_send_exit_status
  105. {
  106. struct channel_data *cd = _scm_to_channel_data (channel);
  107. int res;
  108. GSSH_VALIDATE_OPEN_CHANNEL (channel, SCM_ARG1, FUNC_NAME);
  109. SCM_ASSERT (scm_is_unsigned_integer (exit_status, 0, UINT32_MAX), exit_status,
  110. SCM_ARG2, FUNC_NAME);
  111. res = ssh_channel_request_send_exit_status (cd->ssh_channel,
  112. scm_to_uint32 (exit_status));
  113. if (res != SSH_OK)
  114. {
  115. ssh_session session = ssh_channel_get_session (cd->ssh_channel);
  116. guile_ssh_session_error1 (FUNC_NAME, session, channel);
  117. }
  118. return SCM_UNDEFINED;
  119. }
  120. #undef FUNC_NAME
  121. SCM_DEFINE (guile_ssh_channel_request_pty, "channel-request-pty", 1, 0, 0,
  122. (SCM channel),
  123. "\
  124. Request a PTY (pseudo terminal).\n\
  125. Return value is undefined.\
  126. ")
  127. #define FUNC_NAME s_guile_ssh_channel_request_pty
  128. {
  129. struct channel_data *data = _scm_to_channel_data (channel);
  130. int res;
  131. GSSH_VALIDATE_OPEN_CHANNEL (channel, SCM_ARG1, FUNC_NAME);
  132. res = ssh_channel_request_pty (data->ssh_channel);
  133. if (res != SSH_OK)
  134. {
  135. ssh_session session = ssh_channel_get_session (data->ssh_channel);
  136. guile_ssh_session_error1 (FUNC_NAME, session, channel);
  137. }
  138. return SCM_UNDEFINED;
  139. }
  140. #undef FUNC_NAME
  141. SCM_DEFINE (guile_ssh_channel_request_shell, "channel-request-shell", 1, 0, 0,
  142. (SCM channel),
  143. "\
  144. Request a shell.\n\
  145. Return value is undefined.\
  146. ")
  147. #define FUNC_NAME s_guile_ssh_channel_request_shell
  148. {
  149. struct channel_data *data = _scm_to_channel_data (channel);
  150. int res;
  151. GSSH_VALIDATE_OPEN_CHANNEL (channel, SCM_ARG1, FUNC_NAME);
  152. res = ssh_channel_request_shell (data->ssh_channel);
  153. if (res != SSH_OK)
  154. {
  155. ssh_session session = ssh_channel_get_session (data->ssh_channel);
  156. guile_ssh_session_error1 (FUNC_NAME, session, channel);
  157. }
  158. return SCM_UNDEFINED;
  159. }
  160. #undef FUNC_NAME
  161. /* Set an environment variable NAME to value VALUE
  162. Return value is undefined. */
  163. SCM_DEFINE (guile_ssh_channel_request_env, "channel-request-env", 3, 0, 0,
  164. (SCM channel, SCM name, SCM value),
  165. "\
  166. Set an environment variable NAME to value VALUE.\n\
  167. Return value is undefined.\
  168. ")
  169. #define FUNC_NAME s_guile_ssh_channel_request_env
  170. {
  171. struct channel_data *data = _scm_to_channel_data (channel);
  172. char *c_name;
  173. char *c_value;
  174. int res;
  175. GSSH_VALIDATE_OPEN_CHANNEL (channel, SCM_ARG1, FUNC_NAME);
  176. SCM_ASSERT (scm_is_string (name), name, SCM_ARG2, FUNC_NAME);
  177. SCM_ASSERT (scm_is_string (value), value, SCM_ARG3, FUNC_NAME);
  178. c_name = scm_to_locale_string (name);
  179. c_value = scm_to_locale_string (value);
  180. res = ssh_channel_request_env (data->ssh_channel, c_name, c_value);
  181. if (res != SSH_OK)
  182. {
  183. ssh_session session = ssh_channel_get_session (data->ssh_channel);
  184. guile_ssh_session_error1 (FUNC_NAME, session, channel);
  185. }
  186. return SCM_UNDEFINED;
  187. }
  188. #undef FUNC_NAME
  189. /* Asserts:
  190. - RES is one of the valid contants described in 'libssh.h'.
  191. */
  192. SCM
  193. _ssh_result_to_symbol (int res)
  194. {
  195. switch (res)
  196. {
  197. case SSH_OK:
  198. return scm_from_locale_symbol ("ok");
  199. case SSH_AGAIN:
  200. return scm_from_locale_symbol ("again");
  201. case SSH_ERROR:
  202. return scm_from_locale_symbol ("error");
  203. default: /* Must not happen. */
  204. assert (0);
  205. return SCM_BOOL_F;
  206. }
  207. }
  208. SCM_GSSH_DEFINE (guile_ssh_channel_open_forward,
  209. "%channel-open-forward", 5,
  210. (SCM channel, SCM remote_host, SCM remote_port,
  211. SCM source_host, SCM local_port))
  212. #define FUNC_NAME s_guile_ssh_channel_open_forward
  213. {
  214. struct channel_data *cd = _scm_to_channel_data (channel);
  215. char *c_remote_host = NULL;
  216. char *c_source_host = NULL;
  217. int res;
  218. SCM_ASSERT (scm_is_string (remote_host), remote_host, SCM_ARG2, FUNC_NAME);
  219. SCM_ASSERT (scm_is_number (remote_port), remote_port, SCM_ARG3, FUNC_NAME);
  220. SCM_ASSERT (scm_is_string (source_host), source_host, SCM_ARG4, FUNC_NAME);
  221. SCM_ASSERT (scm_is_number (local_port), local_port, SCM_ARG5, FUNC_NAME);
  222. scm_dynwind_begin (0);
  223. c_remote_host = scm_to_locale_string (remote_host);
  224. scm_dynwind_free (c_remote_host);
  225. c_source_host = scm_to_locale_string (source_host);
  226. scm_dynwind_free (c_source_host);
  227. res = ssh_channel_open_forward (cd->ssh_channel,
  228. c_remote_host, scm_to_int32 (remote_port),
  229. c_source_host, scm_to_int32 (local_port));
  230. if (res == SSH_OK)
  231. SCM_SET_CELL_TYPE (channel, SCM_CELL_TYPE (channel) | SCM_OPN);
  232. scm_dynwind_end ();
  233. return _ssh_result_to_symbol (res);
  234. }
  235. #undef FUNC_NAME
  236. SCM_GSSH_DEFINE (guile_ssh_channel_listen_forward,
  237. "%channel-listen-forward", 3,
  238. (SCM session, SCM address, SCM port))
  239. #define FUNC_NAME s_guile_ssh_channel_listen_forward
  240. {
  241. struct session_data *sd = _scm_to_session_data (session);
  242. char *c_address = NULL;
  243. int bound_port;
  244. int res;
  245. SCM_ASSERT (scm_is_string (address) || scm_is_bool (address),
  246. address, SCM_ARG2, FUNC_NAME);
  247. SCM_ASSERT (scm_is_number (port), port, SCM_ARG3, FUNC_NAME);
  248. scm_dynwind_begin (0);
  249. if (scm_is_string (address))
  250. {
  251. c_address = scm_to_locale_string (address);
  252. scm_dynwind_free (c_address);
  253. }
  254. res = ssh_forward_listen (sd->ssh_session,
  255. c_address,
  256. scm_to_int (port),
  257. &bound_port);
  258. if (res != SSH_OK)
  259. bound_port = -1;
  260. else if (scm_zero_p (port))
  261. bound_port = scm_to_int (port);
  262. scm_dynwind_end ();
  263. return scm_values (scm_list_2 (_ssh_result_to_symbol (res),
  264. scm_from_int (bound_port)));
  265. }
  266. #undef FUNC_NAME
  267. SCM_GSSH_DEFINE (guile_ssh_channel_accept_forward,
  268. "%channel-accept-forward", 2,
  269. (SCM session, SCM timeout))
  270. #define FUNC_NAME s_guile_ssh_channel_accept_forward
  271. {
  272. struct session_data *sd = _scm_to_session_data (session);
  273. ssh_channel c_channel = NULL;
  274. SCM channel = SCM_BOOL_F;
  275. int port;
  276. SCM_ASSERT (scm_is_number (timeout), timeout, SCM_ARG2, FUNC_NAME);
  277. c_channel = ssh_channel_accept_forward (sd->ssh_session,
  278. scm_to_int (timeout),
  279. &port);
  280. if (c_channel)
  281. {
  282. channel = _scm_from_channel_data (c_channel, session,
  283. SCM_RDNG | SCM_WRTNG);
  284. SCM_SET_CELL_TYPE (channel, SCM_CELL_TYPE (channel) | SCM_OPN);
  285. }
  286. return scm_values (scm_list_2 (channel, scm_from_int (port)));
  287. }
  288. #undef FUNC_NAME
  289. /* FIXME: Should it be defined in some other module? */
  290. SCM_GSSH_DEFINE (guile_ssh_channel_cancel_forward,
  291. "channel-cancel-forward", 3,
  292. (SCM session, SCM address, SCM port))
  293. #define FUNC_NAME s_guile_ssh_channel_cancel_forward
  294. {
  295. struct session_data *sd = _scm_to_session_data (session);
  296. char *c_address = NULL;
  297. int res;
  298. SCM_ASSERT (scm_is_string (address), address, SCM_ARG2, FUNC_NAME);
  299. SCM_ASSERT (scm_is_number (port), port, SCM_ARG3, FUNC_NAME);
  300. scm_dynwind_begin (0);
  301. c_address = scm_to_locale_string (address);
  302. scm_dynwind_free (c_address);
  303. res = ssh_forward_cancel (sd->ssh_session,
  304. c_address, scm_to_int32 (port));
  305. scm_dynwind_end ();
  306. return _ssh_result_to_symbol (res);
  307. }
  308. #undef FUNC_NAME
  309. SCM_DEFINE (guile_ssh_channel_set_pty_size_x,
  310. "channel-set-pty-size!", 3, 0, 0,
  311. (SCM channel, SCM col, SCM row),
  312. "\
  313. Change size of the PTY to columns COL and rows ROW.\n\
  314. eturn value is undefined.\
  315. ")
  316. #define FUNC_NAME s_guile_ssh_channel_set_pty_size_x
  317. {
  318. struct channel_data *data = _scm_to_channel_data (channel);
  319. GSSH_VALIDATE_OPEN_CHANNEL (channel, SCM_ARG1, FUNC_NAME);
  320. SCM_ASSERT (scm_is_unsigned_integer (col, 0, UINT32_MAX), col,
  321. SCM_ARG2, FUNC_NAME);
  322. SCM_ASSERT (scm_is_unsigned_integer (row, 0, UINT32_MAX), row,
  323. SCM_ARG2, FUNC_NAME);
  324. ssh_channel_change_pty_size (data->ssh_channel,
  325. scm_to_uint32 (col),
  326. scm_to_uint32 (row));
  327. return SCM_UNDEFINED;
  328. }
  329. #undef FUNC_NAME
  330. SCM_DEFINE (guile_ssh_channel_set_stream_x,
  331. "channel-set-stream!", 2, 0, 0,
  332. (SCM channel, SCM stream_name),
  333. "\
  334. Set stream STREAM_NAME for channel CHANNEL. STREAM_NAME must be one of the \n\
  335. following symbols: \"stdout\" (default), \"stderr\".\n\
  336. Return value is undefined.\
  337. ")
  338. #define FUNC_NAME s_guile_ssh_channel_set_stream_x
  339. {
  340. struct channel_data *cd = _scm_to_channel_data (channel);
  341. GSSH_VALIDATE_OPEN_CHANNEL (channel, SCM_ARG1, FUNC_NAME);
  342. SCM_ASSERT (scm_is_symbol (stream_name), stream_name, SCM_ARG2, FUNC_NAME);
  343. if (scm_is_eq (stream_name, scm_from_locale_symbol ("stdout")))
  344. {
  345. cd->is_stderr = 0;
  346. }
  347. else if (scm_is_eq (stream_name, scm_from_locale_symbol ("stderr")))
  348. {
  349. cd->is_stderr = 1;
  350. }
  351. else
  352. {
  353. guile_ssh_error1 (FUNC_NAME,
  354. "Wrong stream name. Possible names are: "
  355. "'stdout, 'stderr", stream_name);
  356. }
  357. return SCM_UNDEFINED;
  358. }
  359. #undef FUNC_NAME
  360. SCM_DEFINE (guile_ssh_channel_get_stream,
  361. "channel-get-stream", 1, 0, 0,
  362. (SCM channel),
  363. "\
  364. Get current stream name from CHANNEL. Throw `guile-ssh-error' on error.\n\
  365. Return one of the following symbols: \"stdout\", \"stderr\".\
  366. ")
  367. #define FUNC_NAME s_guile_ssh_channel_get_stream
  368. {
  369. struct channel_data *cd = _scm_to_channel_data (channel);
  370. GSSH_VALIDATE_OPEN_CHANNEL (channel, SCM_ARG1, FUNC_NAME);
  371. if (cd->is_stderr == 0)
  372. return scm_from_locale_symbol ("stdout");
  373. if (cd->is_stderr == 1)
  374. return scm_from_locale_symbol ("stderr");
  375. guile_ssh_error1 (FUNC_NAME, "Wrong stream.",
  376. scm_from_int (cd->is_stderr));
  377. return SCM_UNDEFINED;
  378. }
  379. #undef FUNC_NAME
  380. SCM_DEFINE (guile_ssh_channel_get_session,
  381. "channel-get-session", 1, 0, 0,
  382. (SCM channel),
  383. "\
  384. Get the session to which belongs the CHANNEL. Throw `guile-ssh-error' on an \n\
  385. error. Return the session.\
  386. ")
  387. #define FUNC_NAME s_guile_ssh_channel_get_session
  388. {
  389. struct channel_data *cd = _scm_to_channel_data (channel);
  390. GSSH_VALIDATE_CHANNEL_DATA (cd, channel, FUNC_NAME);
  391. return cd->session;
  392. }
  393. #undef FUNC_NAME
  394. /* Predicates */
  395. SCM_DEFINE (guile_ssh_channel_is_open_p, "channel-open?", 1, 0, 0,
  396. (SCM channel),
  397. "Return #t if channel CHANNEL is open, #f otherwise.")
  398. {
  399. struct channel_data *data = _scm_to_channel_data (channel);
  400. if (data && ssh_channel_is_open (data->ssh_channel))
  401. return SCM_BOOL_T;
  402. return SCM_BOOL_F;
  403. }
  404. SCM_GSSH_DEFINE (gssh_channel_send_eof, "%channel-send-eof",
  405. 1, (SCM channel))
  406. #define FUNC_NAME s_gssh_channel_send_eof
  407. {
  408. struct channel_data *cd = _scm_to_channel_data (channel);
  409. scm_t_bits pt_bits;
  410. int rc;
  411. GSSH_VALIDATE_CHANNEL_DATA (cd, channel, FUNC_NAME);
  412. pt_bits = SCM_CELL_TYPE (channel);
  413. if ((pt_bits & SCM_WRTNG) == 0)
  414. {
  415. guile_ssh_error1 (FUNC_NAME, "Could not send EOF on an input channel",
  416. channel);
  417. }
  418. rc = ssh_channel_send_eof (cd->ssh_channel);
  419. if (rc == SSH_ERROR)
  420. guile_ssh_error1 (FUNC_NAME, "Could not send EOF on a channel", channel);
  421. SCM_SET_CELL_TYPE (channel, pt_bits & ~SCM_WRTNG);
  422. return SCM_UNDEFINED;
  423. }
  424. #undef FUNC_NAME
  425. SCM_DEFINE (guile_ssh_channel_is_eof_p, "channel-eof?", 1, 0, 0,
  426. (SCM channel),
  427. "\
  428. Return #t if remote has set EOF, #f otherwise.\n\
  429. Throw `guile-ssh-error' if the channel has been closed and freed.\
  430. ")
  431. #define FUNC_NAME s_guile_ssh_channel_is_eof_p
  432. {
  433. struct channel_data *data = _scm_to_channel_data (channel);
  434. GSSH_VALIDATE_CHANNEL_DATA (data, channel, FUNC_NAME);
  435. return scm_from_bool (ssh_channel_is_eof (data->ssh_channel));
  436. }
  437. #undef FUNC_NAME
  438. /* Initialize channel related functions. */
  439. void
  440. init_channel_func (void)
  441. {
  442. #include "channel-func.x"
  443. }
  444. /* channel-func.c ends here */