Skip to content

Commit 30359d1

Browse files
committed
v.1.4 PRE 0: new clean API
new system_safe, system_execsq* tnx Luca Tagliavini
1 parent 2f3f79c commit 30359d1

14 files changed

+304
-232
lines changed

CMakeLists.txt

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
cmake_minimum_required(VERSION 3.12)
22
project(s2argv-execs
3-
VERSION 1.3
3+
VERSION 1.4
44
DESCRIPTION "execute a file taking its arguments from a string"
55
HOMEPAGE_URL "https://github.com/rd235/s2argv-execs"
66
LANGUAGES C)
77

8-
set(LIB_VERSION 0.9.0)
9-
set(LIB_SOVERSION 0)
8+
set(LIB_VERSION 1.4.0)
9+
set(LIB_SOVERSION 1)
1010

1111
include(GNUInstallDirs)
1212
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -pedantic")

execs.c

+38-23
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <string.h>
2222
#include <stdlib.h>
2323
#include <unistd.h>
24+
#include <errno.h>
2425
#include <execs.h>
2526

2627
//char *sn[] = { "END", "SPACE", "CHAR", "SGLQ", "DBLQ", "ESCAPE", "SEMIC", "VAR", "ESCVAR", "DBLESC" };
@@ -44,7 +45,7 @@
4445

4546
/* This is the FSA used to get the lexical items of the command line */
4647

47-
char nextstate[NSTATES][NSTATES-1]= {
48+
static char nextstate[NSTATES][NSTATES-1]= {
4849
{END, 0, 0, 0, 0, 0, 0, 0}, // END
4950
{END,SPACE,CHAR,SGLQ,DBLQ,ESCAPE,SEMIC, VAR}, // SPACE
5051
{END,SPACE,CHAR,SGLQ,DBLQ,ESCAPE,SEMIC,CHAR}, // CHAR
@@ -56,7 +57,7 @@ char nextstate[NSTATES][NSTATES-1]= {
5657
{END, VAR, VAR, VAR, VAR, VAR, VAR, VAR}, // ESCVAR
5758
{END, DBLQ,DBLQ,DBLQ,DBLQ, DBLQ, DBLQ,DBLQ}}; // DBLESC
5859

59-
char action[NSTATES][NSTATES-1]= {
60+
static char action[NSTATES][NSTATES-1]= {
6061
{ENDCMD| 0, 0, 0, 0, 0, 0, 0, 0}, //END
6162
{ENDCMD| 0, 0,NEWARG|CHCOPY,NEWARG,NEWARG,NEWARG, ENDCMD,NEWARG}, //SPACE
6263
{ENDCMD|ENDARG,ENDARG, CHCOPY, 0, 0, 0,ENDCMD|ENDARG, 0}, //CHAR
@@ -68,16 +69,11 @@ char action[NSTATES][NSTATES-1]= {
6869
{ENDCMD|ENDVAR,CHCOPY, CHCOPY,CHCOPY,CHCOPY,CHCOPY, CHCOPY,CHCOPY}, //ESCVAR
6970
{ENDCMD|ENDARG,CHCOPY, CHCOPY,CHCOPY,CHCOPY,CHCOPY, CHCOPY,CHCOPY}}; //DBLESC
7071

71-
char *getvar_null(const char *name);
72-
s2argv_getvar_t s2argv_getvar=getvar_null;
72+
s2argv_getvar_t s2argv_getvar=NULL;
7373
int (* execs_fork_security)(void *execs_fork_security_arg);
7474
void *execs_fork_security_arg;
7575

76-
char *getvar_null(const char *name) {
77-
return "";
78-
}
79-
80-
static int args_fsa(const char *args, char **argv, char *buf)
76+
static int args_fsa(const char *args, char **argv, char *buf, int flags)
8177
{
8278
int state=SPACE;
8379
int argc=0;
@@ -130,16 +126,22 @@ static int args_fsa(const char *args, char **argv, char *buf)
130126
*argv="";
131127
argv++;
132128
}
133-
if (action[state][this] & ENDCMD)
129+
if (action[state][this] & ENDCMD)
134130
*argv++=0;
135-
}
131+
}
136132
if (action[state][this] & (ENDARG|ENDVAR))
137133
argc++;
138134
if (action[state][this] & ENDCMD)
139135
argc++;
140136
//printf("%c %s+%s=%s %x\n",*args,sn[state],sn[this],sn[nextstate[state][this]],action[state][this]);
141137
//printf("%s %d->%d\n",args,state,nextstate[state][this]);
142138
state=nextstate[state][this];
139+
switch (state) {
140+
case VAR: if (flags & EXECS_NOVAR) return errno = EINVAL, -1;
141+
break;
142+
case SEMIC: if (flags & EXECS_NOSEQ) return errno = EINVAL, -1;
143+
break;
144+
}
143145
}
144146
if (argv)
145147
*argv=0;
@@ -150,15 +152,15 @@ static int args_fsa(const char *args, char **argv, char *buf)
150152

151153
char **s2argv(const char *args)
152154
{
153-
int argc=args_fsa(args,NULL,NULL);
155+
int argc=args_fsa(args,NULL,NULL,0);
154156
char buf[strlen(args)+1];
155157
char **argv=calloc(argc+1,sizeof(char *));
156158
if (argv) {
157159
int i;
158-
args_fsa(args,argv,buf);
160+
args_fsa(args,argv,buf,0);
159161
for (i=0; i<argc+1; i++)
160162
argv[i]=argv[i]?strdup(argv[i]):0;
161-
/* for (i=0; i<argc+1; i++)
163+
/* for (i=0; i<argc+1; i++)
162164
printf("%d %s\n",i,argv[i]); */
163165
}
164166
return argv;
@@ -189,13 +191,16 @@ size_t s2argc(char **argv) {
189191
return argc;
190192
}
191193

192-
int s2multiargv(const char *args, int (*f)(char **argv, void *opaque), void *opaque)
194+
int s2multiargv(const char *args,
195+
int (*f)(char **argv, void *opaque), void *opaque, int flags)
193196
{
194-
int argc=args_fsa(args,NULL,NULL);
197+
int argc=args_fsa(args,NULL,NULL,flags);
198+
if (argc < 0)
199+
return -1;
195200
char *argv[argc+1];
196201
char buf[strlen(args)+1];
197202
char **thisargv=argv;
198-
args_fsa(args,argv,buf);
203+
args_fsa(args,argv,buf,0);
199204
int rv=0;
200205
while (*thisargv && rv==0) {
201206
rv=f(thisargv, opaque);
@@ -206,13 +211,23 @@ int s2multiargv(const char *args, int (*f)(char **argv, void *opaque), void *opa
206211
}
207212
#endif
208213

209-
int execs_common(const char *path, const char *args, char *const envp[], char *buf)
214+
int _execs_common(const char *path, const char *args, char *const envp[], char *buf, int flags)
210215
{
211-
int argc=args_fsa(args,NULL,NULL);
216+
int argc=args_fsa(args,NULL,NULL,flags);
212217
char *argv[argc+1];
213-
args_fsa(args,argv,buf);
214-
if (path)
215-
return execve(path, argv, envp);
216-
else
218+
char tmpbuf[(buf == NULL) ? strlen(args) + 1 : 0];
219+
if (buf == NULL) buf = tmpbuf;
220+
if (args_fsa(args,argv,buf,flags) < 0)
221+
return -1;
222+
if (path) {
223+
if (*path)
224+
return execve(path, argv, envp);
225+
else {
226+
if (argv[0][0] == '/')
227+
return execvpe(argv[0], argv, envp);
228+
else
229+
return errno = EACCES, -1;
230+
}
231+
} else
217232
return execvpe(argv[0], argv, envp);
218233
}

execs.h

+62-56
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@
2525
#include <string.h>
2626
#include <sys/wait.h>
2727

28+
#define EXECS_SOVERSION 1
29+
2830
extern char **environ;
2931

3032
/* This header file declares all the functions defined in
31-
the libexecs and libeexecs libraries.
32-
libeexecs is a minimal subset of the libexecs library designed
33-
for embedded systems with strict memory requirements.
33+
the libexecs and libeexecs libraries.
34+
libeexecs is a minimal subset of the libexecs library designed
35+
for embedded systems with strict memory requirements.
3436
It implements only the execs* functions. Programs using libexecs
3537
can also use the esystem (a.k.a. system_eexecsp) inline function */
3638

@@ -45,27 +47,26 @@ extern void *execs_fork_security_arg;
4547
/* execs is like execv: argv is computed by parsing args */
4648
/* execsp is like execvp: argv is computed by parsing args,
4749
argv[0] is the executable file to be searched for along $PATH */
48-
/* execse and execspe permit the specification of the environment
50+
/* execse and execspe permit the specification of the environment
4951
(as in execve or execvpe) */
5052
/* execs, execse, execsp and execspe do not require dynamic allocation *but*
5153
require an extra copy of args on the stack */
52-
/* in all eexecs* functions, the string args is modified
54+
/* in all eexecs* functions, the string args is modified
5355
(no extra copies on the stack, args is parsed on itself): */
54-
int execs_common(const char *path, const char *args, char *const envp[], char *buf);
56+
#define EXECS_NOSEQ 0x1
57+
#define EXECS_NOVAR 0x2
5558

56-
static inline int execse(const char *path, const char *args, char *const envp[]) {
57-
char buf[strlen(args)+1];
58-
return execs_common(path, args, envp, buf);
59-
}
59+
int _execs_common(const char *path, const char *args, char *const envp[], char *buf, int flags);
6060

61-
#define execs(path, args) execse((path),(args),environ)
62-
#define execsp(args) execse(NULL,(args),environ)
63-
#define execspe(args,env) execse(NULL,(args),(env))
61+
#define execs(path, args) _execs_common((path),(args),environ,NULL,EXECS_NOSEQ)
62+
#define execse(path, args, env) _execs_common((path),(args),(env),NULL,EXECS_NOSEQ)
63+
#define execsp(args) _execs_common(NULL,(args),environ,NULL,EXECS_NOSEQ)
64+
#define execspe(args,env) _execs_common(NULL,(args),(env),NULL,EXECS_NOSEQ)
6465

65-
#define eexecs(path, args) execs_common((path),(args),environ,(args))
66-
#define eexecse(path, args, env) execs_common((path),(args),(env),(args))
67-
#define eexecsp(args) execs_common(NULL,(args),environ,(args))
68-
#define eexecspe(args,env) execs_common(NULL,(args),(env),(args))
66+
#define eexecs(path, args) _execs_common((path),(args),environ,(args),EXECS_NOSEQ)
67+
#define eexecse(path, args, env) _execs_common((path),(args),(env),(args),EXECS_NOSEQ)
68+
#define eexecsp(args) _execs_common(NULL,(args),environ,(args),EXECS_NOSEQ)
69+
#define eexecspe(args,env) _execs_common(NULL,(args),(env),(args),EXECS_NOSEQ)
6970

7071
static inline int system_eexecsp(const char *command) {
7172
int status;
@@ -75,7 +76,7 @@ static inline int system_eexecsp(const char *command) {
7576
return -1;
7677
case 0:
7778
if (__builtin_expect(execs_fork_security == NULL || execs_fork_security(execs_fork_security_arg) == 0, 1))
78-
execs_common(NULL, (char *) command, environ, (char *) command);
79+
_execs_common(NULL, (char *) command, environ, (char *) command, 0);
7980
_exit(127);
8081
default:
8182
waitpid(pid,&status,0);
@@ -87,52 +88,60 @@ static inline int system_eexecsp(const char *command) {
8788

8889
/******** library functions defined in libexecs only (not in libeexec) ********/
8990

90-
/* system_nosh is an "almost" drop in replacement for system(3).
91-
it does not start a shell but it parses the arguments and
92-
runs the command */
93-
/* system_execs is similar to system_nosh but instead of searching the
94-
executable file along the directories listed in $PATH it starts
95-
the program whose path has been passed as its first arg. */
96-
int system_execsr(const char *path, const char *command, int redir[3]);
91+
int _system_common(const char *path, const char *command, int redir[3], int flags);
9792

98-
#define system_nosh(cmd) system_execsr(NULL,(cmd),NULL)
93+
/* system_safe requires the absolute path of the command */
94+
/* system_execs executes the program whose path has been passed as its first arg. */
95+
#define system_safe(cmd) _system_common("",(cmd),NULL,EXECS_NOSEQ | EXECS_NOVAR)
9996

100-
#define system_execsrp(cmd,redir) system_execsr(NULL,(cmd),(redir))
101-
#define system_execsra(cmd,redir) system_execsr("",(cmd),(redir))
102-
#define system_execs(path,cmd) system_execsr((path),(cmd),NULL)
103-
#define system_execsp(cmd) system_execsr(NULL,(cmd),NULL)
104-
#define system_execsa(cmd) system_execsr("",(cmd),NULL)
97+
#define system_execs(path,cmd) _system_common((path),(cmd),NULL,EXECS_NOSEQ)
98+
#define system_execsp(cmd) _system_common(NULL,(cmd),NULL,EXECS_NOSEQ)
99+
#define system_execsa(cmd) _system_common("",(cmd),NULL,EXECS_NOSEQ)
100+
#define system_execsr(path,command,redir) _system_common((path),(cmd),(redir),EXECS_NOSEQ)
101+
#define system_execsrp(cmd,redir) _system_common(NULL,(cmd),(redir),EXECS_NOSEQ)
102+
#define system_execsra(cmd,redir) _system_common("",(cmd),(redir),EXECS_NOSEQ)
105103

106-
/* popen_nosh is an "almost" drop in replacement for popen(3),
107-
and pclose_nosh is its counterpart for pclose(3). */
104+
/* system_nosh is an "almost" drop in replacement for system(3).
105+
it does not start a shell but it parses the arguments and
106+
runs the command */
107+
/* system_execsq* support colon separated sequences of commands */
108+
#define system_nosh(cmd) _system_common(NULL,(cmd),NULL,0)
109+
#define system_execsqp(cmd) _system_common(NULL,(cmd),NULL,0)
110+
#define system_execsqa(cmd) _system_common("",(cmd),NULL,0)
111+
#define system_execsqrp(cmd,redir) _system_common(NULL,(cmd),(redir),0)
112+
#define system_execsqra(cmd,redir) _system_common("",(cmd),(redir),0)
113+
114+
FILE *_popen_common(const char *path, const char *command, const char *type, int flags);
108115
/* popen_execs/pclose_execs do not use $PATH to search the executable file*/
109-
FILE *popen_execs(const char *path, const char *command, const char *type);
110116
int pclose_execs(FILE *stream);
111117

112-
#define popen_nosh(cmd, type) popen_execs(NULL, (cmd), (type))
113-
#define pclose_nosh(stream) pclose_execs(stream)
118+
/* popen_nosh is an "almost" drop in replacement for popen(3),
119+
and pclose_nosh is its counterpart for pclose(3). */
120+
#define popen_nosh(cmd, type) _popen_common(NULL, (cmd), (type))
121+
#define pclose_nosh(stream) _popen_common(stream)
114122

115-
#define popen_execsp(cmd, type) popen_execs(NULL, (cmd), (type))
123+
#define popen_execs(path, cmd, type) _popen_common(path, (cmd), (type), EXECS_NOSEQ)
124+
#define popen_execsp(cmd, type) _popen_common(NULL, (cmd), (type), EXECS_NOSEQ)
116125
#define pclose_execsp(stream) pclose_execs(stream)
117126

118127
/* run a command in coprocessing mode */
119-
pid_t coprocess_common(const char *path, const char *command,
120-
char *const argv[], char *const envp[], int pipefd[2]);
128+
pid_t _coprocess_common(const char *path, const char *command,
129+
char *const argv[], char *const envp[], int pipefd[2], int flags);
121130

122-
#define coprocv(path, argv, pfd) coprocess_common((path),NULL,(argv), environ, pfd)
123-
#define coprocve(path, argv, env, pfd) coprocess_common((path),NULL,(argv), (env), pfd)
124-
#define coprocvp(file, argv, pfd) coprocess_common(NULL,(file),(argv), environ, pfd)
125-
#define coprocvpe(file, argv, env, pfd) coprocess_common(NULL,(file),(argv), (env), pfd)
131+
#define coprocv(path, argv, pfd) _coprocess_common((path),NULL,(argv), environ, pfd)
132+
#define coprocve(path, argv, env, pfd) _coprocess_common((path),NULL,(argv), (env), pfd)
133+
#define coprocvp(file, argv, pfd) _coprocess_common(NULL,(file),(argv), environ, pfd)
134+
#define coprocvpe(file, argv, env, pfd) _coprocess_common(NULL,(file),(argv), (env), pfd)
126135

127-
#define coprocs(path, cmd, pfd) coprocess_common((path),(cmd),NULL, environ, pfd)
128-
#define coprocse(path, cmd, env, pfd) coprocess_common((path),(cmd),NULL, (env), pfd)
129-
#define coprocsp(cmd, pfd) coprocess_common(NULL,(cmd),NULL, environ, pfd)
130-
#define coprocspe(cmd, env, pfd) coprocess_common(NULL,(cmd),NULL, (env), pfd)
136+
#define coprocs(path, cmd, pfd) _coprocess_common((path),(cmd),NULL, environ, pfd)
137+
#define coprocse(path, cmd, env, pfd) _coprocess_common((path),(cmd),NULL, (env), pfd)
138+
#define coprocsp(cmd, pfd) _coprocess_common(NULL,(cmd),NULL, environ, pfd)
139+
#define coprocspe(cmd, env, pfd) _coprocess_common(NULL,(cmd),NULL, (env), pfd)
131140

132141
/* Low level argc management functions */
133142

134-
/* s2argv parses args.
135-
It allocates, initializes and returns an argv array, ready for execv.
143+
/* s2argv parses args.
144+
It allocates, initializes and returns an argv array, ready for execv.
136145
s2argv is able to parse several commands separated by semicolons (;).
137146
The return value is the sequence of all the corresponding argv
138147
(each one has a NULL element as its terminator) and one further
@@ -145,7 +154,7 @@ char **s2argv(const char *args);
145154
/* s2argv_free deallocates an argv returned by s2argv */
146155
void s2argv_free(char **argv);
147156

148-
/* number of elements of argv */
157+
/* the sum of s2argc for all commands, including the NULLs */
149158
size_t s2argvlen(char **argv);
150159

151160
/* argc of the (first) command */
@@ -155,16 +164,13 @@ size_t s2argc(char **argv);
155164
/* var definition function (e.g. s2argv_getvar=getenv)*/
156165
typedef char * (* s2argv_getvar_t) (const char *name);
157166
extern s2argv_getvar_t s2argv_getvar;
158-
/* getvar_null is the deafult value for s2argv_getvar,
159-
it always returns an empty string for any variable name */
160-
char *getvar_null(const char *name);
161-
162167

163168
/* multi argv. Args can contain several commands semicolon (;) separated.
164169
This function parses args and calls f for each command/argv in args.
165170
If f returns 0 s2multiargv calls f for the following argv, otherwise
166-
returns the non-zero value.
171+
returns the non-zero value.
167172
*/
168-
int s2multiargv(const char *args, int (*f)(char **argv, void *opaque), void *opaque);
173+
int s2multiargv(const char *args,
174+
int (*f)(char **argv, void *opaque), void *opaque, int flags);
169175

170176
#endif

execstest.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
/*
32
* s2argv: convert strings to argv
43
* Copyright (C) 2014 Renzo Davoli. University of Bologna. <renzo@cs.unibo.it>
@@ -55,7 +54,7 @@ int main()
5554
printargv(myargv);
5655
printf("len %zd argc %zd\n", s2argvlen(myargv), s2argc(myargv));
5756
s2argv_free(myargv);
58-
s2multiargv(buf, print1argv, NULL);
57+
s2multiargv(buf, print1argv, NULL, 0);
5958
if (fork()==0) {
6059
eexecsp(buf);
6160
exit(-1);

man/CMakeLists.txt

+10-11
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,20 @@
11
cmake_minimum_required(VERSION 3.7)
22

3-
set(RONN_ORGANIZATION "VirtualSquare")
4-
set(RONN_ARGS --organization=${RONN_ORGANIZATION})
3+
set(PANDOC_ORG "VirtualSquare")
54

6-
# ### ronn pages
5+
# ### pandoc pages
76

8-
file(GLOB VU_RONN_PAGES ${CMAKE_CURRENT_SOURCE_DIR}/*.[1-8].ronn)
7+
file(GLOB VU_PANDOC_PAGES ${CMAKE_CURRENT_SOURCE_DIR}/*.[1-8].md)
98
set(VU_MAN_FILES)
10-
foreach(VU_RONN_PATH IN LISTS VU_RONN_PAGES)
11-
# VU_RONNPAGE: basename of VU_RONN_PATH
12-
get_filename_component(VU_RONNPAGE ${VU_RONN_PATH} NAME)
13-
# VU_MANPAGE: VU_RONNPAGE without the suffix
14-
string(REGEX REPLACE "\.ronn$" "" VU_MANPAGE ${VU_RONNPAGE})
9+
foreach(VU_PANDOC_PATH IN LISTS VU_PANDOC_PAGES)
10+
# VU_PANDOCPAGE: basename of VU_PANDOC_PATH
11+
get_filename_component(VU_PANDOCPAGE ${VU_PANDOC_PATH} NAME)
12+
# VU_MANPAGE: VU_PANDOCPAGE without the suffix
13+
string(REGEX REPLACE "\.md$" "" VU_MANPAGE ${VU_PANDOCPAGE})
1514
list(APPEND VU_MAN_FILES ${VU_MANPAGE})
16-
endforeach(VU_RONN_PATH)
15+
endforeach(VU_PANDOC_PATH)
1716

18-
add_custom_target(${PROJECT_NAME}_manpages ALL make RONN_ARGS="${RONN_ARGS}" ${VU_MAN_FILES}
17+
add_custom_target(${PROJECT_NAME}_manpages ALL make PANDOC_ORG="${PANDOC_ORG}" ${VU_MAN_FILES}
1918
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
2019

2120
### man pages

0 commit comments

Comments
 (0)