Run as a daemon or service: Difference between revisions

Added Wren
(added Perl programming solution)
(Added Wren)
Line 573:
vwait forever</lang>
On Windows, there is a commercial extension to Tcl which allows a script to be installed as a service. Such a script would be much like the one above, but without the daemonization section as that has become a property of the runtime.
 
=={{header|Wren}}==
{{libheader|Wren-date}}
An embedded program but the actual daemon is of course the C host even though the process is orchestrated by the Wren code which handles any errors and prints the time every second to the file.
 
The following script is based on the C example though modified a little to run on Ubuntu 20.04.
<lang ecmascript>/* dumper.wren */
 
import "./date" for Date
 
var O_WRONLY = 1
var O_APPEND = 1024
var O_CREAT = 64
 
var STDOUT_FILENO = 1
 
class C {
foreign static fileName
 
foreign static open(pathName, flags, mode)
 
foreign static daemon(nochdir, noclose)
 
foreign static redirectStdout(oldfd, newfd)
 
foreign static close(fd)
 
foreign static time
 
foreign static sleep(seconds)
}
 
// gets a Date object from a Unix time in seconds
var UT2Date = Fn.new { |ut| Date.unixEpoch.addSeconds(ut) }
 
Date.default = "ddd| |mmm| |dd| |hh|:|MM|:|ss| |yyyy" // default format for printing
 
// open file before becoming a daemon
var fd = C.open(C.fileName, O_WRONLY | O_APPEND | O_CREAT, 438)
if (fd < 0) {
System.print("Error opening %(C.fileName)")
return
}
 
// become a daemon
if (C.daemon(0, 0) < 0) {
System.print("Error creating daemon.")
return
}
 
// redirect stdout
if (C.redirectStdout(fd, STDOUT_FILENO) < 0) {
System.print("Error redirecting stdout.")
return
}
 
// close file
if (C.close(fd) < 0) {
System.print("Error closing %(C.fileName)")
return
}
 
// dump time every second
while (true) {
System.print(UT2Date.call(C.time))
C.sleep(1)
}</lang>
<br>
We now embed this in the following C program, compile and run it.
<lang c>/* gcc dumper.c -o dumper -lwren -lm */
 
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "wren.h"
 
char *fileName;
 
void C_fileName(WrenVM* vm) {
wrenSetSlotString(vm, 0, fileName);
}
 
void C_open(WrenVM* vm) {
const char *pathName = wrenGetSlotString(vm, 1);
int flags = (int)wrenGetSlotDouble(vm, 2);
mode_t mode = (mode_t)wrenGetSlotDouble(vm, 3);
int fd = open(pathName, flags, mode);
wrenSetSlotDouble(vm, 0, (double)fd);
}
 
void C_daemon(WrenVM* vm) {
int nochdir = (int)wrenGetSlotDouble(vm, 1);
int noclose = (int)wrenGetSlotDouble(vm, 2);
int d = daemon(nochdir, noclose);
wrenSetSlotDouble(vm, 0, (double)d);
}
 
void C_redirectStdout(WrenVM* vm) {
int oldfd = (int)wrenGetSlotDouble(vm, 1);
int newfd = (int)wrenGetSlotDouble(vm, 2);
newfd = dup2(oldfd, newfd);
wrenSetSlotDouble(vm, 0, (double)newfd);
}
 
void C_close(WrenVM* vm) {
int fd = (int)wrenGetSlotDouble(vm, 1);
int ret = close(fd);
wrenSetSlotDouble(vm, 0, (double)ret);
}
 
void C_time(WrenVM* vm) {
time_t t = time(NULL);
wrenSetSlotDouble(vm, 0, (double)t);
}
 
void C_sleep(WrenVM* vm) {
unsigned int seconds = (unsigned int) wrenGetSlotDouble(vm, 1);
unsigned int ret = sleep(seconds);
wrenSetSlotDouble(vm, 0, (double)ret);
}
 
WrenForeignMethodFn bindForeignMethod(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature) {
if (strcmp(module, "main") == 0) {
if (strcmp(className, "C") == 0) {
if (isStatic && strcmp(signature, "fileName") == 0) return C_fileName;
if (isStatic && strcmp(signature, "open(_,_,_)") == 0) return C_open;
if (isStatic && strcmp(signature, "daemon(_,_)") == 0) return C_daemon;
if (isStatic && strcmp(signature, "redirectStdout(_,_)") == 0) return C_redirectStdout;
if (isStatic && strcmp(signature, "close(_)") == 0) return C_close;
if (isStatic && strcmp(signature, "time") == 0) return C_time;
if (isStatic && strcmp(signature, "sleep(_)") == 0) return C_sleep;
}
}
return NULL;
}
 
static void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
fflush(stdout); // as we're redirecting stdout to a file
}
 
void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
switch (errorType) {
case WREN_ERROR_COMPILE:
printf("[%s line %d] [Error] %s\n", module, line, msg);
break;
case WREN_ERROR_STACK_TRACE:
printf("[%s line %d] in %s\n", module, line, msg);
break;
case WREN_ERROR_RUNTIME:
printf("[Runtime Error] %s\n", msg);
break;
}
}
 
char *readFile(const char *fileName) {
FILE *f = fopen(fileName, "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *script = malloc(fsize + 1);
size_t ret = fread(script, 1, fsize, f);
if (ret != fsize) printf("Error reading %s\n", fileName);
fclose(f);
script[fsize] = 0;
return script;
}
 
static void loadModuleComplete(WrenVM* vm, const char* module, WrenLoadModuleResult result) {
if( result.source) free((void*)result.source);
}
 
WrenLoadModuleResult loadModule(WrenVM* vm, const char* name) {
WrenLoadModuleResult result = {0};
if (strcmp(name, "random") != 0 && strcmp(name, "meta") != 0) {
result.onComplete = loadModuleComplete;
char fullName[strlen(name) + 6];
strcpy(fullName, name);
strcat(fullName, ".wren");
result.source = readFile(fullName);
}
return result;
}
 
int main(int argc, char **argv) {
fileName = argv[1];
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
config.bindForeignMethodFn = &bindForeignMethod;
config.loadModuleFn = &loadModule;
WrenVM* vm = wrenNewVM(&config);
const char* module = "main";
const char* fileName = "dumper.wren";
char *script = readFile(fileName);
WrenInterpretResult result = wrenInterpret(vm, module, script);
switch (result) {
case WREN_RESULT_COMPILE_ERROR:
printf("Compile Error!\n");
break;
case WREN_RESULT_RUNTIME_ERROR:
printf("Runtime Error!\n");
break;
case WREN_RESULT_SUCCESS:
break;
}
wrenFreeVM(vm);
free(script);
return 0;
}</lang>
 
{{out}}
Sample output:
<pre>
$ ./dumper dump
$ tail -f dump
Sat Dec 18 16:58:26 2021
Sat Dec 18 16:58:27 2021
Sat Dec 18 16:58:28 2021
Sat Dec 18 16:58:29 2021
Sat Dec 18 16:58:30 2021
Sat Dec 18 16:58:31 2021
Sat Dec 18 16:58:32 2021
Sat Dec 18 16:58:33 2021
Sat Dec 18 16:58:34 2021
Sat Dec 18 16:58:35 2021
^C
$ pkill -x dumper
$ rm dump
</pre>
 
{{omit from|Brlcad}}
9,488

edits