Lazarus

Programming => Operating Systems => Linux => Topic started by: auRazor on December 19, 2013, 06:15:38 am

Title: Creating Linux Daemon's
Post by: auRazor on December 19, 2013, 06:15:38 am
I am trying to create a linux Daemon without much success. I have used the lazdaemon code and using the cleandirs as an example. In my code I put a few log calls in and am getting nothing back. Has anyone ever created a daemon for linux if so are you able to point me to an example that works?


I am on ubuntu 13.04 using lazarus 1.0.14 and fpc 2.6.2.

I am starting the daemon from the command line using the script at http://aurawin.com/lazarus/fedora.service (http://aurawin.com/lazarus/fedora.service). The application and script are outside of the normal init.d directory.


unit gwymapper;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, DaemonApp;

type
  TCanalGatewayMapper = class(TDaemonMapper)
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  CanalGatewayMapper: TCanalGatewayMapper;

implementation

procedure RegisterMapper;
begin
  RegisterDaemonMapper(TCanalGatewayMapper)
end;

{$R *.lfm}


initialization
  RegisterMapper;
end.

########################################################################
unit gwyrun;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, DaemonApp, eventlog;

type

  { TCanalGatewayRun }

  TCanalGatewayRun = class(TDaemon)
    procedure DataModuleExecute(Sender: TCustomDaemon);
    procedure DataModuleStart(Sender: TCustomDaemon; var OK: Boolean);
    procedure DataModuleStop(Sender: TCustomDaemon; var OK: Boolean);
  private
    { private declarations }
    sConfigFile : string;
    elLog : TEventLog;
    procedure _startLog;
  public
    { public declarations }
  end;

var
  CanalGatewayRun: TCanalGatewayRun;

implementation

procedure RegisterDaemon;
begin
  RegisterDaemonClass(TCanalGatewayRun)
end;

{$R *.lfm}

procedure TCanalGatewayRun.DataModuleExecute(Sender: TCustomDaemon);
begin

end;

procedure TCanalGatewayRun.DataModuleStart(Sender: TCustomDaemon;
  var OK: Boolean);
begin
  ok := true;
  elLog.Info('Started');
end;

procedure TCanalGatewayRun.DataModuleStop(Sender: TCustomDaemon; var OK: Boolean
  );
begin
  Ok := true;
  elLog.Info('Stopped');
end;

procedure TCanalGatewayRun._startLog;
begin
  LogMessage('Message from canal');
  elLog:=Self.Logger;
  elLog.LogType := ltFile;
  elLog.FileName := '/home/rhenderson/sandbox/canal/gwy.log';
  If (sConfigFile='') then
    elLog.Error('No configuration file found !');
end;


initialization
  RegisterDaemon;
end.
Title: Re: Creating Linux Daemon's
Post by: Leledumbo on December 19, 2013, 05:29:42 pm
Did you follow this (http://wiki.freepascal.org/Daemons_and_Services#Linux_.28Debian.29)? It works for my web application that sits as a daemon.
Title: Re: Creating Linux Daemon's
Post by: snorkel on December 19, 2013, 06:34:22 pm
I could never get lazdaemon to work properly, so I found a pure daemon example, it was pretty out of date and I was able to get it working with some minor changes and it works great. 

http://www.filewatcher.com/p/fp-compiler-2.4.4_2.4.4-0_i386.deb.1902154/usr/share/doc/fp-compiler/2.4.4/unix/daemon.pp.gz.html
Title: Re: Creating Linux Daemon's
Post by: jack_ on July 11, 2014, 08:09:05 pm
It's an old topic but search function show this as a good place, so for next users
I've attach an working Daemon example as a ZIP file.

It's created visually with using Project -> New Project... -> Daemon (service) application

Created in:
Ubuntu 14.04 LTS with Cinnamon
Typhon IDE  4.8.0   Synchronize with Lazarus Source 29-3-2014 SVN Rev 44546
FreePascal  2.7.1   Source 29-3-2014 SVN Rev 27327

msapTemp.lpr
Code: [Select]
Program msapTemp;

Uses
{$IFDEF UNIX}
  CThreads,
{$ENDIF}
  DaemonApp, lazdaemonapp, DaemonMapperUnit1, DaemonUnit1
  { add your units here };

begin
  Application.Initialize;
  Application.Run;
end.

daemonmapperunit1.pas
Code: [Select]
unit DaemonMapperUnit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, DaemonApp;

type
  TDaemonMapper1 = class(TDaemonMapper)
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  DaemonMapper1: TDaemonMapper1;

implementation

procedure RegisterMapper;
begin
  RegisterDaemonMapper(TDaemonMapper1)
end;

{$R *.lfm}


initialization
  RegisterMapper;
end.

!!! Very IMPORTANT !!! - when you create a new daemon project yourself you have to put your TDaemon class name to DaemonClassName !
You click a DaemonMapperUnit1 tab on Editor, then F12 key [sometimes 2 times].
You have an TDataModule form called DaemonMapper1 on top - click on it.
On the Object Inspector you click DaemonDefs [...] button and then on the new window click Add.
Click on the new 0[zero] position and look on the Object Inspector.
There you have to in the DaemonClassName property put your TDaemon class name - in my example you have TDaemon1.
The ZIP file and sources are working and contain above steps completed.

daemonmapperunit1.lfm
Code: [Select]
object DaemonMapper1: TDaemonMapper1
  DaemonDefs = < 
    item
      DaemonClassName = 'TDaemon1'
      Name = 'TDaemon1'
      DisplayName = 'TDaemon1'
      Options = [doAllowStop, doAllowPause]
      WinBindings.Dependencies = <>
      WinBindings.StartType = stBoot
      WinBindings.WaitHint = 0
      WinBindings.IDTag = 0
      WinBindings.ServiceType = stWin32
      WinBindings.ErrorSeverity = esIgnore
      LogStatusReport = False
    end>
  left = 364
  top = 504
end

daemonunit1.pas
Code: [Select]
unit DaemonUnit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, DaemonApp;

type

  { TDaemon1 }
  TDaemon1 = class(TDaemon)
    procedure DataModuleExecute(Sender: TCustomDaemon);
    procedure DataModuleShutDown(Sender: TCustomDaemon);
    procedure DataModuleStart(Sender: TCustomDaemon; var OK: boolean);
    procedure DataModuleStop(Sender: TCustomDaemon; var OK: boolean);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Daemon1: TDaemon1;
  Log: TextFile;

implementation

procedure RegisterDaemon;
begin
  RegisterDaemonClass(TDaemon1);
end;

{$R *.lfm}

{ TDaemon1 }

procedure TDaemon1.DataModuleExecute(Sender: TCustomDaemon);
begin
  while Self.Status = csRunning do
  begin
    sleep(1000);
    WriteLn(Log, datetimetostr(Now));
    Flush(Log);
    LogMessage(DateTimeToStr(Now));
  end;
end;

procedure TDaemon1.DataModuleShutDown(Sender: TCustomDaemon);
begin
  WriteLn(Log, 'Shutdown');
  Flush(Log);
end;

procedure TDaemon1.DataModuleStart(Sender: TCustomDaemon; var OK: boolean);
begin
  OK := True;
  WriteLn(Log, 'Start');
  Flush(Log);
end;

procedure TDaemon1.DataModuleStop(Sender: TCustomDaemon; var OK: boolean);
begin
  OK := True;
  WriteLn(Log, 'Stop');
  Flush(Log);
end;


initialization
  RegisterDaemon;
  AssignFile(Log, 'msaplog.txt');
  Rewrite(Log);
end.


daemonunit1.lfm
Code: [Select]
object Daemon1: TDaemon1
  OldCreateOrder = False
  OnStart = DataModuleStart
  OnStop = DataModuleStop
  OnShutDown = DataModuleShutDown
  OnExecute = DataModuleExecute
  Height = 172
  HorizontalOffset = 342
  VerticalOffset = 210
  Width = 193
end


After build you can run it from Terminal[you have to enter folder where executable file is] with:
Code: [Select]
# ./msapTemp --run
Search for two files as an output:
msapTemp.log [internal Daemon logging file]
and
msaplog.txt [our file for logging with WriteLn]
Title: Re: Creating Linux Daemon's
Post by: BigChimp on July 12, 2014, 09:20:26 am
Thanks for posting that! If you think that
http://wiki.lazarus.freepascal.org/Daemons_and_Services
should be updated, please update it...

Thanks a lot
Title: Re: Creating Linux Daemon's
Post by: AnthonyTekatch on November 10, 2014, 05:52:58 pm
Search for two files as an output:
msapTemp.log [internal Daemon logging file]
and
msaplog.txt [our file for logging with WriteLn]

Where is msapTemp.log stored? I cannot find any such file. I am using Linux.
Title: Re: Creating Linux Daemon's
Post by: JuhaManninen on November 11, 2014, 12:38:52 am
Could somebody please see what is wrong with the CleanDirs example which uses LazDaemon.
I believe it has worked at some moment in the past but not anymore.
Title: Re: Creating Linux Daemon's
Post by: motaz on November 11, 2014, 05:49:06 am
For Linux background services I  used to write normal console applications that has no text output, then I write small shell script to run, stop and check status of this service and put it /etc/init.d/ directory

Check this blog:
http://freepascalanswers.wordpress.com/2013/12/12/service-app/
Title: Re: Creating Linux Daemon's
Post by: snorkel on November 13, 2014, 05:41:29 pm
For Linux background services I  used to write normal console applications that has no text output, then I write small shell script to run, stop and check status of this service and put it /etc/init.d/ directory

Check this blog:
http://freepascalanswers.wordpress.com/2013/12/12/service-app/

Hi Motaz,

nice example and good for simple services, but it does not handle signals, so you can't send it a signal to reload config for example.
Title: Re: Creating Linux Daemon's
Post by: motaz on November 15, 2014, 12:44:16 pm
Quote
but it does not handle signals,
Yes you are right snorkel, it can only start, stop, and check status of service
Title: Re: Creating Linux Daemon's
Post by: jack_ on February 07, 2015, 12:32:48 am
Search for two files as an output:
msapTemp.log [internal Daemon logging file]
and
msaplog.txt [our file for logging with WriteLn]

Where is msapTemp.log stored? I cannot find any such file. I am using Linux.

This is an internal logger file place in the same directory in which you have compiled binary file.
File is created first time when you run daemon using -r or --run command.
Title: Re: Creating Linux Daemon's
Post by: robsoft on March 09, 2015, 11:40:44 pm
This is an internal logger file place in the same directory in which you have compiled binary file.
File is created first time when you run daemon using -r or --run command.

Jack_, thanks for this - that's got me started at last. I couldn't for the life of me figure out what was going on with the LazDaemon stuff, but I think you've given me a push in the right direction. Many thanks!

I'm trying to write something that takes incoming serial data on the raspberry pi, and broadcasts it over the network - or possibly just allows incoming socket connections for 'subscribers' to the data stream. I've never written anything on the Pi before, never used Lazarus before, hardly done much Linux and even my day job is more C# than Delphi these days... an interesting challenge :-)
Title: Re: Creating Linux Daemon's
Post by: richard_rtech on March 09, 2015, 11:47:04 pm
This is an internal logger file place in the same directory in which you have compiled binary file.
File is created first time when you run daemon using -r or --run command.

Jack_, thanks for this - that's got me started at last. I couldn't for the life of me figure out what was going on with the LazDaemon stuff, but I think you've given me a push in the right direction. Many thanks!

I'm trying to write something that takes incoming serial data on the raspberry pi, and broadcasts it over the network - or possibly just allows incoming socket connections for 'subscribers' to the data stream. I've never written anything on the Pi before, never used Lazarus before, hardly done much Linux and even my day job is more C# than Delphi these days... an interesting challenge :-)

Look at SOCAT, you are making work for yourself ;)
Title: Re: Creating Linux Daemon's
Post by: robsoft on March 10, 2015, 12:19:12 am
Look at SOCAT, you are making work for yourself ;)

Aaah.... <googles>.... ok, thanks. That looks interesting. Thanks!
Title: Re: Creating Linux Daemon's
Post by: richard_rtech on March 10, 2015, 12:26:25 am
I was looking at the same thing months back and have used that instead. I have a custom serial bus system we use and that was used to replace a nuked serial <-> ethernet bridge in an emergency.
Title: Re: Creating Linux Daemon's
Post by: robsoft on March 10, 2015, 01:38:38 am
I think my use case might put SOCAT out of question, be interested to hear what you think (thanks for your time so far!)

The electronic balance is connected via RS232 to the Raspberry Pi. At any time, a user can hit the 'print' button on the balance, and the current reading is sent to the Raspi.

Somewhere in the store, on one of the numerous Point-of-sale tills (PCs running our bespoke Delphi [Windows-based] software), a cashier wants to grab that reading. They hit a particular button and the most recent reading from the balance is 'captured' by the POS software.

Ideally, when the Raspi has given the reading to a till, the reading should be cleared so that it doesn't then give that same reading to another till again immediately afterwards - a user would have to go and hit 'print' on the balance to get their own reading, as it were.

If no reading has been taken in the last couple of minutes, the 'last reading' effectively times-out and also becomes cleared (so they don't inadvertently capture an old/spoof reading).


I'm sure I'm making it sound more complex than it is!


In our concept, the Raspi is holding onto the reading until a till asks for it; it hands it over to the first till that asks for it and then resets so that it won't give that data to any other till - basically, a new reading has to be made first. If the Raspi gets a reading and nobody asks for it within a period of time, the reading is deliberately lost.

So I envisioned a small Lazarus daemon on the Raspi that was listening to the balance, capturing the incoming values, and listening on a particular socket for an incoming connection to give the reading to. This daemon would be able to handle the reset & timeout reading logic etc. On the till side, it's just a simple ad-hoc socket connection made at the instant the till wants to grab the current reading.

Do you think I could bend SOCAT to help with this - I've just had it happily forwarding the readings on to a telnet session on a Window box as a test, but the till needs to be connected before the reading is made, as I see it. And as you'd expect, I can open a second connection to SOCAT from another box but this doesn't get any data until the first connection is closed.

Again, thanks for your help - sorry if I've just given you a headache with all the text :-)
Title: Re: Creating Linux Daemon's
Post by: richard_rtech on March 10, 2015, 02:09:23 pm
Replied via PM as this is going OT :)
Title: Re: Creating Linux Daemon's
Post by: ArminLinder on February 24, 2022, 10:36:32 am
Anyone reaching here any time in the future, please note that the above sample will not work well on Windows. The daemon will run, but it will not respond to the Windows Service Control Manager, since TDeamon.execute is not multitasking. See updated wiki at https://wiki.lazarus.freepascal.org/Daemons_and_Services (https://wiki.lazarus.freepascal.org/Daemons_and_Services) for a daemon source code which runs on Windows and Linux.

Cheers, Armin.
TinyPortal © 2005-2018