shim.cpp
Go to the documentation of this file.
1 // Sets up a node process environment and executes the target node
2 // Author: Max Schwarz <max.schwarz@ais.uni-bonn.de>
3 
4 #include <stdexcept>
5 #include <vector>
6 #include <sstream>
7 
8 #include <unistd.h>
9 #include <getopt.h>
10 #include <string.h>
11 
12 #include <utmp.h>
13 
14 #include <sys/time.h>
15 #include <sys/resource.h>
16 #include <sys/prctl.h>
17 
18 static const struct option OPTIONS[] = {
19  {"help", no_argument, nullptr, 'h'},
20  {"namespace", required_argument, nullptr, 'n'},
21  {"env", required_argument, nullptr, 'e'},
22  {"coredump", no_argument, nullptr, 'c'},
23  {"coredump-relative", required_argument, nullptr, 'C'},
24  {"tty", required_argument, nullptr, 't'},
25  {"run", required_argument, nullptr, 'r'},
26  {"stderr", required_argument, nullptr, 's'},
27 
28  {nullptr, 0, nullptr, 0}
29 };
30 
31 void usage()
32 {
33  fprintf(stderr, R"EOS(
34 This is an internal tool for rosmon. You should not need to call it yourself.
35 
36 Usage:
37  _shim [options] --run <executable> [args...]
38 
39 Options:
40  --namespace=NS Put the node in namespace NS
41  --env=A=B Set environment variable A to value B (can be repeated)
42  --coredump Enable coredump collection
43  --coredump-relative=DIR Coredumps should go to DIR
44  --run <executable> All arguments after this one are passed on
45  --tty TTY TTY fd for stdout
46  --stderr FD file descriptor for stderr
47 )EOS");
48 }
49 
50 int main(int argc, char** argv)
51 {
52  bool coredumpsEnabled = false;
53  char* coredumpsRelative = nullptr;
54 
55  char* nodeExecutable = nullptr;
56  int nodeOptionsBegin = -1;
57 
58  int tty = -1;
59  int stderr_fd = -1;
60 
61  while(true)
62  {
63  int option_index;
64  int c = getopt_long(argc, argv, "h", OPTIONS, &option_index);
65 
66  if(c == -1)
67  break;
68 
69  switch(c)
70  {
71  case 'h':
72  usage();
73  return 0;
74  case '?':
75  usage();
76  return 1;
77  case 'n':
78  setenv("ROS_NAMESPACE", optarg, 1);
79  break;
80  case 'e':
81  {
82  char* value = strchr(optarg, '=');
83  if(!value)
84  throw std::invalid_argument("Need '=' in --env spec");
85 
86  *value = 0;
87 
88  setenv(optarg, value + 1, 1);
89  break;
90  }
91  case 'c':
92  coredumpsEnabled = true;
93  break;
94  case 'C':
95  coredumpsRelative = optarg;
96  break;
97  case 't':
98  tty = atoi(optarg);
99  break;
100  case 'r':
101  nodeExecutable = optarg;
102  nodeOptionsBegin = optind;
103  break;
104  case 's':
105  stderr_fd = atoi(optarg);
106  break;
107  }
108 
109  if(nodeExecutable)
110  break;
111  }
112 
113  if(!nodeExecutable)
114  throw std::invalid_argument("Need --run option");
115 
116  if(tty < 0)
117  throw std::invalid_argument("Need --tty option");
118 
119  if(stderr_fd < 0)
120  throw std::invalid_argument("Need --stderr option");
121 
122  if(login_tty(tty) != 0)
123  {
124  perror("Could not call login_tty()");
125  std::abort();
126  }
127 
128  if(dup2(stderr_fd, STDERR_FILENO) < 0)
129  {
130  perror("Could not call dup2() for stderr");
131  std::abort();
132  }
133 
134  // Try to enable core dumps
135  if(coredumpsEnabled)
136  {
137  rlimit limit;
138  if(getrlimit(RLIMIT_CORE, &limit) == 0)
139  {
140  // only modify the limit if coredumps are disabled entirely
141  if(limit.rlim_cur == 0)
142  {
143  limit.rlim_cur = limit.rlim_max;
144  setrlimit(RLIMIT_CORE, &limit);
145  }
146  }
147 
148  // If needed for coredump collection with a relative core_pattern,
149  // cd to a temporary directory.
150  if(coredumpsRelative)
151  {
152  if(chdir(coredumpsRelative) != 0)
153  {
154  perror("Could not change to newly created process working directory");
155  }
156  }
157  }
158  else
159  {
160  // Disable coredumps
161  rlimit limit;
162  if(getrlimit(RLIMIT_CORE, &limit) == 0)
163  {
164  limit.rlim_cur = 0;
165  setrlimit(RLIMIT_CORE, &limit);
166  }
167  }
168 
169  // Allow gdb to attach
170  prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY);
171 
172  // Build up argument vector
173  std::vector<char*> args;
174 
175  args.push_back(nodeExecutable);
176 
177  for(int i = nodeOptionsBegin; i < argc; ++i)
178  args.push_back(argv[i]);
179 
180  args.push_back(nullptr);
181 
182  // Go!
183  if(execvp(nodeExecutable, args.data()) != 0)
184  {
185  std::stringstream ss;
186  for(const auto& part : args)
187  ss << part << " ";
188 
189  fprintf(stderr, "Could not execute %s: %s\n", ss.str().c_str(), strerror(errno));
190  }
191 
192  // We should not arrive here
193  std::abort();
194 }
void usage()
Definition: shim.cpp:31
static const struct option OPTIONS[]
Definition: shim.cpp:18
int main(int argc, char **argv)
Definition: shim.cpp:50


rosmon_core
Author(s): Max Schwarz
autogenerated on Sat Jan 9 2021 03:35:43