Beispiel #1
0
// Walk walks the supplied directory (expecting it to look like /proc)
// and marshalls the files into instances of Process, which it then
// passes one-by-one to the supplied function. Walk is only made public
// so that is can be tested.
func (w *walker) Walk(f func(Process, Process)) error {
	dirEntries, err := fs.ReadDirNames(w.procRoot)
	if err != nil {
		return err
	}

	for _, filename := range dirEntries {
		pid, err := strconv.Atoi(filename)
		if err != nil {
			continue
		}

		ppid, threads, jiffies, rss, rssLimit, err := readStats(path.Join(w.procRoot, filename, "stat"))
		if err != nil {
			continue
		}

		openFiles, err := fs.ReadDirNames(path.Join(w.procRoot, filename, "fd"))
		if err != nil {
			continue
		}

		openFilesLimit, err := readLimits(path.Join(w.procRoot, filename, "limits"))
		if err != nil {
			continue
		}

		cmdline, name := "", "(unknown)"
		if cmdlineBuf, err := cachedReadFile(path.Join(w.procRoot, filename, "cmdline")); err == nil {
			// like proc, treat name as the first element of command line
			i := bytes.IndexByte(cmdlineBuf, '\000')
			if i == -1 {
				i = len(cmdlineBuf)
			}
			name = string(cmdlineBuf[:i])
			cmdlineBuf = bytes.Replace(cmdlineBuf, []byte{'\000'}, []byte{' '}, -1)
			cmdline = string(cmdlineBuf)
		}

		f(Process{
			PID:            pid,
			PPID:           ppid,
			Name:           name,
			Cmdline:        cmdline,
			Threads:        threads,
			Jiffies:        jiffies,
			RSSBytes:       rss,
			RSSBytesLimit:  rssLimit,
			OpenFilesCount: len(openFiles),
			OpenFilesLimit: openFilesLimit,
		}, Process{})
	}

	return nil
}
Beispiel #2
0
func (p dir) ReadDirNames(path string) ([]string, error) {
	if path == "/" {
		result := []string{}
		for _, v := range p.entries {
			result = append(result, v.Name())
		}
		return result, nil
	}

	head, tail := split(path)
	fs, ok := p.entries[head]
	if !ok {
		return nil, fmt.Errorf("Not found: %s", path)
	}

	return fs.ReadDirNames(tail)
}
Beispiel #3
0
// walkNamespace does the work of walk for a single namespace
func (w pidWalker) walkNamespace(buf *bytes.Buffer, sockets map[uint64]*Proc, namespaceProcs []*process.Process) error {

	if found, err := readProcessConnections(buf, namespaceProcs); err != nil || !found {
		return err
	}

	var statT syscall.Stat_t
	var fdBlockCount uint64
	for i, p := range namespaceProcs {

		// Get the sockets for all the processes in the namespace
		dirName := strconv.Itoa(p.PID)
		fdBase := filepath.Join(procRoot, dirName, "fd")

		if fdBlockCount > w.fdBlockSize {
			// we surpassed the filedescriptor rate limit
			select {
			case <-w.tickc:
			case <-w.stopc:
				return nil // abort
			}

			fdBlockCount = 0
			// read the connections again to
			// avoid the race between between /net/tcp{,6} and /proc/PID/fd/*
			if found, err := readProcessConnections(buf, namespaceProcs[i:]); err != nil || !found {
				return err
			}
		}

		fds, err := fs.ReadDirNames(fdBase)
		if err != nil {
			// Process is gone by now, or we don't have access.
			continue
		}

		var proc *Proc
		for _, fd := range fds {
			fdBlockCount++

			// Direct use of syscall.Stat() to save garbage.
			err = fs.Stat(filepath.Join(fdBase, fd), &statT)
			if err != nil {
				continue
			}

			// We want sockets only.
			if statT.Mode&syscall.S_IFMT != syscall.S_IFSOCK {
				continue
			}

			// Initialize proc lazily to avoid creating unnecessary
			// garbage
			if proc == nil {
				proc = &Proc{
					PID:  uint(p.PID),
					Name: p.Name,
				}
			}

			sockets[statT.Ino] = proc
		}

	}

	return nil
}