// Copyright 2019 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris

package procfs

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"

	"golang.org/x/sys/unix"
)

// ProcMapPermissions contains permission settings read from /proc/[pid]/maps
type ProcMapPermissions struct {
	// mapping has the [R]ead flag set
	Read bool
	// mapping has the [W]rite flag set
	Write bool
	// mapping has the [X]ecutable flag set
	Execute bool
	// mapping has the [S]hared flag set
	Shared bool
	// mapping is marked as [P]rivate (copy on write)
	Private bool
}

// ProcMap contains the process memory-mappings of the process,
// read from /proc/[pid]/maps
type ProcMap struct {
	// The start address of current mapping.
	StartAddr uintptr
	// The end address of the current mapping
	EndAddr uintptr
	// The permissions for this mapping
	Perms *ProcMapPermissions
	// The current offset into the file/fd (e.g., shared libs)
	Offset int64
	// Device owner of this mapping (major:minor) in Mkdev format.
	Dev uint64
	// The inode of the device above
	Inode uint64
	// The file or psuedofile (or empty==anonymous)
	Pathname string
}

// parseDevice parses the device token of a line and converts it to a dev_t
// (mkdev) like structure.
func parseDevice(s string) (uint64, error) {
	toks := strings.Split(s, ":")
	if len(toks) < 2 {
		return 0, fmt.Errorf("unexpected number of fields")
	}

	major, err := strconv.ParseUint(toks[0], 16, 0)
	if err != nil {
		return 0, err
	}

	minor, err := strconv.ParseUint(toks[1], 16, 0)
	if err != nil {
		return 0, err
	}

	return unix.Mkdev(uint32(major), uint32(minor)), nil
}

// parseAddress just converts a hex-string to a uintptr
func parseAddress(s string) (uintptr, error) {
	a, err := strconv.ParseUint(s, 16, 0)
	if err != nil {
		return 0, err
	}

	return uintptr(a), nil
}

// parseAddresses parses the start-end address
func parseAddresses(s string) (uintptr, uintptr, error) {
	toks := strings.Split(s, "-")
	if len(toks) < 2 {
		return 0, 0, fmt.Errorf("invalid address")
	}

	saddr, err := parseAddress(toks[0])
	if err != nil {
		return 0, 0, err
	}

	eaddr, err := parseAddress(toks[1])
	if err != nil {
		return 0, 0, err
	}

	return saddr, eaddr, nil
}

// parsePermissions parses a token and returns any that are set.
func parsePermissions(s string) (*ProcMapPermissions, error) {
	if len(s) < 4 {
		return nil, fmt.Errorf("invalid permissions token")
	}

	perms := ProcMapPermissions{}
	for _, ch := range s {
		switch ch {
		case 'r':
			perms.Read = true
		case 'w':
			perms.Write = true
		case 'x':
			perms.Execute = true
		case 'p':
			perms.Private = true
		case 's':
			perms.Shared = true
		}
	}

	return &perms, nil
}

// parseProcMap will attempt to parse a single line within a proc/[pid]/maps
// buffer.
func parseProcMap(text string) (*ProcMap, error) {
	fields := strings.Fields(text)
	if len(fields) < 5 {
		return nil, fmt.Errorf("truncated procmap entry")
	}

	saddr, eaddr, err := parseAddresses(fields[0])
	if err != nil {
		return nil, err
	}

	perms, err := parsePermissions(fields[1])
	if err != nil {
		return nil, err
	}

	offset, err := strconv.ParseInt(fields[2], 16, 0)
	if err != nil {
		return nil, err
	}

	device, err := parseDevice(fields[3])
	if err != nil {
		return nil, err
	}

	inode, err := strconv.ParseUint(fields[4], 10, 0)
	if err != nil {
		return nil, err
	}

	pathname := ""

	if len(fields) >= 5 {
		pathname = strings.Join(fields[5:], " ")
	}

	return &ProcMap{
		StartAddr: saddr,
		EndAddr:   eaddr,
		Perms:     perms,
		Offset:    offset,
		Dev:       device,
		Inode:     inode,
		Pathname:  pathname,
	}, nil
}

// ProcMaps reads from /proc/[pid]/maps to get the memory-mappings of the
// process.
func (p Proc) ProcMaps() ([]*ProcMap, error) {
	file, err := os.Open(p.path("maps"))
	if err != nil {
		return nil, err
	}
	defer file.Close()

	maps := []*ProcMap{}
	scan := bufio.NewScanner(file)

	for scan.Scan() {
		m, err := parseProcMap(scan.Text())
		if err != nil {
			return nil, err
		}

		maps = append(maps, m)
	}

	return maps, nil
}
