1 /*
2 
3   Copyright (c) 2009-2013 uim Project https://github.com/uim/uim
4 
5   All rights reserved.
6 
7   Redistribution and use in source and binary forms, with or without
8   modification, are permitted provided that the following conditions
9   are met:
10 
11   1. Redistributions of source code must retain the above copyright
12      notice, this list of conditions and the following disclaimer.
13   2. Redistributions in binary form must reproduce the above copyright
14      notice, this list of conditions and the following disclaimer in the
15      documentation and/or other materials provided with the distribution.
16   3. Neither the name of authors nor the names of its contributors
17      may be used to endorse or promote products derived from this software
18      without specific prior written permission.
19 
20   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30   SUCH DAMAGE.
31 
32 */
33 
34 #include <config.h>
35 
36 #include <stdio.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/wait.h>
40 
41 #include "uim.h"
42 #include "uim-internal.h"
43 #include "uim-scm.h"
44 #include "uim-scm-abbrev.h"
45 #include "uim-posix.h"
46 #include "uim-notify.h"
47 #include "gettext.h"
48 #include "dynlib.h"
49 
50 typedef struct {
51   int flag;
52   char *arg;
53 } opt_args;
54 
55 static uim_lisp
make_arg_cons(const opt_args * arg)56 make_arg_cons(const opt_args *arg)
57 {
58   return CONS(MAKE_SYM(arg->arg), MAKE_INT(arg->flag));
59 }
60 
61 static uim_lisp
make_arg_list(const opt_args * list)62 make_arg_list(const opt_args *list)
63 {
64   uim_lisp ret_;
65   int i = 0;
66 
67   ret_ = uim_scm_null();
68   while (list[i].arg != 0) {
69     ret_ = CONS((uim_lisp)uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)make_arg_cons,
70 							   (void *)&list[i]), ret_);
71     i++;
72   }
73   return ret_;
74 }
75 
76 static uim_lisp
c_current_process_id(void)77 c_current_process_id(void)
78 {
79   return MAKE_INT(getpid());
80 }
81 static uim_lisp
c_parent_process_id(void)82 c_parent_process_id(void)
83 {
84   return MAKE_INT(getppid());
85 }
86 static uim_lisp
c_process_fork(void)87 c_process_fork(void)
88 {
89   return MAKE_INT(fork());
90 }
91 static uim_lisp
c__exit(uim_lisp status_)92 c__exit(uim_lisp status_)
93 {
94   _exit(C_INT(status_));
95   return uim_scm_t();
96 }
97 
98 const static opt_args waitpid_options[] = {
99 #ifdef WCONTINUED
100   { WCONTINUED, "$WCONTINUED" },
101 #endif
102 #ifdef WNOHANG
103   { WNOHANG,    "$WNOHANG" },
104 #endif
105 #ifdef WUNTRACED
106   { WUNTRACED,  "$WUNTRACED" },
107 #endif
108   { 0, 0 }
109 };
110 static uim_lisp uim_lisp_process_waitpid_options;
111 static uim_lisp
c_process_waitpid_options(void)112 c_process_waitpid_options(void)
113 {
114   return uim_lisp_process_waitpid_options;
115 }
116 static uim_lisp
c_process_waitpid(uim_lisp pid_,uim_lisp options_)117 c_process_waitpid(uim_lisp pid_, uim_lisp options_)
118 {
119   uim_lisp ret_ = uim_scm_null();
120   int status;
121 
122   ret_ = MAKE_INT(waitpid(C_INT(pid_), &status, C_INT(options_)));
123   if (WIFEXITED(status))
124     return LIST5(ret_, uim_scm_t(), uim_scm_f(), uim_scm_f(), MAKE_INT(WEXITSTATUS(status)));
125   else if (WIFSIGNALED(status))
126     return LIST5(ret_, uim_scm_f(), uim_scm_t(), uim_scm_f(), MAKE_INT(WTERMSIG(status)));
127 #ifdef WIFSTOPPED
128   else if (WIFSTOPPED(status))
129     return LIST5(ret_, uim_scm_f(), uim_scm_f(), uim_scm_t(), MAKE_INT(WSTOPSIG(status)));
130 #endif
131 
132   return LIST5(ret_, uim_scm_f(), uim_scm_f(), uim_scm_f(), MAKE_INT(status));
133 }
134 
135 static uim_lisp
c_daemon(uim_lisp nochdir_,uim_lisp noclose_)136 c_daemon(uim_lisp nochdir_, uim_lisp noclose_)
137 {
138   return MAKE_INT(daemon(C_BOOL(nochdir_), C_BOOL(noclose_)));
139 }
140 
141 static uim_lisp
c_execve(uim_lisp file_,uim_lisp argv_,uim_lisp envp_)142 c_execve(uim_lisp file_, uim_lisp argv_, uim_lisp envp_)
143 {
144   char **argv;
145   char **envp;
146   int i;
147   int argv_len = uim_scm_length(argv_);
148   int envp_len;
149   uim_lisp ret_;
150 
151   if (argv_len < 1)
152     return uim_scm_f();
153 
154   argv = uim_malloc(sizeof(char *) * (argv_len + 1));
155 
156   for (i = 0; i < argv_len; i++) {
157     argv[i] = uim_strdup(REFER_C_STR(CAR(argv_)));
158     argv_ = CDR(argv_);
159   }
160   argv[argv_len] = NULL;
161 
162   if (FALSEP(envp_) || NULLP(envp_)) {
163     envp_len = 0;
164     envp = NULL;
165   } else {
166     envp_len = uim_scm_length(envp_);
167     envp = uim_malloc(sizeof(char *) * (envp_len + 1));
168 
169     for (i = 0; i < envp_len; i++) {
170       uim_lisp env_ = CAR(envp_);
171 
172       uim_asprintf(&envp[i], "%s=%s", REFER_C_STR(CAR(env_)), REFER_C_STR(CDR(env_)));
173       envp_ = CDR(envp_);
174     }
175     envp[envp_len] = NULL;
176   }
177 
178   ret_ = MAKE_INT(execve(REFER_C_STR(file_), argv, envp));
179 
180   for (i = 0; i < argv_len; i++)
181     free(argv[i]);
182   free(argv);
183 
184   for (i = 0; i < envp_len; i++)
185     free(envp[i]);
186   free(envp);
187 
188   return ret_;
189 }
190 
191 static uim_lisp
c_execvp(uim_lisp file_,uim_lisp argv_)192 c_execvp(uim_lisp file_, uim_lisp argv_)
193 {
194   char **argv;
195   int i;
196   int len = uim_scm_length(argv_);
197   uim_lisp ret_;
198 
199   if (len < 1)
200     return uim_scm_f();
201 
202   argv = uim_malloc(sizeof(char *) * (len + 1));
203 
204   for (i = 0; i < len; i++) {
205     argv[i] = uim_strdup(REFER_C_STR(CAR(argv_)));
206     argv_ = CDR(argv_);
207   }
208   argv[len] = NULL;
209 
210   ret_ = MAKE_INT(execvp(REFER_C_STR(file_), argv));
211 
212   for (i = 0; i < len; i++)
213     free(argv[i]);
214   free(argv);
215 
216   return ret_;
217 }
218 
219 void
uim_plugin_instance_init(void)220 uim_plugin_instance_init(void)
221 {
222   uim_scm_init_proc0("current-process-id", c_current_process_id);
223   uim_scm_init_proc0("parent-process-id",  c_parent_process_id);
224   uim_scm_init_proc0("process-fork", c_process_fork);
225   uim_scm_init_proc1("_exit", c__exit);
226   uim_scm_init_proc2("process-waitpid", c_process_waitpid);
227   uim_scm_init_proc0("process-waitpid-options?", c_process_waitpid_options);
228   uim_lisp_process_waitpid_options = make_arg_list(waitpid_options);
229   uim_scm_gc_protect(&uim_lisp_process_waitpid_options);
230   uim_scm_eval_c_string("(define process-waitpid-options-alist (process-waitpid-options?))");
231 
232   uim_scm_init_proc2("daemon", c_daemon);
233 
234   uim_scm_init_proc3("execve", c_execve);
235   uim_scm_init_proc2("execvp", c_execvp);
236 }
237 
238 void
uim_plugin_instance_quit(void)239 uim_plugin_instance_quit(void)
240 {
241   uim_scm_gc_unprotect(&uim_lisp_process_waitpid_options);
242 }
243