Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
F
frama-c
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Container Registry
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
pub
frama-c
Commits
428f4208
Commit
428f4208
authored
8 years ago
by
Kostyantyn Vorobyov
Browse files
Options
Downloads
Patches
Plain Diff
[RTL] Interface for running shell commands
parent
a1adf7ec
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
src/plugins/e-acsl/share/e-acsl/e_acsl_shexec.h
+225
-0
225 additions, 0 deletions
src/plugins/e-acsl/share/e-acsl/e_acsl_shexec.h
with
225 additions
and
0 deletions
src/plugins/e-acsl/share/e-acsl/e_acsl_shexec.h
0 → 100644
+
225
−
0
View file @
428f4208
/**************************************************************************/
/* */
/* This file is part of the Frama-C's E-ACSL plug-in. */
/* */
/* Copyright (C) 2012-2015 */
/* CEA (Commissariat à l'énergie atomique et aux énergies */
/* alternatives) */
/* */
/* you can redistribute it and/or modify it under the terms of the GNU */
/* Lesser General Public License as published by the Free Software */
/* Foundation, version 2.1. */
/* */
/* It is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
/* GNU Lesser General Public License for more details. */
/* */
/* See the GNU Lesser General Public License version 2.1 */
/* for more details (enclosed in the file license/LGPLv2.1). */
/* */
/**************************************************************************/
/*! ***********************************************************************
* \file e_acsl_shexec.h
* \brief Interface for running shell commands
***************************************************************************/
#ifndef E_ACSL_SHEXEC
#define E_ACSL_SHEXEC
#include
"e_acsl_malloc.h"
#include
"e_acsl_printf.h"
#include
"e_acsl_string.h"
#include
<errno.h>
#include
<sys/wait.h>
/*! \class ipr_t
* \brief Result struct for `shexec` function -- execute a command in the
* shell via fork/exec and return results */
typedef
struct
{
/** \brief resulting STDERR stream as \p const \p char* */
char
*
stderrs
;
/** \brief Supplied STDIN stream as \p const \p char* */
char
*
stdins
;
/** \brief resulting STDOUT stream as \p const \p char* */
char
*
stdouts
;
/** \brief Exit status of a program */
int
exit_status
;
/** \brief ID of a child process this command has been executed in */
pid_t
pid
;
/** \brief Set to non-zero if child process is interrupted via a signal */
int
signaled
;
/** \brief If \p signalled is set, \p signo is set to the number of signal
* that interrupted execution of a child process */
int
signo
;
/** \brief A command to execute. Needs to be NULL terminated */
char
**
argv
;
/** \brief ARGV */
/** \brief Message if the command has failed to run */
char
*
error
;
}
ipr_t
;
/* \brief Read characters from a buffer associated with a file descriptor into
* a C string
*
* Read a string from a buffer associated with a file descriptor by allocating
* a string of an initial size and increasing the size of a buffer with
* realloc. This is for the cases when we can not quickly seek through the
* file and identify the size of a buffer associated with a file descriptor
*
* \param fd - file descriptor to read from
* \param bufsize - the number of characters we read a t a time
*
* \return NUL-terminated C string on success
* \return NULL on failure */
char
*
fd_read
(
int
fd
,
short
bufsize
)
{
/* Read `buffer_size` chars at a time */
short
buffer_size
=
bufsize
*
sizeof
(
char
);
/* Size of the fetched string */
int
size
=
buffer_size
;
/* Buffer where for read data */
char
*
buffer
=
(
char
*
)
native_malloc
(
size
);
/* The number of read bytes */
short
fetched
=
0
;
int
rd
=
0
;
/* Count of fetched characters */
/* Each time the pointer if moved by `size - buffer_size` as initially
* the size of 'buffer' is 'buffer_size' */
while
((
fetched
=
read
(
fd
,
buffer
+
size
-
buffer_size
,
buffer_size
)))
{
rd
+=
fetched
;
if
(
fetched
!=
-
1
)
{
size
+=
fetched
*
sizeof
(
char
);
buffer
=
native_realloc
(
buffer
,
size
+
1
);
}
else
{
return
NULL
;
}
}
buffer
[
rd
]
=
'\0'
;
return
buffer
;
}
/* Execute a command in the shell and place results to data */
ipr_t
*
__shexec
(
ipr_t
*
data
)
{
int
outfd
[
2
],
errfd
[
2
],
infd
[
2
];
int
oldstdout
,
oldstderr
,
oldstdin
;
if
(
pipe
(
infd
))
/* From where parent is going to read */
data
->
error
=
nstrdup
(
"Can not create a pipe for STDIN"
);
if
(
pipe
(
outfd
))
/* From where parent is going to read */
data
->
error
=
nstrdup
(
"Can not create a pipe for STDOUT"
);
if
(
pipe
(
errfd
))
/* From where parent is going to read */
data
->
error
=
nstrdup
(
"Can not create a pipe for STDERR"
);
/* Immediately return if reading from one of the STD pipes failed */
if
(
data
->
error
)
return
data
;
/* Save stdin, stdout and stderr */
oldstdin
=
dup
(
0
);
oldstdout
=
dup
(
1
);
oldstderr
=
dup
(
2
);
/* Close stdin, stdout and stderr */
close
(
0
);
close
(
1
);
close
(
2
);
dup2
(
infd
[
0
],
0
);
/* Make the read end of infd as STDIN */
dup2
(
outfd
[
1
],
1
);
/* Make the write end of outfd as STDOUT */
dup2
(
errfd
[
1
],
2
);
/* Make the write end of outfd as STDERR */
pid_t
pid
=
fork
();
if
(
!
pid
)
{
/* Close the streams as they are not required for a child */
close
(
infd
[
0
]);
close
(
outfd
[
0
]);
close
(
errfd
[
0
]);
close
(
infd
[
1
]);
close
(
outfd
[
1
]);
close
(
errfd
[
1
]);
execvp
(
data
->
argv
[
0
],
data
->
argv
);
dup2
(
oldstderr
,
2
);
/* Restore stderr */
if
(
errno
)
{
data
->
error
=
nstrdup
(
"Failed to execute:
\n
"
);
char
**
arg
=
data
->
argv
-
1
;
while
(
*++
arg
)
data
->
error
=
sappend
(
*
arg
,
data
->
error
,
" "
);
}
}
else
{
close
(
0
);
close
(
1
);
close
(
2
);
dup2
(
oldstdin
,
0
);
dup2
(
oldstdout
,
1
);
dup2
(
oldstderr
,
2
);
close
(
outfd
[
1
]);
close
(
errfd
[
1
]);
close
(
infd
[
0
]);
/* If data->stdin string if supplied, write that string to child's
STDIN first */
if
(
data
->
stdins
)
/* Return NULL if write fails */
if
(
write
(
infd
[
1
],
data
->
stdins
,
strlen
(
data
->
stdins
))
==
-
1
)
return
NULL
;
/* Read from child's stdout and stderr */
data
->
stdouts
=
fd_read
(
outfd
[
0
],
256
);
if
(
!
data
->
stdouts
)
data
->
error
=
nstrdup
(
"Error reading from STDOUT pipe"
);
data
->
stderrs
=
fd_read
(
errfd
[
0
],
256
);
if
(
!
data
->
stderrs
)
data
->
error
=
nstrdup
(
"Error reading from STDERR pipe"
);
/* Close file descriptors we still have open */
close
(
outfd
[
0
]);
/* read end of STDOUT */
close
(
errfd
[
0
]);
/* read end of STDERR */
close
(
infd
[
1
]);
/* write end of STDIN */
int
status
;
waitpid
(
pid
,
&
status
,
0
);
/* wait for the child to finish */
data
->
exit_status
=
WEXITSTATUS
(
status
);
/* exis status */
data
->
pid
=
pid
;
/* process number */
data
->
signaled
=
WIFSIGNALED
(
status
);
/* signal caught */
data
->
signo
=
WTERMSIG
(
status
);
/* signal number caught */
return
data
;
}
return
NULL
;
}
/* \brief Deallocate an `ipr_t` structure returned by `shexec` */
void
free_ipr
(
ipr_t
*
ipr
)
{
if
(
ipr
)
{
if
(
ipr
->
stdouts
)
native_free
(
ipr
->
stdouts
);
if
(
ipr
->
stderrs
)
native_free
(
ipr
->
stderrs
);
if
(
ipr
->
error
)
native_free
(
ipr
->
error
);
if
(
ipr
->
stdins
)
native_free
(
ipr
->
stdins
);
native_free
(
ipr
);
}
}
/* \brief Execute a command given via parameter `data` in the current shell
* and its result as `ipr_t` struct.
*
* \param data - command to execute. This argument is assumed to be a
* NULL-terminated array of strings
* \param sin - if not NULL a C string given via `sin` is supplied as standard
* input to the executed command
* \return - heap-allocated struct `ipr_t` that describes the output of the
* executed command. De-allocation of this struct should be performed via the
* `free_ipr` function */
static
ipr_t
*
shexec
(
char
**
data
,
const
char
*
sin
)
{
/* Allocate and initialise the struct that we use */
ipr_t
*
ipr
=
(
ipr_t
*
)
native_malloc
(
sizeof
(
ipr_t
));
ipr
->
stderrs
=
NULL
;
ipr
->
stdouts
=
NULL
;
ipr
->
stdins
=
nstrdup
(
sin
);
ipr
->
argv
=
data
;
ipr
->
exit_status
=
0
;
ipr
->
pid
=
0
;
ipr
->
signaled
=
0
;
return
__shexec
(
ipr
);
}
#endif
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment