<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"sort"
	"strings"
	"syscall"
	"text/tabwriter"
)

func processes() []os.FileInfo {
	var ps []os.FileInfo

	proc, err := os.Open("/proc")
	if err != nil {
		log.Fatal(err)
	}

	files, err := proc.Readdir(-1)
	if err != nil {
		log.Fatal(err)
	}

	r := regexp.MustCompile("^[0-9]+$")

	for _, f := range files {
		if f.IsDir() && r.MatchString(f.Name()) {
			ps = append(ps, f)
		}
	}
	return ps
}

func namespaces(ps []os.FileInfo) map[string][]string {
	netns := make(map[string][]string)
	r := regexp.MustCompile("^net:\\[([0-9]+)\\]$")

	for _, f := range ps {
		nsName, err := os.Readlink("/proc/" + f.Name() + "/ns/net")
		if err != nil {
			// Permission denied if you are not root: you can't see /proc/<pid>/
			continue
		}

		// we are not converting string to a number for conveniency. nsNum is a string type.
		nsNum := r.FindStringSubmatch(nsName)[1]

		netns[nsNum] = append(netns[nsNum], f.Name())
	}
	return netns
}

func main() {
	runtime.LockOSThread()
	ps := processes()
	// key is namespace number, value is list of process pids. All stored as string type.
	netns := namespaces(ps)

	// If we run external command:
	joinPtr := flag.String("j", "", "Join namespace number")
	flag.Parse()

	if *joinPtr == "" {
		w := tabwriter.NewWriter(os.Stdout, 0, 0, 0, ' ', tabwriter.AlignRight)
		fmt.Fprintln(w, "NS NUMBER \t PIDS")

		// Sort by namespace
		nsList := []string{}
		for k, _ := range netns {
			nsList = append(nsList, k)
		}
		sort.Strings(nsList)

		for _, ns := range nsList {
			pidsJoined := strings.Join(netns[ns], ",")
			fmt.Fprintln(w, ns, "\t", pidsJoined)
		}
		w.Flush()
		os.Exit(0)
	}

	//TODO: is there a way to get fd without going to proc?
	pids := netns[*joinPtr]
	if len(pids) == 0 {
		log.Fatalf("Namespace %s not found.", *joinPtr)
	}
	pid := pids[0]

	fd, err := syscall.Open(filepath.Join("/proc", pid, "ns/net"), syscall.O_RDONLY, 0644)
	if err != nil {
		log.Fatal(err)
	}
	exitCode, _, errno := syscall.RawSyscall(308, uintptr(fd), 0, 0) // 308 is setns
	if exitCode != 0 {
		log.Fatal(errno)
	}

	cmd := exec.Command(flag.Args()[0], flag.Args()[1:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		log.Fatal(err)
	}<commit_msg>Refactored, split into functions<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"sort"
	"strings"
	"syscall"
	"text/tabwriter"
)

type NsData struct {
	pids []string
	file string
}

type NsMap struct {
	Map map[string]*NsData
}

func processes() []os.FileInfo {
	var ps []os.FileInfo

	proc, err := os.Open("/proc")
	if err != nil {
		log.Fatal(err)
	}

	files, err := proc.Readdir(-1)
	if err != nil {
		log.Fatal(err)
	}

	r := regexp.MustCompile("^[0-9]+$")

	for _, f := range files {
		if f.IsDir() && r.MatchString(f.Name()) {
			ps = append(ps, f)
		}
	}
	return ps
}

func namespaces(ps []os.FileInfo) NsMap {
	netns := NsMap{Map: make(map[string]*NsData)}
	r := regexp.MustCompile("^net:\\[([0-9]+)\\]$")

	for _, f := range ps {
		fpath := filepath.Join("/proc", f.Name(), "ns/net")
		nsName, err := os.Readlink(fpath)
		if err != nil {
			// Permission denied if you are not root: you can't see /proc/<pid>/
			continue
		}

		// we are not converting string to a number for conveniency. nsNum is a string type.
		nsNum := r.FindStringSubmatch(nsName)[1]
		if _, ok := netns.Map[nsNum]; !ok {
			netns.Map[nsNum] = &NsData{file: fpath}
		}

		netns.Map[nsNum].pids = append(netns.Map[nsNum].pids, f.Name())
	}
	return netns
}

func print(netns NsMap) {
	w := tabwriter.NewWriter(os.Stdout, 0, 0, 0, ' ', tabwriter.AlignRight)
	fmt.Fprintln(w, "NS NUMBER \t PIDS")

	// Sort by namespace
	nsList := []string{}
	for k, _ := range netns.Map {
		nsList = append(nsList, k)
	}
	sort.Strings(nsList)

	for _, ns := range nsList {
		pidsJoined := strings.Join(netns.Map[ns].pids, ",")
		fmt.Fprintln(w, ns, "\t", pidsJoined)
	}
	w.Flush()
}

func joinNs(netns NsMap, target string) {
	pids := netns.Map[target].pids
	if len(pids) == 0 {
		log.Fatalf("Namespace %s not found.", target)
	}
	pid := pids[0]

	fd, err := syscall.Open(filepath.Join("/proc", pid, "ns/net"), syscall.O_RDONLY, 0644)
	if err != nil {
		log.Fatal(err)
	}
	exitCode, _, errno := syscall.RawSyscall(308, uintptr(fd), 0, 0) // 308 is setns
	if exitCode != 0 {
		log.Fatal(errno)
	}

	cmd := exec.Command(flag.Args()[0], flag.Args()[1:]...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		log.Fatal(err)
	}
}

func main() {
	runtime.LockOSThread()
	ps := processes()

	netns := namespaces(ps)

	// If we run external command:
	joinPtr := flag.String("j", "", "Join namespace number")
	flag.Parse()

	if *joinPtr == "" {
		print(netns)
	} else {
		joinNs(netns, *joinPtr)
	}
{'fraction_non_alphanumeric': 0.1875887243966741, 'fraction_numerical': 0.010748326911377002, 'mean_word_length': 3.318739054290718, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '447674', 'n_tokens_mistral': 2169, 'n_tokens_neox': 1985, 'n_words': 483}