Setting process name (as seen by `ps`) in Go
Question: The following (rightfully) doesn't work:

    
    
    package main
    
    import (
            "os"
            "time"
    )
    
    func main() {
            os.Args[0] = "custom name"
            println("sleeping")
            time.Sleep(1000 * time.Second)
            println("done")
    }
    

Some languages provide this feature of [setting process
name](http://www.steve.org.uk/Reference/Unix/faq_2.html#SEC22) as a built-in
functionality (in Ruby, for instance, it is only a matter of [assigning
to](https://github.com/mperham/sidekiq/blob/master/lib/sidekiq/launcher.rb#L27)
`$0`) or as a third-party library
([Python](http://pypi.python.org/pypi/setproctitle)).

I'm looking for a solution that works, at least, on Linux.


Answer: There are multiple ways to accomplish this, and many of them only work in
certain situations. I don't really recommend doing it, as (for one thing) it
can result in your process showing up with different names in different
situations. They require using syscall and/or unsafe, and so you're
deliberately subverting the safety of the Go language. That said, however,
your options seem to be:

## Modify argv[0]

    
    
    func SetProcessName(name string) error {
        argv0str := (*reflect.StringHeader)(unsafe.Pointer(&os.Args[0]))
        argv0 := (*[1 << 30]byte)(unsafe.Pointer(argv0str.Data))[:argv0str.Len]
    
        n := copy(argv0, name)
        if n < len(argv0) {
                argv0[n] = 0
        }
    
        return nil
    }
    

In Go, you don't have access to the actual argv array itself (without calling
internal runtime functions), so you are limited to a new name no longer than
the length of the current process name.

This seems to mostly work on both Darwin and Linux.

## Call PR_SET_NAME

    
    
    func SetProcessName(name string) error {
        bytes := append([]byte(name), 0)
        ptr := unsafe.Pointer(&bytes[0])
        if _, _, errno := syscall.RawSyscall6(syscall.SYS_PRCTL, syscall.PR_SET_NAME, uintptr(ptr), 0, 0, 0, 0); errno != 0 {
                return syscall.Errno(errno)
        }
        return nil
    }
    

The new name can be at most 16 bytes.

This doesn't work on Darwin, and doesn't seem to do much on Linux, though it
succeeds and PR_GET_NAME reports the correct name afterward. This may be
something peculiar about my Linux VM, though.

