Is it possible to get the exit code of a previous run of systemd's process on re-run?
That is, suppose I have the following C++ code:
int main(int argc, char **argv)
{
if (argc > 2)
{
std::string opt = argv[1];
std::string val = argv[2];
if (arg == "--exit-code" && val == "42")
{
std::cout << "Previous exit code is: " << val << std::endl;
return 0;
}
}
std::cout << "This is the first run" << std::endl;
return 42;
}
And systemd's configuration:
[Unit]
Description=Fails first then succeeds
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=./a.out
Restart=on-failure # --exit-code <-- how to pass the previous exit code here?
[Install]
WantedBy=multi-user.target
How does one get the exit code of the previous run and pass it to subsequent attempts of the same process?
I would suggest calling systemctl show <service name> and looking for ExecMainCode=<exit code>. Alternatively, you could read $EXIT_CODE in the ExecStopPost and store it somewhere for later use. I don't know any way to pass it as a command line argument, other than writing a wrapper script or changing ExecStart (note that $EXIT_CODE won't be available in ExecStart).
Related
The following C snippet is supposed to be run by Windows IIS, as a CGI .exe program.
It outputs three character "a, b, c" with a 10 second delay between them.
However, if I use a browser to access the program, and then reloads the browser page to access the program again - then I get two processes running in parallell on the IIS.
At the browser I will of course only see the output of process 2, as the TCP connection to process 1 has been closed after the first "a" was received.
On the Windows server process 2 happily runs to completion, but processes 1 runs only until it outputs the second character "b".
The WriteFile that outputs that "b" is successful, and also the following log write "Done" is also excuted (thus, there is no fatil exception in WriteFile).
But then, suddenly, process 1 is terminated.
My theory is that IIS detects that some output is received from process 1, and that IIS then forcibly terminates it (as the client is disconnected)
If I add a 10ms sleep (commented below) after the WriteFile, then process 1 does not even execute the log write "Done".
I suppose that this is due to the fact that IIS needs a little time to perform that Terminate call, and without the Sleep the process has time to execute at least the log write "Done" before IIS terminates.
Does anybody recognize this?
And how do I stop IIS from terminating the process (except by beginning by forking it into a new process, that is not owned by IIS)
I really would like to run process 1 all the way to the end, even if no client is "listening" to it...
#include <stdio.h>
#include <windows.h>
void out(char *text)
{
int i;
int written;
char buf[1000];
FILE *fp;
for(i = 0; text[i] != '\0'; i++)
buf[i] = (text[i] == '\n' ? '^' : text[i]);
buf[i] = '\0';
if((fp = fopen("/temp/testkill.txt", "a")) != NULL) {
fprintf(fp, "%d: Write %s\n", _getpid(), buf);
fclose(fp);
}
if(WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), text, strlen(text), &written, NULL) == 0)
written = -1;
// Sleep(10);
if((fp = fopen("/temp/testkill.txt", "a")) != NULL) {
fprintf(fp, "%d: Done! %s (%d)\n", _getpid(), buf, written);
fclose(fp);
}
}
main()
{
out("Content-Type: text/html\n\n<html><body>\n");
out("a");
Sleep(10000);
out("b");
Sleep(10000);
out("c");
}
I have a program with the following logic, which continuously reads input and prints out the read input.
int main()
{
while(1){
std::string str;
std::cin>>str; // Read a string
std::cout<<"\""<<str<<"\""<<std::endl<<std::flush;
str.clear();
sleep(1);
}
}
Now i start this program from ksh, feeding few lines of input using a HERE doc.
abi#linux:~/Tst> ./a.out << EOF
> Hi
> How
> are
> You
> EOF
"Hi"
"How"
"are"
"You"
""
""
""
""
""
""
*i entered <ctrl+C> here to stop the program*
abi#linux:~/Tst>
My Question is, I have provided only 4 lines as input from HERE doc,
But after the inputs are exhausted, the a.out continuously reads NULL as the input and prints out "".
why is this happening ?
Your program as presented will never terminate; as you have a
while(1) {
do_things_forever();
}
Because it never terminates, and stdin will be null once you reach the end of input, it's doing exactly what you ask it to.
You probably want something akin to:
std::string str;
while( !( std::cin >> str ).eof() ) {
std::cout << '"' << str << '"' << std::endl << std::flush;
str.clear();
sleep(1);
}
The current tab-completion while "read -e" is active in bash seems to be only matching filenames:
read -e
[[TabTab]]
abc.txt bcd.txt cde.txt
I want the completion to be a set of strings defined by me, while file/dir/hostname-completion etc. should be deactivated for the duration of "read -e".
Outside of a script
complete -W 'string1 string2 string3' -E
works well, but i cant get this kind of completion to work inside a script while using "read -e".
Although it seems like a reasonable request, I don't believe that is possible.
The existing implementation of the read builtin sets the readline completion environment to a fairly basic configuration before calling readline to handle -e input.
You can see the code in builtins/read.def, in the edit_line function: it sets rl_attempted_completion_function to NULL for the duration of the call to readline. readline has several completion overrides, so it's not 100% obvious that this resets the entire completion environment, but as far as I know this is the function which is used to implement programmable completion as per the complete command.
With some work, you could probably modify the definition of the read command to allow a specific completion function instead of or in addition to the readline standard filename completion function. That would require a non-trivial understanding of bash internals, but it would be a reasonable project if you wanted to gain familiarity with those internals.
As a simpler but less efficient alternative, you could write your own little utility which just accepts one line of keyboard input with readline and echoes it to stdout. Then invoke read redirecting its stdin to your utility:
read -r < <(my_reader string1 string2 string3)
(That assumes that my_reader uses its command-line arguments to construct the potential completion list for the readline library. You'd probably want the option to present a prompt as well.)
The readline documentation includes an example of an application which does simple custom completion; once you translate it from the K&R function prototype syntax, it might be pretty easy to adapt to your needs.
Edit: After I looked at that example again, I thought it had a lot of unnecessary details, so I wrote the following example with fewer unnecessary details. I might upload it to github, but for now it's here even though it's nearly 100 lines:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <readline/readline.h>
static void version(const char* progname) {
fprintf(stderr, "%s 0.1\n", progname);
}
static void usage(const char* progname) {
fprintf(stderr, "Usage: %s [-fhv] [-p PROMPT] [-n PROGNAME] [COMPLETION...]\n", progname);
fprintf(stderr,
"Reads one line using readline, and prints it to stdout.\n"
"Returns success if a line was read.\n"
" -p PROMPT Output PROMPT before requesting input.\n"
" -n PROGNAME Set application name to PROGNAME for readline config file\n"
" (Default: %s).\n"
" -f Use filename completion as well as specified completions.\n"
" -h Print this help text and exit.\n"
" -v Print version number and exit.\n"
" COMPLETION word to add to the list of possible completions.\n",
progname);
}
/* Readline really likes globals, so none of its hooks take a context parameter. */
static char** completions = NULL;
static char* generate_next_completion(const char* text, int state) {
static int index = 0;
if (state == 0) index = 0; /* reset index if we're starting */
size_t textlen = strlen(text);
while (completions[index++])
if (strncmp(completions[index - 1], text, textlen) == 0)
return strdup(completions[index - 1]);
return NULL;
}
/* We use this if we will fall back to filename completion */
static char** generate_completions(const char* text, int start, int end) {
return rl_completion_matches(text, generate_next_completion);
}
int main (int argc, char **argv) {
const char* prompt = "";
const char* progname = strrchr(argv[0], '/');
progname = progname ? progname + 1 : argv[0];
rl_readline_name = progname;
bool use_file_completion = false;
for (;;) {
int opt = getopt(argc, argv, "+fp:n:hv");
switch (opt) {
case -1: break;
case 'f': use_file_completion = true; continue;
case 'p': prompt = optarg; continue;
case 'n': rl_readline_name = optarg; continue;
case 'h': usage(progname); return 0;
case 'v': version(progname); return 0;
default: usage(progname); return 2;
}
break;
}
/* The default is stdout, which would interfere with capturing output. */
rl_outstream = stderr;
completions = argv + optind;
rl_completion_entry_function = rl_filename_completion_function;
if (*completions) {
if (use_file_completion)
rl_attempted_completion_function = generate_completions;
else
rl_completion_entry_function = generate_next_completion;
} else {
/* No specified strings */
if (!use_file_completion)
rl_inhibit_completion = true;
}
char* line = readline(prompt);
if (line) {
puts(line);
free(line);
return 0;
} else {
fputc('\n', rl_outstream);
return 1;
}
}
I am creating a large pintool and I have two questions:
The tool (abridged below to the relevant part only) sometimes cannot identify the image/routine for particular executed instructions. Does anybody know when/why can that happen?
The tool (when instrumenting a Barnes-Hut benchmark) always terminates with an out-of-memory (OOM) error after running for a while (although the benchmark, when run standalone, completes successfully). Which tools to use to debug/trace the OOM error of Pin-instrumented applications?
int main(int argc, char *argv[])
{
PIN_InitSymbols();
if( PIN_Init(argc, argv) )
{
return 0;
}
INS_AddInstrumentFunction(Instruction, 0);
PIN_StartProgram();
return 0;
}
VOID Instruction(INS ins, VOID *v)
{
INS_InsertPredicatedCall( ins,
IPOINT_BEFORE,
(AFUNPTR) handle_ins_execution,
IARG_INST_PTR,
.....);
}
VOID handle_ins_execution (ADDRINT addr, ...)
{
PIN_LockClient();
IMG img = IMG_FindByAddress(addr);
RTN rtn = RTN_FindByAddress(addr);
PIN_UnlockClient();
if( IMG_Valid(img) ) {
std::cerr << "From Image : " << IMG_Name( img ) << std::endl;
} else {
std::cerr << "From Image : " << "(UKNOWN)" << std::endl;
}
if( RTN_Valid(rtn) ) {
std::cerr << "From Routine : " << RTN_Name(rtn) << std::endl;
} else {
std::cerr << "From Routine : " << "(UKNOWN)" << std::endl;
}
}
I recently asked this on the PinHeads forum, and I'm awaiting a response. What I have read in the documentation is that the IMG_FindByAddress function operates by looking "for each image, check if the address is within the mapped memory region of one of its segments." It may be possible that instructions are executed that are not within the valid ranges.
The best way to know what image it is in for cases like this is to look at the context. My pintool (based on DebugTrace) continues to run even without knowing what image it is in. You can look at the log entries before and after this occurs. I see this all the time in dydl on OSX.
SO,
There are many similar questions, however none that I have been able to use. My code snippet is as follows:
for(int j=0; j<N; j++) {
pid_t pid = fork();
if (pid == -1) {
exit(-1); //err
} else if (pid == 0) {//kid
stringstream ss;
ss<<j;
execlp("./sub","sub",ss.str().c_str(),NULL);
exit(0);
} else {
/* parent */
}
}
my executing code in sub(.cpp) is:
int main( int argc, char **argv )
{
cout<<argv[i]<<endl;
exit(0);
}
my output is as such:
[terminal prompt '$'] 4
2
3
etc.
Is there a way I could prevent the prompt from displaying on the exec call? and why is it ONLY displaying on the first exec call, and not on every one?
What you see is the normal prompt of your shell, because the parent process terminates very quickly. It is not the output of the exec call. The forked processes print their output after the parent process has terminated.
You can use waitpid() in the parent process to "wait" until all forked process have terminated.