Run as a daemon or service: Difference between revisions

From Rosetta Code
Content added Content deleted
m ({{omit from|TPP}})
m (omissions)
Line 153: Line 153:
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.
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.


{{omit from|Brlcad}}
{{omit from|GUISS}}
{{omit from|Lilypond}}
{{omit from|Openscad}}
{{omit from|TPP}}
{{omit from|TPP}}
{{omit from|ZX Spectrum Basic}}

Revision as of 18:21, 11 March 2013

Run as a daemon or service is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

A daemon is a service that runs in the background independent of a users login session.

Demonstrate how a program disconnects from the terminal to run as a daemon in the background.

Write a small program that writes a message roughly once a second to its stdout which should be redirected to a file.

Note that in some language implementations it may not be possible to disconnect from the terminal, and instead the process needs to be started with stdout (and stdin) redirected to files before program start. If that is the case then a helper program to set up this redirection should be written in the language itself. A shell wrapper, as would be the usual solution on Unix systems, is not appropriate.

C

Library: BSD libc

BSD provides a convenient daemon(3) function. GNU libc also provides daemon(3), but POSIX omits it, so it is not portable. Other BSDisms in this program are __progname and <err.h>.

The task also wants to redirect stdout. This program does so with dup2(2). Had we wanted to directly write to a file, we could open the file with file = fopen(argv[1], "a"), and write to file instead of stdout.

<lang c>#include <err.h>

  1. include <errno.h>
  2. include <fcntl.h>
  3. include <stdlib.h>
  4. include <stdio.h>
  5. include <string.h>
  6. include <syslog.h>
  7. include <time.h>
  8. include <unistd.h>

int main(int argc, char **argv) { extern char *__progname; time_t clock; int fd;

if (argc != 2) { fprintf(stderr, "usage: %s file\n", __progname); exit(1); }

/* Open the file before becoming a daemon. */ fd = open(argv[1], O_WRONLY | O_APPEND | O_CREAT, 0666); if (fd < 0) err(1, argv[1]);

/* * Become a daemon. Lose terminal, current working directory, * stdin, stdout, stderr. */ if (daemon(0, 0) < 0) err(1, "daemon");

/* Redirect stdout. */ if (dup2(fd, STDOUT_FILENO) < 0) { syslog(LOG_ERR, "dup2: %s", strerror(errno)); exit(1); } close(fd);

/* Dump clock. */ for (;;) { time(&clock); fputs(ctime(&clock), stdout); if (fflush(stdout) == EOF) { syslog(LOG_ERR, "%s: %s", argv[1], strerror(errno)); exit(1); } sleep(1); /* Can wake early or drift late. */ } }</lang>

$ make dumper
cc -O2 -pipe    -o dumper dumper.c 
$ ./dumper dump
$ tail -f dump
Fri Nov 18 13:50:41 2011
Fri Nov 18 13:50:42 2011
Fri Nov 18 13:50:43 2011
Fri Nov 18 13:50:44 2011
Fri Nov 18 13:50:45 2011
^C
$ pkill -x dumper
$ rm dump

PicoLisp

<lang PicoLisp>(unless (fork)

  (out "file.log"
     (println *Pid)    # First write the daemon's PID to the file
     (for N 3600       # Write count for about one hour (if not killed)
        (wait 1000)
        (println N)
        (flush) ) )
  (bye) )              # Child terminates after one hour

(bye) # Parent terminates immediately</lang>

Pike

__FILE__ is a preprocessor definition that contains the current filename. if the first argument is "daemon" the program will be restarted with stdout redirected to "foo".

<lang Pike>int main(int argc, array argv) {

   if (sizeof(argv)>1 && argv[1] == "daemon")
   {
       Stdio.File newout = Stdio.File("foo", "wc");
       Process.spawn_pike(({ __FILE__ }), ([ "stdout":newout ]));
       return 1;
   }
   int i = 100;
   while(i--)
   {
       write(i+"\n");
       sleep(0.1);
   }

}</lang>

Tcl

Tcl doesn't come with tools for converting the process into a daemon, but can build them easily enough. Here's the BSD daemon function mapped into a Tcl command in a package.

Library: Critcl

<lang tcl>package provide daemon 1 package require critcl

critcl::ccode {

   #include <stdlib.h>

} critcl::cproc daemon {Tcl_Interp* interp} ok {

   if (daemon(0, 0) < 0) {

Tcl_AppendResult(interp, "cannot switch to daemon operation: ", Tcl_PosixError(interp), NULL); return TCL_ERROR;

   }
   return TCL_OK;

}</lang> These tools can then be used to solve this task: <lang tcl>### Command line argument parsing if {$argc < 1} {

   puts "usage: $argv0 file ?message...?"
   exit 1

} elseif {$argc == 1} {

   set filename [lindex $argv 0]
   set message "Hi there!"

} else {

   set message [join [lassign $argv filename]]

}

      1. Daemonize

package require daemon daemon close stdout; open $filename  ;# Redirects stdout!

      1. Print the message to the file every second until killed

proc every {ms body} {eval $body; after $ms [info level 0]} every 1000 {puts "[clock format [clock seconds]]: $message"} 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.