...

Source file src/github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/util/util.go

Documentation: github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/util

     1  // Copyright 2021 Chaos Mesh Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  
    16  package util
    17  
    18  import (
    19  	"fmt"
    20  	"io"
    21  	"os"
    22  	"strconv"
    23  	"sync"
    24  
    25  	"github.com/go-logr/logr"
    26  	"github.com/pkg/errors"
    27  
    28  	"github.com/chaos-mesh/chaos-mesh/pkg/bpm"
    29  	"github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/graph"
    30  )
    31  
    32  // ReadCommName returns the command name of process
    33  func ReadCommName(pid int) (string, error) {
    34  	f, err := os.Open(fmt.Sprintf("%s/%d/comm", bpm.DefaultProcPrefix, pid))
    35  	if err != nil {
    36  		return "", err
    37  	}
    38  	defer f.Close()
    39  
    40  	b, err := io.ReadAll(f)
    41  	if err != nil {
    42  		return "", err
    43  	}
    44  
    45  	return string(b), nil
    46  }
    47  
    48  // GetChildProcesses will return all child processes's pid. Include all generations.
    49  // Only return error when `/proc` cannot be read.
    50  func GetChildProcesses(ppid uint32, logger logr.Logger) ([]uint32, error) {
    51  	procs, err := os.ReadDir(bpm.DefaultProcPrefix)
    52  	if err != nil {
    53  		return nil, errors.Wrapf(err, "read /proc")
    54  	}
    55  
    56  	type processPair struct {
    57  		Pid  uint32
    58  		Ppid uint32
    59  	}
    60  
    61  	pairs := make(chan processPair)
    62  	done := make(chan bool)
    63  
    64  	go func() {
    65  		var wg sync.WaitGroup
    66  
    67  		for _, proc := range procs {
    68  			_, err := strconv.ParseUint(proc.Name(), 10, 32)
    69  			if err != nil {
    70  				continue
    71  			}
    72  
    73  			statusPath := bpm.DefaultProcPrefix + "/" + proc.Name() + "/stat"
    74  
    75  			wg.Add(1)
    76  			go func() {
    77  				defer wg.Done()
    78  
    79  				reader, err := os.Open(statusPath)
    80  				if err != nil {
    81  					logger.Error(err, "read status file error", "path", statusPath)
    82  					return
    83  				}
    84  				defer reader.Close()
    85  
    86  				var (
    87  					pid    uint32
    88  					comm   string
    89  					state  string
    90  					parent uint32
    91  				)
    92  				// according to procfs's man page
    93  				fmt.Fscanf(reader, "%d %s %s %d", &pid, &comm, &state, &parent)
    94  
    95  				pairs <- processPair{
    96  					Pid:  pid,
    97  					Ppid: parent,
    98  				}
    99  			}()
   100  		}
   101  
   102  		wg.Wait()
   103  		done <- true
   104  	}()
   105  
   106  	processGraph := graph.NewGraph()
   107  	for {
   108  		select {
   109  		case pair := <-pairs:
   110  			processGraph.Insert(pair.Ppid, pair.Pid)
   111  		case <-done:
   112  			return processGraph.Flatten(ppid, logger), nil
   113  		}
   114  	}
   115  }
   116  
   117  func EncodeOutputToError(output []byte, err error) error {
   118  	return errors.Errorf("error code: %v, msg: %s", err, string(output))
   119  }
   120