// runpbcollect is a wrapper which runs the pbcollect process.
//
// pbcollect listens on a TCP port for data streamed in by barrel
// processes. Those barrels will continuously send data to the same
// pbcollect process for up to 5 minutes, then try to reconnect,
// potentially finding a new listener. If successful, they'll
// immediately close their outstanding connection, switching over to
// the new listener.
//
// Because of this pattern of behavior, pbcollect's restarts are
// somewhat delicate.  To shutdown a pbcollect process, we should
// immediately stop accepting new connections (freeing the port for a
// new listener) but continue processing existing connections for five
// minutes. This lets the barrel processes continue sending data
// uninterrupted.  Then, we can start a new pbcollect process on the
// same old port, ready to receive data as soon as barrels reconnect.
//
// This is done by running pbcollect through a wrapper. On Linux,
// we've got access to the PDEATHSIG APIs of prctl(2), which instruct
// the kernel to send a particular signal to the child (pbcollect)
// process when the wrapper exits. On non-Linux platforms like OSX, we
// just poll getppid(2) to check whether the parent wrapper has
// exited. Either way, it's pbcollect's job to stop listening for new
// connections when it is asked to shut down.
//
// Meanwhile, daemontools is satisfied when the wrapper process dies,
// so it immediately starts a new wrapper which will attempt to bind
// to the port. It might fail if this happens during the old
// pbcollect's polling interval.
package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"

	"code.justin.tv/common/chitin"
	_ "code.justin.tv/common/golibs/bininfo"
)

func main() {
	bin := flag.String("cmd", "", "path to pbcollect executable")
	flag.Parse()

	err := chitin.ExperimentalTraceProcessOptIn()
	if err != nil {
		log.Fatalf("trace enable err=%q", err)
	}

	if *bin == "" {
		fmt.Println("FATAL: Did not receive any value for the -cmd flag. " +
			"This must be set to point to the pbcollect executable, like './pbcollect'.")
		os.Exit(1)
	}

	// Change the default flag values to adjust how pbcollect is
	// run. Don't add flags here.
	cmd := exec.Command(*bin)

	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	// On Linux, we configure the process to receive SIGUSR2 when this
	// wrapper exits. On all other systems, the following line does
	// nothing.
	cmd.SysProcAttr = cmdAttributes

	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}
}
