kcontext.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <assert.h>
  5. #include <sys/types.h>
  6. #include <unistd.h>
  7. #include <faux/str.h>
  8. #include <faux/conv.h>
  9. #include <faux/list.h>
  10. #include <klish/khelper.h>
  11. #include <klish/kpargv.h>
  12. #include <klish/kcontext.h>
  13. #include <klish/kscheme.h>
  14. #include <klish/ksession.h>
  15. #include <klish/kaction.h>
  16. #include <klish/kscheme.h>
  17. #include <klish/kexec.h>
  18. struct kcontext_s {
  19. kcontext_type_e type;
  20. kscheme_t *scheme;
  21. int retcode;
  22. ksession_t *session;
  23. kplugin_t *plugin;
  24. kpargv_t *pargv;
  25. const kpargv_t *parent_pargv; // Parent
  26. const kcontext_t *parent_context; // Parent context (if available)
  27. const kexec_t *parent_exec; // Parent exec (if available)
  28. faux_list_node_t *action_iter; // Current action
  29. ksym_t *sym;
  30. int stdin;
  31. int stdout;
  32. int stderr;
  33. faux_buf_t *bufout; // Don't free. Just a link
  34. faux_buf_t *buferr; // Don't free. Just a link
  35. pid_t pid;
  36. bool_t done; // If all actions are done
  37. char *line; // Text command context belong to
  38. size_t pipeline_stage; // Index of current command within full pipeline
  39. bool_t is_last_pipeline_stage;
  40. };
  41. // Simple methods
  42. // Type
  43. KGET(context, kcontext_type_e, type);
  44. FAUX_HIDDEN KSET(context, kcontext_type_e, type);
  45. // Scheme
  46. KGET(context, kscheme_t *, scheme);
  47. KSET(context, kscheme_t *, scheme);
  48. // RetCode
  49. KGET(context, int, retcode);
  50. FAUX_HIDDEN KSET(context, int, retcode);
  51. // Plugin
  52. FAUX_HIDDEN KSET(context, kplugin_t *, plugin);
  53. // Sym
  54. KGET(context, ksym_t *, sym);
  55. FAUX_HIDDEN KSET(context, ksym_t *, sym);
  56. // Pargv
  57. KGET(context, kpargv_t *, pargv);
  58. FAUX_HIDDEN KSET(context, kpargv_t *, pargv);
  59. // Parent pargv
  60. KGET(context, const kpargv_t *, parent_pargv);
  61. FAUX_HIDDEN KSET(context, const kpargv_t *, parent_pargv);
  62. // Parent context
  63. KGET(context, const kcontext_t *, parent_context);
  64. FAUX_HIDDEN KSET(context, const kcontext_t *, parent_context);
  65. // Parent exec
  66. KGET(context, const kexec_t *, parent_exec);
  67. FAUX_HIDDEN KSET(context, const kexec_t *, parent_exec);
  68. // Action iterator
  69. KGET(context, faux_list_node_t *, action_iter);
  70. FAUX_HIDDEN KSET(context, faux_list_node_t *, action_iter);
  71. // STDIN
  72. KGET(context, int, stdin);
  73. FAUX_HIDDEN KSET(context, int, stdin);
  74. // STDOUT
  75. KGET(context, int, stdout);
  76. FAUX_HIDDEN KSET(context, int, stdout);
  77. // STDERR
  78. KGET(context, int, stderr);
  79. FAUX_HIDDEN KSET(context, int, stderr);
  80. // bufout
  81. KGET(context, faux_buf_t *, bufout);
  82. FAUX_HIDDEN KSET(context, faux_buf_t *, bufout);
  83. // buferr
  84. KGET(context, faux_buf_t *, buferr);
  85. FAUX_HIDDEN KSET(context, faux_buf_t *, buferr);
  86. // PID
  87. KGET(context, pid_t, pid);
  88. FAUX_HIDDEN KSET(context, pid_t, pid);
  89. // Session
  90. KGET(context, ksession_t *, session);
  91. FAUX_HIDDEN KSET(context, ksession_t *, session);
  92. // Done
  93. KGET_BOOL(context, done);
  94. FAUX_HIDDEN KSET_BOOL(context, done);
  95. // Line
  96. KGET_STR(context, line);
  97. FAUX_HIDDEN KSET_STR(context, line);
  98. // Pipeline stage
  99. KGET(context, size_t, pipeline_stage);
  100. FAUX_HIDDEN KSET(context, size_t, pipeline_stage);
  101. // Is last pipeline stage
  102. KGET(context, bool_t, is_last_pipeline_stage);
  103. FAUX_HIDDEN KSET(context, bool_t, is_last_pipeline_stage);
  104. kcontext_t *kcontext_new(kcontext_type_e type)
  105. {
  106. kcontext_t *context = NULL;
  107. context = faux_zmalloc(sizeof(*context));
  108. assert(context);
  109. if (!context)
  110. return NULL;
  111. // Initialize
  112. context->type = type;
  113. context->scheme = NULL;
  114. context->retcode = 0;
  115. context->plugin = NULL;
  116. context->pargv = NULL;
  117. context->parent_pargv = NULL; // Don't free
  118. context->parent_context = NULL; // Don't free
  119. context->parent_exec = NULL; // Don't free
  120. context->action_iter = NULL;
  121. context->sym = NULL;
  122. context->stdin = -1;
  123. context->stdout = -1;
  124. context->stderr = -1;
  125. context->bufout = NULL;
  126. context->buferr = NULL;
  127. context->pid = -1; // PID of currently executed ACTION
  128. context->session = NULL; // Don't free
  129. context->done = BOOL_FALSE;
  130. context->line = NULL;
  131. context->pipeline_stage = 0;
  132. context->is_last_pipeline_stage = BOOL_TRUE;
  133. return context;
  134. }
  135. void kcontext_free(kcontext_t *context)
  136. {
  137. if (!context)
  138. return;
  139. kpargv_free(context->pargv);
  140. if (context->stdin != -1)
  141. close(context->stdin);
  142. if (context->stdout != -1)
  143. close(context->stdout);
  144. if (context->stderr != -1)
  145. close(context->stderr);
  146. faux_str_free(context->line);
  147. faux_free(context);
  148. }
  149. kparg_t *kcontext_candidate_parg(const kcontext_t *context)
  150. {
  151. const kpargv_t *pargv = NULL;
  152. assert(context);
  153. if (!context)
  154. return NULL;
  155. pargv = kcontext_parent_pargv(context);
  156. if (!pargv)
  157. return NULL;
  158. return kpargv_candidate_parg(pargv);
  159. }
  160. const kentry_t *kcontext_candidate_entry(const kcontext_t *context)
  161. {
  162. kparg_t *parg = NULL;
  163. assert(context);
  164. if (!context)
  165. return NULL;
  166. parg = kcontext_candidate_parg(context);
  167. if (!parg)
  168. return NULL;
  169. return kparg_entry(parg);
  170. }
  171. const char *kcontext_candidate_value(const kcontext_t *context)
  172. {
  173. kparg_t *parg = NULL;
  174. assert(context);
  175. if (!context)
  176. return NULL;
  177. parg = kcontext_candidate_parg(context);
  178. if (!parg)
  179. return NULL;
  180. return kparg_value(parg);
  181. }
  182. const kaction_t *kcontext_action(const kcontext_t *context)
  183. {
  184. faux_list_node_t *node = NULL;
  185. assert(context);
  186. if (!context)
  187. return NULL;
  188. node = kcontext_action_iter(context);
  189. if (!node)
  190. return NULL;
  191. return (const kaction_t *)faux_list_data(node);
  192. }
  193. const char *kcontext_script(const kcontext_t *context)
  194. {
  195. const kaction_t *action = NULL;
  196. assert(context);
  197. if (!context)
  198. return NULL;
  199. action = kcontext_action(context);
  200. if (!action)
  201. return NULL;
  202. return kaction_script(action);
  203. }
  204. bool_t kcontext_named_udata_new(kcontext_t *context,
  205. const char *name, void *data, kudata_data_free_fn free_fn)
  206. {
  207. assert(context);
  208. if (!context)
  209. return BOOL_FALSE;
  210. return kscheme_named_udata_new(context->scheme, name, data, free_fn);
  211. }
  212. void *kcontext_named_udata(const kcontext_t *context, const char *name)
  213. {
  214. assert(context);
  215. if (!context)
  216. return NULL;
  217. return kscheme_named_udata(context->scheme, name);
  218. }
  219. void *kcontext_udata(const kcontext_t *context)
  220. {
  221. kplugin_t *plugin = NULL;
  222. assert(context);
  223. if (!context)
  224. return NULL;
  225. plugin = kcontext_plugin(context);
  226. if (!plugin)
  227. return NULL;
  228. return kplugin_udata(plugin);
  229. }
  230. const kentry_t *kcontext_command(const kcontext_t *context)
  231. {
  232. kpargv_t *pargv = NULL;
  233. assert(context);
  234. if (!context)
  235. return NULL;
  236. pargv = kcontext_pargv(context);
  237. if (!pargv)
  238. return NULL;
  239. return kpargv_command(pargv);
  240. }
  241. kplugin_t *kcontext_plugin(const kcontext_t *context)
  242. {
  243. const kaction_t *action = NULL;
  244. assert(context);
  245. if (!context)
  246. return NULL;
  247. // If plugin field is specified then return it. It is specified for
  248. // plugin's init() and fini() functions.
  249. if (context->plugin)
  250. return context->plugin;
  251. // If plugin is not explicitly specified then return parent plugin for
  252. // currently executed sym (ACTION structure contains it).
  253. action = kcontext_action(context);
  254. if (!action)
  255. return NULL;
  256. return kaction_plugin(action);
  257. }
  258. static int kcontext_vprintf(const kcontext_t *context,
  259. bool_t is_stderr, const char *fmt, va_list ap)
  260. {
  261. const kaction_t *action = NULL;
  262. const ksym_t *sym = NULL;
  263. faux_buf_t *buf = NULL;
  264. int rc = -1;
  265. FILE *f = NULL;
  266. if (!context)
  267. return -1;
  268. action = kcontext_action(context);
  269. if (!action)
  270. return -1;
  271. sym = kaction_sym(action);
  272. if (!sym)
  273. return -1;
  274. if (is_stderr) {
  275. buf = kcontext_buferr(context);
  276. f = stderr;
  277. } else {
  278. buf = kcontext_bufout(context);
  279. f = stdout;
  280. }
  281. // "Silent" output
  282. if (ksym_sync(sym) &&
  283. ksym_silent(sym) &&
  284. kcontext_is_last_pipeline_stage(context) &&
  285. buf) {
  286. char *line = NULL;
  287. line = faux_str_vsprintf(fmt, ap);
  288. rc = strlen(line);
  289. if (rc > 0)
  290. faux_buf_write(buf, line, rc);
  291. faux_str_free(line);
  292. } else {
  293. rc = vfprintf(f, fmt, ap);
  294. fflush(f);
  295. }
  296. return rc;
  297. }
  298. int kcontext_printf(const kcontext_t *context, const char *fmt, ...)
  299. {
  300. int rc = -1;
  301. va_list ap;
  302. va_start(ap, fmt);
  303. rc = kcontext_vprintf(context, BOOL_FALSE, fmt, ap);
  304. va_end(ap);
  305. return rc;
  306. }
  307. int kcontext_printf_err(const kcontext_t *context, const char *fmt, ...)
  308. {
  309. int rc = -1;
  310. va_list ap;
  311. va_start(ap, fmt);
  312. rc = kcontext_vprintf(context, BOOL_TRUE, fmt, ap);
  313. va_end(ap);
  314. return rc;
  315. }