Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting process name (as seen by `ps`) in Go

Tags:

linux

process

go

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 as a built-in functionality (in Ruby, for instance, it is only a matter of assigning to $0) or as a third-party library (Python).

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

like image 834
Sridhar Ratnakumar Avatar asked Feb 17 '13 21:02

Sridhar Ratnakumar


2 Answers

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.

like image 95
Kyle Lemons Avatar answered Nov 19 '22 19:11

Kyle Lemons


To change a process name on Linux, you need to use the prctl system call combined with the PR_SET_NAME option.

At the moment, I don't think you can do this in Go code. You can, however, build a small C module to do this and then integrate it into your Go build.

like image 4
Daniel Avatar answered Nov 19 '22 18:11

Daniel