w11 - cpp 0.794
Backend server for Rlink and w11
Loading...
Searching...
No Matches
RtclSystem.cpp
Go to the documentation of this file.
1// $Id: RtclSystem.cpp 1186 2019-07-12 17:49:59Z mueller $
2// SPDX-License-Identifier: GPL-3.0-or-later
3// Copyright 2013-2018 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
4//
5// Revision History:
6// Date Rev Version Comment
7// 2018-12-23 1091 1.0.2 use c++ style casts; use range loop
8// 2014-08-22 584 1.0.1 use nullptr
9// 2013-05-17 521 1.0 Initial version
10// ---------------------------------------------------------------------------
11
16#include <unistd.h>
17#include <errno.h>
18#include <string.h>
19#include <sys/types.h>
20#include <sys/wait.h>
21
22#include <iostream>
23#include <string>
24#include <algorithm>
25
26#include "librtools/RerrMsg.hpp"
28
29#include "RtclSignalAction.hpp"
30
31#include "RtclSystem.hpp"
32
33using namespace std;
34
40// all method definitions in namespace Retro
41namespace Retro {
42
43static const int kOK = TCL_OK;
44static const int kERR = TCL_ERROR;
45
46//------------------------------------------+-----------------------------------
48
49void RtclSystem::CreateCmds(Tcl_Interp* interp)
50{
51 Tcl_CreateObjCommand(interp, "rutil::isatty", Isatty,
52 nullptr, nullptr);
53 Tcl_CreateObjCommand(interp, "rutil::sigaction", SignalAction,
54 nullptr, nullptr);
55 Tcl_CreateObjCommand(interp, "rutil::waitpid", WaitPid,
56 nullptr, nullptr);
57 return;
58}
59
60//------------------------------------------+-----------------------------------
62
63int RtclSystem::Isatty(ClientData /*cdata*/, Tcl_Interp* interp,
64 int objc, Tcl_Obj* const objv[])
65{
66 RtclArgs args(interp, objc, objv);
67 string file = "stdin";
68 if (!args.GetArg("?file", file)) return kERR;
69 if (!args.AllDone()) return kERR;
70
71 transform(file.begin(), file.end(), file.begin(), ::tolower);
72 int fileno = -1;
73 if (file == "stdin") fileno = STDIN_FILENO;
74 if (file == "stdout") fileno = STDOUT_FILENO;
75 if (file == "stderr") fileno = STDERR_FILENO;
76 if (fileno == -1) return args.Quit("file must be stdin, stdout, or stderr");
77
78 args.SetResult(bool(::isatty(fileno)));
79
80 return kOK;
81}
82
83//------------------------------------------+-----------------------------------
84
85static int signam2num(const std::string& signam)
86{
87 string sn = signam;
88 transform(sn.begin(), sn.end(), sn.begin(), ::toupper);
89 if (sn == "SIGHUP") return SIGHUP;
90 if (sn == "SIGINT") return SIGINT;
91 if (sn == "SIGTERM") return SIGTERM;
92 if (sn == "SIGUSR1") return SIGUSR1;
93 if (sn == "SIGUSR2") return SIGUSR2;
94 return -1;
95}
96
97static const char* signum2nam(int signum)
98{
99 if (signum == SIGHUP) return "SIGHUP";
100 if (signum == SIGINT) return "SIGINT";
101 if (signum == SIGTERM) return "SIGTERM";
102 if (signum == SIGUSR1) return "SIGUSR1";
103 if (signum == SIGUSR2) return "SIGUSR2";
104 return "???";
105}
106
107//------------------------------------------+-----------------------------------
109
110int RtclSystem::SignalAction(ClientData /*cdata*/, Tcl_Interp* interp,
111 int objc, Tcl_Obj* const objv[])
112{
113 RtclArgs args(interp, objc, objv);
114 RerrMsg emsg;
115
116 // check if initialized, if not, do it
117 if (!RtclSignalAction::Obj()) {
118 if (!RtclSignalAction::Init(interp, emsg)) return args.Quit(emsg);
119 }
121
122 // blank 'sigaction' is a noop (initialize as side effect)
123 if (objc == 1) return kOK;
124
125 // handle cases with only options (no signal name first)
126
127 if (args.PeekArgString(0)[0] == '-') {
128 static RtclNameSet optset("-init|-info");
129 string opt;
130 if (args.NextOpt(opt, optset)) {
131
132 if (opt == "-init") { // -init
133 if (!args.AllDone()) return kERR;
134 return kOK;
135
136 } else if (opt == "-info") { // -info
137 RtclOPtr pres(Tcl_NewListObj(0,nullptr));
138 int siglist[] = {SIGHUP,SIGINT,SIGTERM,SIGUSR1,SIGUSR2};
139 for (auto& sig : siglist) {
140 Tcl_Obj* pobj;
141 if (pact->GetAction(sig, pobj, emsg)) {
142 RtclOPtr pele(Tcl_NewListObj(0,0));
143 Tcl_ListObjAppendElement(nullptr, pele,
144 Tcl_NewStringObj(signum2nam(sig),-1));
145 if (pobj) {
146 Tcl_ListObjAppendElement(nullptr, pele, pobj);
147 } else {
148 Tcl_ListObjAppendElement(nullptr, pele,
149 Tcl_NewStringObj("{}",-1));
150 }
151 Tcl_ListObjAppendElement(nullptr, pres, pele);
152 }
153 }
154 args.SetResult(pres);
155 return kOK;
156 }
157 }
158 if (!args.OptValid()) return kERR;
159 if (!args.AllDone()) return kERR;
160 return kERR;
161 }
162
163 // handle cases which start with a signal name
164
165 string signam;
166 if (!args.GetArg("signam", signam)) return kERR;
167 int signum = signam2num(signam);
168 if (signum < 0) return args.Quit("invalid signal name");
169
170 static RtclNameSet optset("-action|-revert");
171 string opt;
172 if (args.NextOpt(opt, optset)) {
173 if (opt == "-action") { // signam -action script
174 string script;
175 if (!args.GetArg("script", script)) return kERR;
176 if (!args.AllDone()) return kERR;
177 RtclOPtr pobj(Tcl_NewStringObj(script.c_str(), -1));
178 if (!pact->SetAction(signum, pobj, emsg))
179 return args.Quit(emsg);
180
181 } else if (opt == "-revert") { // signam -revert
182 if (!args.AllDone()) return kERR;
183 if (!pact->ClearAction(signum, emsg))
184 return args.Quit(emsg);
185 }
186
187 } else { // signam
188 if (!args.OptValid()) return kERR;
189 if (!args.AllDone()) return kERR;
190 Tcl_Obj* pobj;
191 if (!pact->GetAction(signum, pobj, emsg))
192 return args.Quit("no handler defined");
193 if (pobj == nullptr) pobj = Tcl_NewStringObj("{}",-1);
194 args.SetResult(pobj);
195 }
196
197 return kOK;
198}
199
200//------------------------------------------+-----------------------------------
202
203int RtclSystem::WaitPid(ClientData /*cdata*/, Tcl_Interp* interp,
204 int objc, Tcl_Obj* const objv[])
205{
206 RtclArgs args(interp, objc, objv);
207 int pid;
208 if (!args.GetArg("pid", pid)) return kERR;
209 if (!args.AllDone()) return kERR;
210
211 int status;
212 int irc = ::waitpid(pid, &status, WNOHANG);
213 if (irc < 0) {
214 RerrMsg emsg("RtclSystem::WaitPid", "waitpid() failed: ", errno);
215 return args.Quit(emsg);
216 }
217 args.SetResult(status);
218 return kOK;
219}
220
221
222} // end namespace Retro
FIXME_docs.
Definition: RerrMsg.hpp:25
FIXME_docs.
Definition: RtclArgs.hpp:41
bool NextOpt(std::string &val)
FIXME_docs.
Definition: RtclArgs.cpp:368
const char * PeekArgString(int rind) const
FIXME_docs.
Definition: RtclArgs.cpp:461
bool GetArg(const char *name, Tcl_Obj *&pval)
FIXME_docs.
Definition: RtclArgs.cpp:114
bool OptValid() const
FIXME_docs.
Definition: RtclArgs.ipp:52
int Quit(const std::string &str)
FIXME_docs.
Definition: RtclArgs.ipp:157
void SetResult(const std::string &str)
FIXME_docs.
Definition: RtclArgs.ipp:76
bool AllDone()
FIXME_docs.
Definition: RtclArgs.cpp:447
Implemenation (inline) of RtclOPtr.
Definition: RtclOPtr.hpp:23
bool SetAction(int signum, Tcl_Obj *pobj, RerrMsg &emsg)
FIXME_docs.
static bool Init(Tcl_Interp *interp, RerrMsg &emsg)
FIXME_docs.
static RtclSignalAction * Obj()
FIXME_docs.
bool ClearAction(int signum, RerrMsg &emsg)
FIXME_docs.
bool GetAction(int signum, Tcl_Obj *&pobj, RerrMsg &emsg)
FIXME_docs.
static int Isatty(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
FIXME_docs.
Definition: RtclSystem.cpp:63
static int WaitPid(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
FIXME_docs.
Definition: RtclSystem.cpp:203
static void CreateCmds(Tcl_Interp *interp)
FIXME_docs.
Definition: RtclSystem.cpp:49
static int SignalAction(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
FIXME_docs.
Definition: RtclSystem.cpp:110
Declaration of class ReventLoop.
Definition: ReventLoop.cpp:47
static const int kERR
Definition: RtclBvi.cpp:38
static const int kOK
Definition: RtclBvi.cpp:37
static int signam2num(const std::string &signam)
Definition: RtclSystem.cpp:85
static const char * signum2nam(int signum)
Definition: RtclSystem.cpp:97