P4dctl

About p4dctl
I was always frustrated by how hard it was to get a good (init) script for starting and stopping Perforce Services: one that worked on most UNIX platforms, and allowed for the fact that while the servers wouldn't run as root, both root and non-root users could start and stop them. Then there's the issue of 'pidfiles': if your startup script creates a pidfile owned by root, the pidfile can become stale if another user (perhaps 'perforce') stops and restarts the server; often the permissions on these files mean that even if the other user wants to do the right thing, they can be thwarted.

Most Perforce sites will also run more than one type of Perforce server (P4D/P4Web/P4FTPD etc.), and the problem is compounded the more servers you run.

So I wrote p4dctl. It allows the administrator to specify all the Perforce services running on a machine in a single, simple text file and allows root and non-root users to start and stop the services. Naturally, non-root users can only affect servers they own. Since p4dctl is a setuid root executable, it uses its root privileges to manage the pid files (for security reasons, it drops these privileges for all other actions), so even if a non-root user is restarting a service, the pidfile will be correctly maintained. This is important for those services that must be stopped using a SIGTERM.

Features

 * Common interface for root and non-root users
 * Non-root users limited to services they own
 * Central configuration of all services
 * Bulk start/stop of services
 * all services
 * all services of a particular type
 * all services by name
 * Easy way to check status of all services
 * Maintains pidfiles under /var/run
 * Sets process name intelligently (e.g. 'p4d [main/1666]' )
 * Designed to be a secure setuid root executable

Configuration
For security reasons, the configuration file path is hard-coded into p4dctl: /etc/p4d.conf. This ensures that only a privileged user can create or edit the file.

A sample configuration looks like this:

#--- #--- P4DEBUG =      server=3 P4LOG  =       log P4CONFIG =     .p4config #--- #--- p4d main {    Owner       =       perforce Execute    =       /usr/local/bin/p4d Umask      =       077 P4ROOT     =       /home/perforce/p4-main P4JOURNAL  =       journal P4PORT     =       1666 PATH       =       /bin:/usr/bin:/usr/local/bin } p4web main {     Owner       =       perforce Execute    =       /usr/local/bin/p4web Args       =       "-b" P4WEBPORT  =       8080 P4PORT     =       1666 P4CLIENT   =       p4webclient PATH       =       /bin:/usr/bin:/usr/local/bin }
 * 1) Global environment variables - passed to ALL services
 * 1) Server specifications

Notice that the service is given a name (in this case both services use 'main'), and an owner. The idea is that only root, and the user 'perforce' can manipulate the main servers, and the environments of the servers are tightly controlled.

Support
This software is not an officially supported Perforce product. Please [mailto:tony@smee.org contact me] directly for help.

Example Usage
Using the configuration file above, here are some example commands showing how p4dctl can be used:

Starting All Services
p4dctl start -a

Starting All P4D Servers
p4dctl start -a -t p4d

Starting All Servers by Name
p4dctl start main

Note that the example above would start both the P4D and P4Web servers - quite a simple way of managing groups of servers.

Sample Init Script
This is where it all started, so there wouldn't be much point in doing this if I didn't show you how to use this in an init script! Here's the one I use on Debian boxes:

. /lib/lsb/init-functions PROG=/usr/local/bin/p4dctl [ -x $PROG ] || exit 0 case "$1" in start) log_begin_msg "Starting Perforce services..."         $PROG -q start -a         log_end_msg $?         ;; stop)   log_begin_msg "Stopping Perforce services..." $PROG -q stop -a log_end_msg $? ;; restart) log_begin_msg "Restarting Perforce servicesa..."        $PROG -q restart -a         log_end_msg $?         ;; *)      log_success_msg "Usage: /etc/init.d/p4d start|stop|restart" exit 1 ;; esac exit 0
 * 1) !/bin/bash
 * 1) BEGIN INIT INFO
 * 2) Provides:          p4dctl
 * 3) Required-Start:
 * 4) Required-Stop:
 * 5) Default-Start:     2 3 4 5
 * 6) Default-Stop:      0 1 6
 * 7) Short-Description: Start Perforce services at boot time
 * 8) Description:       This script starts all Perforce services managed
 * 9)                    by p4dctl as configured in /etc/p4d.conf.
 * 10) END INIT INFO
 * 1) Source init-function library containing e.g. log_daemon_msg

Obviously there's some Debian-specific stuff in there, but the main point is that the simple act of starting and stopping all services is reduced to a one-liner.

Downloads
Most people should build p4dctl from the source. To do so, you'll need the Perforce C++ API for your platform, a suitable C++ compiler, and Perforce Jam.

There are a couple of Linux binaries available from the Public Depot that people are welcome to use. If other platforms are required, please [mailto:tony@smee.org contact me].

Global Syntax
p4dctl [global options] [options] [ ] Where 'global options' are: -c      Path to configuration file (/etc/p4d.conf) -p  Path to pid file directory (/var/run) -q             Quiet mode -v             Verbose output Recognised commands are: start          Start specified servers stop           Stop specified servers restart        Restart specified servers status         Check the status of specified servers checkpoint     Checkpoint specified P4D servers journal        Rotate journals of specified P4D servers

Start Command Syntax
p4dctl [global options] start [options] [ ] Where [options] are: -a             Start all servers -t      Start only servers of specified type

If is specified, then the operation is limited to servers with that name.

Stop Command Syntax
p4dctl [global options] stop [options] [ ] Where [options] are: -a             Stop all servers -t      Stop only servers of specified type

If is specified, then the operation is limited to servers with that name.

Restart Command Syntax
p4dctl [global options] restart [options] [ ] Where [options] are: -a             Restart all servers -t      Restart only servers of specified type

If is specified, then the operation is limited to servers with that name.

Status Command Syntax
p4dctl [global options] status [options] [ ] Where [options] are: -a             Check status of all servers -t      Check only servers of specified type

If is specified, then the operation is limited to servers with that name.

Checkpoint Command Syntax
p4dctl [global options] checkpoint [options] [ ] Where [options] are: -a             Checkpoint all P4D servers

If is specified, then the operation is limited to servers with that name.

Journal Command Syntax
p4dctl [global options] journal [options] [ ] Where [options] are: -a             Rotate journals for all P4D servers