Writing resident programs (so-called daemons) under Linux

There are at least two ways to run a program in background under Linux:

  1. adding an ampersand (&) to the command line, like this: program param1 param2 param3 &.
  2. using the screen program, like this: screen -m -d program param1 param2.

But we aren't programmers to count on the user to run our program in one of these ways. I'll show you how to make you program put itself in the background. We're first going to use the daemon system call (see: man 3 daemon) from the C library. This is why the program writing process will be different than usually:

  1. instead of using LD to link the program, we're going to use GCC (which, seeing the .o extension in our file's name, will link it correctly with the C library, without compiling)
  2. since we're using GCC and the C library (which already has its own _start symbol), our code will begin with the main label (the same as in programs written in the C language)
  3. the daemon function must be declared as external (extern)

To see that our daemon (TSR in Linux) really is working, we'll put a loop inside, which displays a message once in a while. To make a pause in execution, we're going to use the sys_nanosleep system function (number 162).

As you can see on the manual page, the daemon function accepts 2 integers (DWORDs) as parameters:

After saying all this, it's time to move on to the example program. Its job is to go into daemon mode and infinitely display the given message each 5 seconds. Thus, the fact that the program is working, will be visible on the terminal on which the program was started. The program itself will also be visible on the processes list (ps -A command). The only way to stop it will be to kill it using the kill command.

Here's the code in NASM syntax:


(skip the code)
; Program going into daemon mode
;
; Author: Bogdan D., bogdandr (at) op.pl
;
; assemble:
; nasm -f elf -o demon.o demon.asm
; gcc -o demon demon.o


extern daemon			; external function declaration

section .text			; beginning of the code section
global main			; the symbol "main" must be global
				; for GCC to see it

main:
	push	dword 1		; second parameter
	push	dword 1		; first parameter
	call	daemon		; calling the daemon function
	add	esp, 8		; removing parameters from the stack

			; interval between consecutive messages
			; will last for 5 seconds and 0 nanoseconds:
	mov	dword [t1+timespec.tv_nsec], 0
	mov	dword [t1+timespec.tv_sec], 5

.petla:
	mov	eax, 4		; file writing function
	mov	ebx, 1		; standard output
	mov	ecx, napis	; what to write
	mov	edx, napis_dl	; length of the message
	int	80h

	mov     eax, 162	; sys_nanosleep
	mov     ebx, t1		; wait for this long
	mov     ecx, 0	; address of a second timespec structure for the result
	int     80h		; make the pause...

	jmp	.petla		; start all over again....

				; the below code will never be executed
	mov	eax, 1
	xor	ebx, ebx
	int	80h		; exit the program

section .data

napis		db	"Your daemon is speaking.", 10
napis_dl	equ	$ - napis

struc timespec			; timespec structure definition
				; (anly as a data type)
	.tv_sec:	resd 1
	.tv_nsec:	resd 1
endstruc

t1 istruc timespec		; create the t1 variable as a whole
				; timespec structure

Assembling and linking goes like this:

	nasm -f elf -o demon.o demon.asm
	gcc -o demon demon.o

One thing needs to mentioned: the sole fact that a program is a daemon does NOT mean that it is working with root privileges (and whole of the system security is useless).


Writing resident programs with int 80h

The daemon function is from the C library, but you can transform it into code which uses only the int 80h. The code of the function is in the misc/daemon.c file in the glibc library sources. It is not long and it can be easily transformed into the following macro:


(skip the macro)
%macro daemon 2
	; first parameter: nochdir - not to change the working
	;				directory to the root directory?
	; second parameter: noclose - not to close stdin and stdout?

	mov	eax, 2
	int	80h		; sys_fork

	cmp	eax, 0
	jl	%%koniec	; EAX < 0 means error

	test	eax, eax
	jz	%%dalej		; EAX = 0 in the child process
				; EAX > 0 in the parent process

	mov	eax, 1
	xor	ebx, ebx
	int	80h		; sys_exit - parent finishes work

 %%glowny:	db	"/", 0
 %%devnull:	db	"/dev/null", 0

 %%dalej:
	mov	eax, 66		; sys_setsid
	int	80h		; create a new session and set GID

	cmp	eax, 0
	jl	%%koniec	; EAX < 0 means error

	%if %1 = 0

		mov	eax, 12		; sys_chdir
		mov	ebx, %%glowny
		int	80h		; change directory to root
	%endif

	%if %2 = 0

		; open /dev/null:
		mov	eax, 5
		mov	ebx, %%devnull
		mov	ecx, 2
		mov	edx, 0
		int	80h

		cmp	eax, 0
		jl	%%koniec	; EAX < 0 means error

		mov	ebx, eax	; EBX = /dev/null descriptor

		; duplicate the standard input, output and error output
		; descriptors to an open /dev/null descriptor and close
		; the descriptor after this

		mov	eax, 63
		mov	ecx, 0		; input
		int	80h

		mov	eax, 63
		mov	ecx, 1		; output
		int	80h

		mov	eax, 63
		mov	ecx, 2		; error output
		int	80h

		mov	eax, 6
		int	80h		; close /dev/null

	%endif
 %%koniec:

%endmacro

; usage:
	daemon 1, 1	; no PUSH and ADD ESP

No we can go back to the old program type, where the start symbol was _start and linking was done with LD, and not GCC with the C library.


On-line contents (access key 2)
Helpers for people with disabilities (access key 0)