2016-05-06 8 views
9

मैं अपने डेमॉन के साथ कांटा प्रक्रियाओं की कोशिश कर रहा हूं, और अपने डेमॉन दुर्घटनाओं के मामले में उन्हें अस्वीकार करने की कोशिश कर रहा हूं।गोलांग निष्पादन प्रक्रिया और इसे अस्वीकार करने के लिए

package main 

import (
    "fmt" 
    "os" 
    "os/exec" 
    "syscall" 
    "time" 
) 

func main() { 

    cmd := "myproc" 
    binary, lookErr := exec.LookPath(cmd) 
    if lookErr != nil { 
     panic(lookErr) 
    } 
    fmt.Println(binary) 

    os.Remove("/tmp/stdin") 
    os.Remove("/tmp/stdout") 
    os.Remove("/tmp/stderr") 

    fstdin, err1 := os.Create("/tmp/stdin") 
    fstdout, err2 := os.Create("/tmp/stdout") 
    fstderr, err3 := os.Create("/tmp/stderr") 
    if err1 != nil || err2 != nil || err3 != nil { 
     fmt.Println(err1, err2, err3) 
     panic("WOW") 
    } 

    argv := []string{"hi"} 
    procAttr := syscall.ProcAttr{ 
     Dir: "/tmp", 
     Files: []uintptr{fstdin.Fd(), fstdout.Fd(), fstderr.Fd()}, 
     Env: []string{"VAR1=ABC123"}, 
     Sys: &syscall.SysProcAttr{ 
      Foreground: false, 
     }, 
    } 

    pid, err := syscall.ForkExec(binary, argv, &procAttr) 
    fmt.Println("Spawned proc", pid, err) 

    time.Sleep(time.Second * 100) 
} 

मैं भी एक साधारण आवेदन है कि सोता है और प्रिंट हैलो दुनिया और यह पथ के लिए रखा बना दिया है: नियमित os/exec उच्च स्तरीय, इसलिए मैं syscall.ForkExec के लिए चला गया और निम्नलिखित कोड का उत्पादन किया है।

#include <stdio.h> 

int main(){ 
    while(1){ 
     printf("hello world"); 
     fflush(stdout); 
     usleep(300000); 
     } 
} 

यह काम करता है, हालांकि, प्रक्रिया को पृष्ठभूमि में नहीं भेजा जाता है जैसा कि मैंने उम्मीद की थी, मेरी जाने की प्रक्रिया अभी भी बच्चे का मालिक है। SysProcAttr लिनक्स में निम्न मान है:

type SysProcAttr struct { 
    Chroot  string   // Chroot. 
    Credential *Credential // Credential. 
    Ptrace  bool   // Enable tracing. 
    Setsid  bool   // Create session. 
    Setpgid  bool   // Set process group ID to Pgid, or, if Pgid == 0, to new pid. 
    Setctty  bool   // Set controlling terminal to fd Ctty (only meaningful if Setsid is set) 
    Noctty  bool   // Detach fd 0 from controlling terminal 
    Ctty  int   // Controlling TTY fd 
    Foreground bool   // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY) 
    Pgid  int   // Child's process group ID if Setpgid. 
    Pdeathsig Signal   // Signal that the process will get when its parent dies (Linux only) 
    Cloneflags uintptr  // Flags for clone calls (Linux only) 
    UidMappings []SysProcIDMap // User ID mappings for user namespaces. 
    GidMappings []SysProcIDMap // Group ID mappings for user namespaces. 
    // GidMappingsEnableSetgroups enabling setgroups syscall. 
    // If false, then setgroups syscall will be disabled for the child process. 
    // This parameter is no-op if GidMappings == nil. Otherwise for unprivileged 
    // users this should be set to false for mappings work. 
    GidMappingsEnableSetgroups bool 
} 

मैं भी कोशिश की निम्नलिखित लेकिन यह एक त्रुटि के कारण:

Sys: &syscall.SysProcAttr{ 
    Setsid:  true, 
    Setctty: true, 
    Foreground: false, 
}, 

Spawned proc 0 inappropriate ioctl for device 

इसके अलावा निम्नलिखित:

Sys: &syscall.SysProcAttr{ 
    Setsid:  true, 
    Setctty: true, 
    Foreground: false, 
    Noctty:  true, 
    Setpgid: true, 
}, 

Spawned proc 0 operation not permitted (with root privilleges) 

मैं क्या कर रहा हूँ/गलत मानते हो? नोट: ओएस/exec उच्च स्तर के कहने के बावजूद, मैंने निम्नलिखित भी कोशिश की, लेकिन यह एक ही परिणाम उत्पन्न करता है।

cs := exec.Command(binary) 
cs.SysProcAttr = &syscall.SysProcAttr{ 
    Setctty: true, 
} 
err := cs.Run() 
fmt.Println(err) 
+0

तुम्हें क्या लगता है 'exec.Cmd' भी उच्च स्तर है? आपके पास भी SysProcAttr तक पहुंच है। इसके अलावा, आपकी प्रक्रिया से आपका क्या मतलब है अभी भी बच्चे का मालिक है? क्या यह एक ही प्रक्रिया समूह में है? यदि माता-पिता बाहर निकलते हैं तो इसे पीआईडी ​​1 में फिर से सौंप दिया नहीं जाता है? – JimB

उत्तर

2

एक प्रक्रिया Start() साथ काँटेदार जारी रहेगा के बाद भी अपनी मूल मर जाता है।

func forker() { 
    cmd := exec.Command("sleep", "3") 
    cmd.Start() 
    time.Sleep(2 * time.Second) 
    os.Exit(1) 
} 

यहाँ sleep प्रक्रिया खुशी से 3 सेकंड के लिए पर रहेंगे भले ही माता-पिता की प्रक्रिया केवल 2 सेकंड के लिए रहता है:

$ forker &; while true; do ps -f; sleep 1; done 

    UID PID PPID C STIME TTY   TIME CMD 
    501 71423 69892 0 3:01PM ttys003 0:00.07 forker 
    501 71433 71432 0 3:01PM ttys003 0:00.00 sleep 3 

    UID PID PPID C STIME TTY   TIME CMD 
    501 71423 69892 0 3:01PM ttys003 0:00.07 forker 
    501 71433 71432 0 3:01PM ttys003 0:00.00 sleep 3 

    UID PID PPID C STIME TTY   TIME CMD 
    501 71433  1 0 3:01PM ttys003 0:00.00 sleep 3 

सूचना कैसे माता पिता प्रक्रिया ID (PPID) sleep प्रक्रिया का बन गया 1 जब मूल प्रक्रिया 71432 बाहर निकलती है। इसका मतलब है कि sleep प्रक्रिया अनाथ हो गई है।

+0

लक्ष्य उपरोक्त उदाहरण (तुरंत) में 71432 बराबर 1 बनाना है। – sheerun

+0

प्रश्न phrased है: "[...] मेरे डेमन दुर्घटनाओं के मामले में [एसआईसी]"। तत्काल प्रक्रिया को अनाथ बनाना जरूरी नहीं है। 'स्टार्ट()' के साथ ही यह केवल अनाथ हो जाएगा जब माता-पिता मर जाएंगे। – augustzf

2

Start() method आपको वह चीज़ देना चाहिए जो आप खोज रहे हैं। मेरे स्क्रिप्ट मेरे नमूना जाओ समाप्त कार्यक्रम चलाने के लिए जारी करने के बाद एक साधारण पाठ फ़ाइल संलग्न करने के लिए:

package main 

import (
    "os/exec" 
) 

func main() { 
    cmd := exec.Command("./appender.sh") 
    cmd.Start() 
} 
+1

ध्यान दें कि अगर माता-पिता माता-पिता से stdin/stdout का उपयोग करता है, यदि पैरेंट समाप्त हो जाता है, तो प्रक्रिया ज़ोंबी बन सकती है। – AJPennster

2

ऐसा लगता है कि तुरंत अस्वीकार करने के लिए अच्छी रणनीति os.Argv[0] प्रक्रिया (स्वयं-स्पॉन) उत्पन्न होती है, फिर लक्ष्य प्रक्रिया (Setsid: true के साथ), और फिर पहली स्पॉन्टेड प्रक्रिया से बाहर निकलती है। इस तरह gradchild प्रक्रिया तुरंत पीपीआईडी ​​1 हो जाता है। वैकल्पिक रूप से पहली स्पॉन्डेड प्रक्रिया बाहर निकलने से पहले माता-पिता के लिए stdout के माध्यम से granchild के पिड संवाद कर सकते हैं।

1

डेमोनाइजेशन गो के गोराउटिन शेड्यूलिंग के साथ अच्छा नहीं खेलता है, इसलिए विवरण बहुत गहराई से मिलता है। godaemon में अच्छी चर्चा और अधिक अच्छी चर्चा के लिंक के साथ एक छोटा सा कार्यान्वयन है, और वहां भी अधिक लोकप्रिय और अधिक परंपरागत रूप से कार्यान्वित go-daemon है।

ioctl त्रुटियां जो आप लगभग निश्चित रूप से Setctty के उपयोग से आ रही हैं।

Sys: &syscall.SysProcAttr{ Foreground: false, Setsid: true, },

आप os/exec के Start, जहां बच्चे प्रक्रिया तुरंत reparented नहीं है की तरह अर्थ विज्ञान मिलना चाहिए, लेकिन सुरक्षित रूप से फहराया जाएगा अगर/जब माता-पिता मर जाता है।

operation not permitted आप है देख रहे हैं, /tmp/ में पाइप के बारे में, मुझे लगता है, strace के तहत चल रहा से: openat(AT_FDCWD, "/tmp/stdin", O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 3 epoll_create1(EPOLL_CLOEXEC) = 4 epoll_ctl(4, EPOLL_CTL_ADD, 3, {EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, {u32=471047936, u64=140179613654784}}) = -1 EPERM (Operation not permitted) epoll_ctl(4, EPOLL_CTL_DEL, 3, 0xc420039c24) = -1 EPERM (Operation not permitted) openat(AT_FDCWD, "/tmp/stdout", O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 5 epoll_ctl(4, EPOLL_CTL_ADD, 5, {EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, {u32=471047936, u64=140179613654784}}) = -1 EPERM (Operation not permitted) epoll_ctl(4, EPOLL_CTL_DEL, 5, 0xc420039c24) = -1 EPERM (Operation not permitted) openat(AT_FDCWD, "/tmp/stderr", O_RDWR|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 6 epoll_ctl(4, EPOLL_CTL_ADD, 6, {EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET, {u32=471047936, u64=140179613654784}}) = -1 EPERM (Operation not permitted) epoll_ctl(4, EPOLL_CTL_DEL, 6, 0xc420039c24) = -1 EPERM (Operation not permitted)

संबंधित मुद्दे