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

前端 未结 3 1876
名媛妹妹
名媛妹妹 2020-12-16 22:28

The following (rightfully) doesn\'t work:

package main

import (
        \"os\"
        \"time\"
)

func main() {
        os.Args[0] = \"custom name\"
               


        
3条回答
  •  悲&欢浪女
    2020-12-16 22:39

    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.

提交回复
热议问题