A library for writing system daemons in golang.

go-daemon Build Status GoDoc

Library for writing system daemons in Go.

Now supported only UNIX-based OS (Windows is not supported). But the library was tested only on Linux and OSX, so that if you have an ability to test the library on other platforms, give me feedback, please (#26).

Please, feel free to send me bug reports and fixes. Many thanks to all contributors.

Features

  • Goroutine-safe daemonization;
  • Out of box work with pid-files;
  • Easy handling of system signals;
  • The control of a daemon.

Installation

go get github.com/sevlyar/go-daemon

You can use gopkg.in:

go get gopkg.in/sevlyar/go-daemon.v0

If you want to use the library in production project, please use vendoring, because i can not ensure backward compatibility before release v1.0.

Examples

Documentation

godoc.org/github.com/sevlyar/go-daemon

How it works

We can not use fork syscall in Golang's runtime, because child process doesn't inherit threads and goroutines in that case. The library uses a simple trick: it runs its own copy with a mark - a predefined environment variable. Availability of the variable for the process means an execution in the child's copy. So that if the mark is not setted - the library executes parent's operations and runs its own copy with mark, and if the mark is setted - the library executes child's operations:

func main() {
	Pre()

	context := new(Context)
	child, _ := context.Reborn()

	if child != nil {
		PostParent()
	} else {
		defer context.Release()
		PostChild()
	}
}

Owner
Comments
  • install error

    install error

    Hello ,i am exec go get url ,then prompt follow message: github.com/sevlyar/go-daemon ../../../go/src/github.com/sevlyar/go-daemon/lock_file.go:53:9: undefined: lockFile ../../../go/src/github.com/sevlyar/go-daemon/lock_file.go:58:9: undefined: unlockFile ../../../go/src/github.com/sevlyar/go-daemon/lock_file.go:123:9: undefined: getFdName

    please ,help me ,thanks , runtime environment macos osx go 1.9

  • go-daemon does not remove the pidfile on exit

    go-daemon does not remove the pidfile on exit

    go-daemon does not remove its pidfile even on a clean stop. This can be seen with the sample application. This is a bit odd as daemon-posix.go has:

    // Release provides correct pid-file release in daemon.
    func (d *Context) Release() (err error) {
        if !initialized {
            return
        }
        if d.pidFile != nil {
            err = d.pidFile.Remove()
        }
        return
    }
    

    and Release() is definitely being called, with d.PidFile non-null.

    I'm running OS-X, with today's master. Here's a demo. Note the file pid is not deleted.

    nimrod:sample amb$ go build
    nimrod:sample amb$ ./sample
    nimrod:sample amb$ ps -ef | fgrep sample
      501 22111     1   0  6:34pm ??         0:00.00 [go-daemon sample]
      501 22116 22094   0  6:34pm ttys021    0:00.00 fgrep sample
    nimrod:sample amb$ cat pid
    22111                                                         # linebreak inserted for ease of reading
    nimrod:sample amb$ ./sample -s stop
    nimrod:sample amb$ ps -ef | fgrep sample
      501 22123 22094   0  6:35pm ttys021    0:00.00 fgrep sample
    nimrod:sample amb$ cat pid
    22111                                                         # linebreak inserted for ease of reading
    nimrod:sample amb$
    
  • What this?

    What this?

    Try to get from github:

    D:\Go\src\inframe>go get github.com/sevlyar/go-daemon
    # github.com/sevlyar/go-daemon
    ..\github.com\sevlyar\go-daemon\daemon_posix.go:51: undefined: syscall.Credential
    
  • Is there a new version release plan?

    Is there a new version release plan?

    Hey, we want a stable and suitable version that can be used in the production environment. But I found that it has been a long time since the last version was released(v0.1.5). Will the project be continuously updated with new versions? Is there a new version release plan?

  • Added power support for the travis.yml file with ppc64le. and update go versions for package: go-daemon

    Added power support for the travis.yml file with ppc64le. and update go versions for package: go-daemon

    Added power support for the travis.yml file with ppc64le. This is part of the Ubuntu distribution for ppc64le. This helps us simplify testing later when distributions are re-building and re-releasing.

    updated the go version go:1.12, 1.13 and 1.14

  • Added Support for Illumos via Fcntl

    Added Support for Illumos via Fcntl

    A simple patch to add support for illumos/solaris11 based Distributions. Long story short there is not flock on those systems. We use Fcntl.

    For a detailed explanation from a seasoned engineer look at https://www.perkin.org.uk/posts/solaris-portability-flock.html

  • go-daemon requires cgo on darwin/macOS

    go-daemon requires cgo on darwin/macOS

    I use go-daemon in rclone and it works very well - thanks!

    However I normally cross compile all the binaries. This means I can't support go-daemon on darwin/macOS because it requires cgo.

    This is the only place I found which uses cgo

    https://github.com/sevlyar/go-daemon/blob/32749a731f76154d29bc6a547e6585f320eb235e/lock_file_darwin.go#L10

    And it looks like it might be reasonably easy to remove as all it is used for is to manipulate C strings.

    If you agree, I'd be happy to send a PR to remove the dependency on cgo.

    This would mean I could bring the --daemon flag to macOS which will make my users happy!

  • daily log rotation (by midnight)

    daily log rotation (by midnight)

    Hi sevlyar

    I've tried the library and its work perfectly.

    I just wondering. Did you have try to do go-daemon on daily log rotation (rotated at midnight)?

     func setupLog() {
            lf, err := NewLogFile(logFileName, os.Stderr)
    	if err != nil {
    		log.Fatal("Unable to create log file: ", err)
    	}
    	log.SetOutput(lf)
    	// rotate log every 30 seconds.
    	rotateLogSignal := time.Tick(30 * time.Second)
    	go func() {
    		for {
    			<-rotateLogSignal
    			if err := lf.Rotate(); err != nil {
    				log.Fatal("Unable to rotate log: ", err)
    			}
    		}
    	}()
    }
    

    Kindly advice.

  • generates a blank pid file on Mac (Darwin)

    generates a blank pid file on Mac (Darwin)

    package main
    
    import (
    	"fmt"
    	"github.com/sevlyar/go-daemon"
    	"html"
    	"log"
    	"net/http"
    	"os"
    )
    
    // To terminate the daemon use:
    //  kill `cat pid`
    func main()  {
    
    	fmt.Println(os.Args[1])
    	if os.Args[1] == "test" {
    		test("hello,world")
    	}
    	if os.Args[1] == "hello" {
    		serveHttp()
    	}
    
    }
    
    func test(t string) {
    	cntxt := &daemon.Context{
    		PidFileName: "pid",
    		PidFilePerm: 0644,
    		LogFileName: "log",
    		LogFilePerm: 0640,
    		WorkDir:     "./test2/",
    		Umask:       027,
    		Args:        []string{"[go-daemon sample]", "hello"},
    	}
    
    	d, err := cntxt.Reborn()
    	if err != nil {
    		log.Fatal("Unable to run: ", err)
    	}
    	if d != nil {
    		return
    	}
    	defer cntxt.Release()
    
    	log.Print("- - - - - - - - - - - - - - -")
    	log.Print("daemon started")
    
    	log.Print(t)
    }
    
    func serveHttp() {
    
    	log.Print("testing!")
    	http.HandleFunc("/", httpHandler)
    	http.ListenAndServe("127.0.0.1:3080", nil)
    }
    
    func httpHandler(w http.ResponseWriter, r *http.Request) {
    	log.Printf("request from %s: %s %q", r.RemoteAddr, r.Method, r.URL)
    	fmt.Fprintf(w, "go-daemon: %q", html.EscapeString(r.URL.Path))
    }
    

    it just saves a blank PID file...Nope..Nothing on it...No PIDs

  • Reload flag

    Reload flag

    I run go-daemon on FreeBSD and I don't know if the reload flag is not implemented or I'm ignorant of how to use it (I'm rookie). I add a function that writes in file: func Writer()

    func Worker() {
          for {
                go Writer()
                if _, ok := <-stop; ok {
                      break
                }
          }
    }
    

    If I type go-daemon -s reload It does nothing, so i'm sure that I don't know how it works... How can I reload the functions into func Worker()?

    Thank you!

  • Fix search. Now it will only return a daemon pointer if it is live

    Fix search. Now it will only return a daemon pointer if it is live

    Fix Search of Unix systems. According to the docs for os.FindProcess(pid) this will never be nil even when I process doesn't exist.

    On Unix systems, FindProcess always succeeds and returns a Process for the given pid, regardless of whether the process exists.

  • example signal-handling.go: Resource temporarily unavailable (in MacOS and Ubuntu)

    example signal-handling.go: Resource temporarily unavailable (in MacOS and Ubuntu)

    I assume I completely misunderstand how this example code should work. My apologizes in advance.

    I built the signal-handling.go example without any modifications. Both for MacOS 12.6 and Ubuntu 22.04.1 LTS.

    I execute: ./daemon and the app 'ghosts' into the background. I checked with 'Activity Monitor' (MacOS) and 'htop' (Ubuntu). Next I execute ./daemon reload and I get Resource temporarily unavailable Whatever command I try (reload, stop or quit), the only result is Resource temporarily unavailable.

    Sending signals like SIGHUP and SIGINT using the OS itself does have the expected result.

    So what is the purpose of adding the commands as app arguments?

  • Context.Reborn fails with

    Context.Reborn fails with "write |1: broken pipe" due to a race condition in writing to Context.wpipe

    Platform, version

    • Almalinux 9, x86_64 on Virtuozzo 7 virtualization.

    • go-daemon v0.1.6

    • go 1.19.2

    Problem statement

    Method Context.parent() in daemon_unix.go contains the following code:

            encoder := json.NewEncoder(d.wpipe)
            if err = encoder.Encode(d); err != nil {
                    return
            }
            _, err = fmt.Fprint(d.wpipe, "\n\n")
    

    In some cases the following happens:

    1. parent writes json into d.wpipe with encoder.Encode(d);
    2. child reads json with corresponding call to decoder.Decode(d);
    3. child executes some code, finishes and close the pipe;
    4. parent tries to performs fmt.Fprint(d.wpipe, "\n\n").

    As a result Context.Reborn() fails with write |1: broken pipe though the child process is successfully started.

    Impact

    In some cases Context.Reborn() can fail with write |1: broken pipe though the child process is successfully started.

    Steps to reproduce

    Compile and run the following program on Almalinux 9 x86_64, Virtuozzo 7:

    package main
    import (
            "log"
            daemon "github.com/avoronkov/go-daemon"
    )
    func main() {
            cntxt := &daemon.Context{
                    LogFileName: "sample.log",
                    LogFilePerm: 0640,
            }
            d, err := cntxt.Reborn()
            if err != nil {
                    log.Fatal("Unable to run: ", err)
            }
            if d != nil {
                    // Parent process
                    log.Printf("Parent: OK")
                    return
            }
            defer cntxt.Release()
            log.Print("Child: OK")
    }
    

    Actual result

    The program fails with the following error:

    $ ./prog 
    2022/10/17 20:29:30 Unable to run: write |1: broken pipe
    

    Expected result

    • Program finishes successfully.

    • Parent writes message Parent: OK

    • Child writes message Child: OK into "sample.log"

    Additional information

    The problem was found when I tried to run existing application which uses go-daemon on Almalinux 9 (which is quite new RedHat-based OS).

    Possible fix

    Apply the following patch:

    --- a/daemon_unix.go
    +++ b/daemon_unix.go
    @@ -113,7 +113,6 @@ func (d *Context) parent() (child *os.Process, err error) {
            if err = encoder.Encode(d); err != nil {
                    return
            }
    -       _, err = fmt.Fprint(d.wpipe, "\n\n")
            return
     }
     
    

    Looks like writing "\n\n" into a pipe after encoding json is redundant. At least I was not able to find the problem it fixes.

  • error message EOF

    error message EOF

    ctx := &daemon.Context{}
    d, err := ctx.Reborn()
    if err != nil {
    	// When I use exec.Command to execute the sh script and the sh script starts this program, the error prompts EOF
    	return
    }
    if d != nil {
    	return
    }
    defer ctx.Release()
    
  • Not working with Linux systemd

    Not working with Linux systemd

    [Unit] Description=Golang HTTP Server After=network-online.target remote-fs.target nss-lookup.target Wants=network-online.target

    [Service] Type=forking PIDFile=/home/sample.pid ExecStart=/home/daemon/go-test ExecReload=/home/daemon/go-test -s reload ExecStop=/home/daemon/go-test -s stop

    KillMode=none PrivateTmp=false Restart=on-failure RestartSec=5

    CPUAccounting=false TasksAccounting=false MemoryAccounting=false

    [Install] WantedBy=multi-user.target Alias=gotest.service

  • enable setting pgid

    enable setting pgid

    After reborn, the new process get pgid the same as it's process id by default. I need to be able to customize the pgid so that I could kill it nicely since the reborn process becomes an orphan process.

    By the way, directly calling to syscall.Setpgid would fail: operation not permitted

    pgid, _ := syscall.Getpgid(os.Getpid())
    cntxt := &daemon.Context{
    	Umask: 027,
    	Env:   append(os.Environ(), "PGID="+strconv.Itoa(pgid)),
    }
    
    d, _ := cntxt.Reborn()
    defer cntxt.Release()
    
    for _, k := range os.Environ() {
            if strings.HasPrefix(k, "PGID=") {
    	        pgid, _ := strconv.Atoi(strings.Split(k, "=")[1])
    	        if err := syscall.Setpgid(os.Getpid(), pgid); err != nil {
    		        panic("fail to set pgid")
    	        }
            }
    }
    

    I'm wondering if there is any way to achieve what I need?

Go simple progress bar writing to output
Go simple progress bar writing to output

?? progress-go Go simple progress bar writing to output ?? ABOUT Contributors: Rafał Lorenz Want to contribute ? Feel free to send pull requests! Have

Oct 30, 2022
remindme is a simple application to set reminders from the CLI that integrates with your system's notification system.
remindme is a simple application to set reminders from the CLI that integrates with your system's notification system.

remindme remindme is a simple application to set reminders from the CLI that integrates with your system's notification system. Examples Once the serv

Nov 24, 2022
Jsos - A operating system that runs system-level javascript, based on the Linux kernel

JsOS ?? An linux-based operating system that runs Javascript code at the system-

Jan 6, 2023
Command Line Alias Manager and Plugin System - Written in Golang
Command Line Alias Manager and Plugin System - Written in Golang

aly - Command Line Alias Manager and Packager Aly offers the simplest way to manage, share, and obtain command line aliases! Warning: This project is

Jun 16, 2022
🔹 Golang module to move the terminal cursor in any direction on every operating system.
🔹 Golang module to move the terminal cursor in any direction on every operating system.

AtomicGo | cursor Get The Module | Documentation | Contributing | Code of Conduct Description Package cursor contains cross-platform methods to move t

Dec 22, 2022
A personal knowledge management and sharing system for VSCode
A personal knowledge management and sharing system for VSCode

Foam ?? This is an early stage project under rapid development. For updates join the Foam community Discord! ?? Foam is a personal knowledge managemen

Jan 9, 2023
Procmon is a Linux reimagining of the classic Procmon tool from the Sysinternals suite of tools for Windows. Procmon provides a convenient and efficient way for Linux developers to trace the syscall activity on the system.
Procmon is a Linux reimagining of the classic Procmon tool from the Sysinternals suite of tools for Windows. Procmon provides a convenient and efficient way for Linux developers to trace the syscall activity on the system.

Process Monitor for Linux (Preview) Process Monitor (Procmon) is a Linux reimagining of the classic Procmon tool from the Sysinternals suite of tools

Dec 29, 2022
A client for managing authzed or any API-compatible system from your command line.

zed A client for managing authzed or any API-compatible system from your command line. Installation zed is currently packaged by as a head-only Homebr

Dec 31, 2022
An Alfred Workflow for the Johnny.Decimal filing system
An Alfred Workflow for the Johnny.Decimal filing system

alfred-jd An Alfred Workflow for the Johnny.Decimal filing system This workflow provides tools for working with the brilliant Johnny.Decimal filing sy

Dec 26, 2022
Libraries and CLIs for my personal all-in-one productivity system including components like bookmarks, notes, todos, projects, etc.

bntp.go Libraries and CLIs for my personal all-in-one productivity system including components like bookmarks, notes, todos, projects, etc. Neovim int

Sep 13, 2022
go-shellcommand is the package providing the function System like the one of the programming language C.

go-shellcommand go-shellcommand is the package providing the function System like the one of the programming language C. process, err := shellcommand.

Oct 17, 2021
🐘 Cross-platform, neofetch alternative for fetching system info.
 🐘 Cross-platform, neofetch alternative for fetching system info.

elefetch ?? Cross-platform, neofetch alternative for fetching system info. Installation go get: go get -u github.com/burntcarrot/elefetch Binaries Bin

Jan 23, 2022
Virtualization system for remote code execution.

Delta CLI Command line application for executing source code inside of a container. Build: go build -o ./delta-cli ./main.go Usage: ./delta-cli <path

Nov 20, 2021
🖼️ A command-line system information tool written in bash 3.2+
🖼️  A command-line system information tool written in bash 3.2+

A command-line system information tool written in bash 3.2+ Neofetch is a command-line system information tool written in bash 3.2+. Neofetch displays

Dec 30, 2022
Gofetch is a pretty command-line "Go and System information" tool written in Go
Gofetch is a pretty command-line

GoFetch Show off your Go information with this cool command-line tool! Report Bug || Request Feature Table of Contents About the Project Built With Ge

Nov 1, 2022
CLI Tool for System Administration

CLI CLI Tool for System Administration Description CLI was developed by Heiko for internal purposes for reoccuring actions The aim is to provide syste

Dec 13, 2021
Green: a distribute key value system for optimize block chain data
Green: a distribute key value system for optimize block chain data

Introduce Green is a distribute key value system for optimize block chain data A

Jan 6, 2022
StudentMgmtSystem - Project for Student Management System and use of CURD Operation

StudentMgmtSystem Project for Student Management System and use of CURD Operatio

Jan 4, 2022
A CLI tool to find the absolute path of any folder in your local file system.

Table of Contents What is this? How to use this Examples of usage How to compile it What am I looking at It's a CLI tool that I made for finding the a

Jan 15, 2022