Browse code

Initial commit

Dario Rodriguez authored on 02/06/2024 20:53:59
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,249 @@
1
+/*
2
+ * libexec.c
3
+ *
4
+ * Small wrapper for execve()
5
+ *
6
+ * (c) 2024 Dario Rodriguez <antartica@whereismybit.com>
7
+ * This file is in the public domain.
8
+ */
9
+
10
+#include <stdio.h>
11
+#include <stdlib.h>
12
+#include <unistd.h>
13
+#include <string.h>
14
+#include <signal.h>
15
+#include <sys/wait.h>
16
+#include <sys/ioctl.h>
17
+#ifndef FIONREAD
18
+#include <sys/filio.h>
19
+#endif
20
+#include <stdarg.h>
21
+#include "libexec.h"
22
+
23
+#ifndef RD
24
+#define RD 0
25
+#endif
26
+
27
+#ifndef WR
28
+#define WR 1
29
+#endif
30
+
31
+exec_t *
32
+exec_init(char *name, char *cmdwithstringsub, char **envp)
33
+{
34
+        exec_t *exec;
35
+        char *ptr;
36
+        int n;
37
+        if((exec=malloc(sizeof(exec_t)))==NULL)
38
+                return(NULL); /* insuf. mem. */
39
+        memset(exec,0,sizeof(exec_t));
40
+        exec->pid=-1;
41
+        exec->laststatus=-1;
42
+        exec->fdin=exec->fdout=exec->fderr=-1;
43
+        exec->envp=envp;
44
+        if(name!=NULL && (exec->name=strdup(name))==NULL) {
45
+                exec_free(exec),exec=NULL;
46
+                return(NULL); /* insuf. mem. */
47
+        }
48
+        for(ptr=strchr(cmdwithstringsub,'%')
49
+          ;ptr!=NULL && ptr[1]=='s'
50
+          ;ptr=strchr(ptr+1,'%')
51
+        ) {
52
+                for(n=0;(ptr-(n+1))>=cmdwithstringsub && ptr[-(n+1)]=='%';) {
53
+                        n++;
54
+                }
55
+                if(((n+1)%2)==0)
56
+                        continue; /* this '%' is escaped (duplicated) */
57
+                break; /* found the first %s */
58
+        }
59
+        exec->has_param=(ptr!=NULL)?1:0;
60
+        if(!(exec->has_param)) {
61
+                exec->prebuf=strdup(cmdwithstringsub);
62
+                exec->postbuf=strdup("");
63
+        } else {
64
+                if((exec->prebuf=malloc((ptr-cmdwithstringsub)+1))!=NULL) {
65
+                        memcpy(exec->prebuf,cmdwithstringsub,ptr-cmdwithstringsub);
66
+                        exec->prebuf[ptr-cmdwithstringsub]='\0';
67
+                }
68
+                exec->postbuf=strdup(ptr+2);
69
+        }
70
+        if(exec->prebuf==NULL || exec->postbuf==NULL) {
71
+                exec_free(exec),exec=NULL;
72
+                return(NULL); /* insuf. mem. */
73
+        }
74
+        return(exec);
75
+}
76
+
77
+void
78
+exec_free(exec_t *exec)
79
+{
80
+        if(exec==NULL)
81
+                return;
82
+        if(exec->pid!=-1)
83
+                exec_close(exec);
84
+        if(exec->name!=NULL)
85
+                free(exec->name),exec->name=NULL;
86
+        if(exec->prebuf!=NULL)
87
+                free(exec->prebuf),exec->prebuf=NULL;
88
+        if(exec->postbuf!=NULL)
89
+                free(exec->postbuf),exec->postbuf=NULL;
90
+        if(exec->fdin!=-1)
91
+                close(exec->fdin),exec->fdin=-1;
92
+        if(exec->fdout!=-1)
93
+                close(exec->fdout),exec->fdout=-1;
94
+        if(exec->fderr!=-1)
95
+                close(exec->fderr),exec->fderr=-1;
96
+        free(exec),exec=NULL;
97
+        return;
98
+}
99
+
100
+int
101
+exec_open(exec_t *exec, char *stringsub)
102
+{
103
+        char cmd[1024];
104
+        int i,n;
105
+        int pipein[2],pipeout[2],pipeerr[2];
106
+        int in_error;
107
+        if(exec==NULL)
108
+                return(-1); /* sanity check error */
109
+        if(exec->pid!=-1)
110
+                return(-1); /* there is already a running child */
111
+        snprintf(cmd,sizeof(cmd),"%s%s%s",exec->prebuf,(exec->has_param && stringsub!=NULL)?stringsub:"",exec->postbuf);
112
+        cmd[sizeof(cmd)-1]='\0';
113
+        pipein[RD]=pipein[WR]=-1;
114
+        pipeout[RD]=pipeout[WR]=-1;
115
+        pipeerr[RD]=pipeerr[WR]=-1;
116
+        in_error=0;
117
+        if(pipe(pipein)==-1 || pipe(pipeout)==-1 || pipe(pipeerr)==-1)
118
+                in_error=1;
119
+        if(in_error==0 && (exec->pid=fork())==0) {
120
+                char *params[1024];
121
+                int usedparams;
122
+                char *ptr,*end,*realend;
123
+                char endchar;
124
+                realend=cmd+strlen(cmd);
125
+                for(usedparams=0,ptr=cmd
126
+                  ;ptr!=realend && usedparams<((sizeof(params)/sizeof(params[0]))-1)
127
+                  ;
128
+                ) {
129
+                        endchar=(ptr[0]=='\"')?'\"':' ';
130
+                        ptr+=(endchar=='\"')?1:0;
131
+                        params[usedparams++]=ptr;
132
+                        for(end=strchr(ptr,endchar)
133
+                          ;end!=NULL
134
+                          ;end=strchr(end+1,endchar)
135
+                        ) {
136
+                                for(n=0;(end-(n+1))>=ptr && end[-(n+1)]=='\\';) {
137
+                                        n++;
138
+                                }
139
+                                if((n%2)==1)
140
+                                        continue; /* this '\"' or ' ' is escaped */
141
+                                break; /* found the first unescaped '\"' or ' ' */
142
+                        }
143
+                        end=(end==NULL)?realend:end;
144
+                        *end='\0';
145
+                        ptr=(end<realend)?end+1:realend;
146
+                        if(endchar=='\"' && ptr[0]==' ')
147
+                                ptr++;
148
+                }
149
+                params[usedparams]=NULL;
150
+                if(usedparams==0)
151
+                        exit(1); /* nothing to execute */
152
+                dup2(pipein[RD],0);
153
+                dup2(pipeout[WR],1);
154
+                dup2(pipeerr[WR],2);
155
+                for(i=3;i<1024;i++)
156
+                        close(i);
157
+                execve(params[0],params,exec->envp);
158
+                exit(2); /* couldn't execve */
159
+        } else if(in_error==0 && exec->pid>0) {
160
+                close(pipein[RD]),pipein[RD]=-1;
161
+                close(pipeout[WR]),pipeout[WR]=-1;
162
+                close(pipeerr[WR]),pipeerr[WR]=-1;
163
+                exec->fdin=pipein[WR],pipein[WR]=-1;
164
+                exec->fdout=pipeout[RD],pipeout[RD]=-1;
165
+                exec->fderr=pipeerr[RD],pipeerr[RD]=-1;
166
+        } else {
167
+                in_error=1;
168
+        }
169
+        if(in_error) {
170
+                int *curfd[]={pipein,pipein+1,pipeout,pipeout+1,pipeerr,pipeerr+1};
171
+                for(i=0;i<(sizeof(curfd)/sizeof(curfd[0]));i++) {
172
+                        if(*(curfd[i])!=-1)
173
+                                close(*(curfd[i])),*(curfd[i])=-1;
174
+                }
175
+                return(-1); /* was in error */
176
+        }
177
+        return(0);
178
+}
179
+
180
+int
181
+exec_close(exec_t *exec)
182
+{
183
+        if(exec==NULL)
184
+                return(-1); /* sanity check failed */
185
+        if(exec->pid==-1)
186
+                return(-1); /* nothing to do as child is not started */
187
+        kill(exec->pid,SIGTERM);
188
+        return(0);
189
+}
190
+
191
+int
192
+exec_reap(exec_t *exec1, /* exec_t *exec2, */ ...)
193
+{
194
+        int status;
195
+        int flag_reaped;
196
+        exec_t *exec;
197
+        va_list ap;
198
+        flag_reaped=0;
199
+        va_start(ap, exec1);
200
+        for(exec=exec1;exec!=NULL;exec=va_arg(ap,exec_t *)) {
201
+                if(exec->pid==-1)
202
+                        continue;
203
+                if(waitpid(exec->pid,&status,WNOHANG)==exec->pid) {
204
+                        exec->pid=-1;
205
+                        exec->laststatus=status;
206
+                        close(exec->fdin),exec->fdin=-1;
207
+                        close(exec->fdout),exec->fdout=-1;
208
+                        close(exec->fderr),exec->fderr=-1;
209
+                        flag_reaped=1;
210
+                        continue;
211
+                }
212
+        }
213
+        va_end(ap);
214
+        return((flag_reaped==0)?-1:0); /* -1: no child has exited, 0: at least one child exited */
215
+}
216
+
217
+int
218
+executil_installsignal(int sig, void (*f)(int))
219
+{
220
+        struct sigaction sa;
221
+        sa.sa_handler=f;
222
+        sigemptyset(&sa.sa_mask);
223
+        sa.sa_flags=0;
224
+        return(sigaction(sig,&sa,NULL));
225
+}
226
+
227
+int
228
+executil_queued(int fd)
229
+{
230
+        int n;
231
+        if(ioctl(fd,FIONREAD,&n)!=0)
232
+                return(-1);
233
+        return(n);
234
+}
235
+
236
+exec_t *
237
+executil_fd2exec(int fd, exec_t *exec1, /* exec_t *exec2, */ ...)
238
+{
239
+        exec_t *exec;
240
+        va_list ap;
241
+        va_start(ap, exec1);
242
+        for(exec=exec1;exec!=NULL;exec=va_arg(ap,exec_t *)) {
243
+                if(exec->fdin==fd || exec->fdout==fd || exec->fderr==fd)
244
+                        break;
245
+        }
246
+        va_end(ap);
247
+        return(exec);
248
+}
249
+