golang unix.TCGETS equivalent on Mac - linux

On Linux I use the following code to enable and disable console echo:
unix.IoctlGetTermios(int(os.Stdin.Fd()), unix.TCGETS)
unix.IoctlSetTermios(unix.Stdout, unix.TCSETS, term)
But it won't compile on Mac, what should I use on Mac?

You could use TIOCGETA and TIOCSETA instead on Mac OS
// IoctlSetTermios performs an ioctl on fd with a *Termios.
//
// The req value will usually be TCSETA or TIOCSETA.
func IoctlSetTermios(fd int, req uint, value *Termios) error {
import (
"bufio"
"fmt"
"log"
"os"
"golang.org/x/sys/unix"
)
func main() {
STDIN := int(os.Stdin.Fd())
tio, err := unix.IoctlGetTermios(STDIN, unix.TIOCGETA)
if err != nil {
log.Fatal(err)
}
fmt.Println("Input sth:")
tio.Lflag &^= unix.ECHO
err = unix.IoctlSetTermios(STDIN, unix.TIOCSETA, tio)
if err != nil {
log.Fatal(err)
}
reader := bufio.NewReader(os.Stdin)
line, _ := reader.ReadString('\n')
tio.Lflag |= unix.ECHO
err = unix.IoctlSetTermios(STDIN, unix.TIOCSETA, tio)
if err != nil {
log.Fatal(err)
}
fmt.Println(line)
}

Instead of using unix.TCGETS / unix.TIOCGETA or unix.TCSETS / unix.TIOCSETA you can define constants in different files and then use build constraints to build those files based on the operating system.
You can check how github.com/moby/term does it here:
https://github.com/moby/term/blob/c43b287e0e0f2460e4ba913936af2f6bdcbe9ed5/termios_bsd.go
https://github.com/moby/term/blob/c43b287e0e0f2460e4ba913936af2f6bdcbe9ed5/termios_nonbsd.go
With this method your code is decoupled from the operating system and you can always use the same constant.

Related

Go - Convert raw byte string into uuid

I am trying to convert raw byte strings into UUIDs in my program as follows:
Case1:
package main
import (
"fmt"
"strconv"
"github.com/google/uuid"
)
func main() {
s := `"\220\254\0021\265\235O~\244\326\216\"\227c\245\002"`
s2, err := strconv.Unquote(s)
if err != nil {
panic(err)
}
by := []byte(s2)
u, err := uuid.FromBytes(by)
if err != nil {
panic(err)
}
fmt.Println(u.String())
}
output:
90ac0231-b59d-4f7e-a4d6-8e229763a502
Case2:
package main
import (
"fmt"
"strconv"
"github.com/google/uuid"
)
func main() {
s := `"\235\273\'\021\003\261#\022\226\275o\265\322\002\211\263"`
s2, err := strconv.Unquote(s)
if err != nil {
panic(err)
}
by := []byte(s2)
u, err := uuid.FromBytes(by)
if err != nil {
panic(err)
}
fmt.Println(u.String())
}
output:
panic: invalid syntax
goroutine 1 [running]:
main.main()
/tmp/sandbox1756881518/prog.go:14 +0x149
Program exited.
The above program is working with string "\220\254\0021\265\235O~\244\326\216\"\227c\245\002" but fails at converting string "\235\273\'\021\003\261#\022\226\275o\265\322\002\211\263" into uuid. How can I convert these strings into UUIDs?
If fails because of \'. When using backticks, all backslashes are literally backslashes and not escape sequences, so you are passing raw backslash \, followed by single quote ' to the strconv.Unquote. It causes invalid syntax. There are two workarounds here:
First
Just replace this line:
s := `"\235\273\'\021\003\261#\022\226\275o\265\322\002\211\263"`
with this:
s := `"\235\273'\021\003\261#\022\226\275o\265\322\002\211\263"`
So there is ' not \'. But if you need to programmatically convert the string, use the second approach.
Second
Import "strings":
import (
"fmt"
"strconv"
"strings"
"github.com/google/uuid"
)
And replace \' with ':
s = strings.ReplaceAll(s, `\'`, `'`)
So the full code looks like this now:
package main
import (
"fmt"
"strconv"
"strings"
"github.com/google/uuid"
)
func main() {
s := `"\235\273\'\021\003\261#\022\226\275o\265\322\002\211\263"`
s = strings.ReplaceAll(s, `\'`, `'`)
s2, err := strconv.Unquote(s)
if err != nil {
fmt.Println(err)
}
by := []byte(s2)
u, err := uuid.FromBytes(by)
if err != nil {
fmt.Println(err)
}
fmt.Println(u.String())
}

Calling mremap in Go doesn't work, but gives no error

I'm trying to mremap a file from Go, but the size of the file doesn't seem to be changing, despite the returned errno of 0. This results in a segfault when I try to access the mapped memory.
I've included the code below. The implementation is similar to the mmap implementation in the sys package, so I'm not sure what's going wrong here:
package main
import (
"fmt"
"io/ioutil"
"log"
"os"
"reflect"
"unsafe"
"golang.org/x/sys/unix"
)
// taken from <https://github.com/torvalds/linux/blob/f8394f232b1eab649ce2df5c5f15b0e528c92091/include/uapi/linux/mman.h#L8>
const (
MREMAP_MAYMOVE = 0x1
// MREMAP_FIXED = 0x2
// MREMAP_DONTUNMAP = 0x4
)
func mremap(data []byte, size int) ([]byte, error) {
header := (*reflect.SliceHeader)(unsafe.Pointer(&data))
mmapAddr, mmapSize, errno := unix.Syscall6(
unix.SYS_MREMAP,
header.Data,
uintptr(header.Len),
uintptr(size),
uintptr(MREMAP_MAYMOVE),
0,
0,
)
if errno != 0 {
return nil, fmt.Errorf("mremap failed with errno: %s", errno)
}
if mmapSize != uintptr(size) {
return nil, fmt.Errorf("mremap size mismatch: requested: %d got: %d", size, mmapSize)
}
header.Data = mmapAddr
header.Cap = size
header.Len = size
return data, nil
}
func main() {
log.SetFlags(log.LstdFlags | log.Lshortfile)
const mmPath = "/tmp/mm_test"
// create a file for mmap with 1 byte of data.
// this should take up 1 block on disk (4096 bytes).
err := ioutil.WriteFile(mmPath, []byte{0x1}, 0755)
if err != nil {
log.Fatal(err)
}
// open and stat the file.
file, err := os.OpenFile(mmPath, os.O_RDWR, 0)
if err != nil {
log.Fatal(err)
}
defer file.Close()
stat, err := file.Stat()
if err != nil {
log.Fatal(err)
}
// mmap the file and print the contents.
// this should print only one byte of data.
data, err := unix.Mmap(int(file.Fd()), 0, int(stat.Size()), unix.PROT_READ|unix.PROT_WRITE, unix.MAP_SHARED)
if err != nil {
log.Fatal(err)
}
fmt.Printf("mmap data: %+v\n", data)
// mremap the file to a size of 2 blocks.
data, err = mremap(data, 2*4096)
if err != nil {
log.Fatal(err)
}
// access the mremapped data.
fmt.Println(data[:4096]) // accessing the first block works.
fmt.Println(data[:4097]) // accessing the second block fails with `SIGBUS: unexpected fault address`.
}
I tried looking for other Go code that uses mremap, but I can't seem to find any. I would appreciate any input!
As #kostix mentioned in the comments, mmap is being used to map a regular file into memory. The reason that accessing the buffer results in a segfault is that the underlying file itself is not large enough. The solution is to truncate the file to the desired length before calling mremap:
if err := file.Truncate(2*4096); err != nil {
log.Fatal(err)
}
data, err = mremap(data, 2*4096)

Sleeping process until completed in Go

I am trying to automate a process in Go. I have been able to implement threads and do the process accordingly however the output is mixed and matched.
I was wondering if there is a way to show the output as it is produced by the program and according to the program's process. So if task A completes before task B, we show A's output before B, or vice-versa.
package main
import (
"fmt"
"log"
"os"
"os/exec"
"sync"
)
var url string
var wg sync.WaitGroup
func nikto() {
cmd := exec.Command("nikto", "-h", url)
cmd.Stdout = os.Stdout
err := cmd.Run()
if err != nil {
log.Fatal(err)
}
wg.Done()
}
func whois() {
cmd := exec.Command("whois", "google.co")
cmd.Stdout = os.Stdout
err := cmd.Run()
if err != nil {
log.Fatal(err)
}
wg.Done()
}
func main() {
fmt.Printf("Please input URL")
fmt.Scanln(&url)
wg.Add(1)
go nikto()
wg.Add(1)
go whois()
wg.Wait()
}
In your process, you pass the os.Stdout file descriptor directly to the commands you invoke to run your child processes. This means the STDOUT pipe of the child processes will be connected directly to your Go program's standard output, and will likely be interleaved if both child processes write simultaneously.
The simplest way to fix this requires you to buffer the output from the STDOUT pipe of the child process in your Go program, so you can intercept the output and control when it is printed.
The Cmd type in the os/exec package provides a function call Output() which will invoke the child process and return the contents of STDOUT in a byte slice. Your code can be adapted with ease to implement this pattern and process the results, for example:
func whois() {
cmd := exec.Command("whois", "google.co")
out, err := cmd.Output()
if err != nil {
log.Fatal(err)
}
fmt.Println(out)
wg.Done()
}
Interleaving of output
If you use functions in the fmt package to print output, there is no guarantee that concurrent calls to fmt.Println will not be interleaved.
To prevent interleaving, you may choose to serialize access to STDOUT, or use a logger which is safe for concurrent use (such as the log package). Here is an example of serializing access to STDOUT in the Go process:
package main
import (
"fmt"
"log"
"os/exec"
"sync"
)
var url string
func nikto(outChan chan<- []byte) {
cmd := exec.Command("nikto", "-h", url)
bs, err := cmd.Output()
if err != nil {
log.Fatal(err)
}
outChan <- bs
}
func whois(outChan chan<- []byte) {
cmd := exec.Command("whois", "google.com")
bs, err := cmd.Output()
if err != nil {
log.Fatal(err)
}
outChan <- bs
}
func main() {
outChan := make(chan []byte)
fmt.Printf("Please input URL")
fmt.Scanln(&url)
go nikto(outChan)
go whois(outChan)
for i := 0; i < 2; i++ {
bs := <-outChan
fmt.Println(string(bs))
}
}

How to properly wait for an event/process to finish not being the parent?

I am using GO to check if a process (not been parent) has ben terminated, basically something like the pwait command in FreeBSD but written in go.
Currently I am trying a for loop with a kill -0, but I notice that the CPU usage is very high 99% with this approach, here is the code:
package main
import (
"fmt"
"os"
"strconv"
"syscall"
"time"
)
func main() {
if len(os.Args) != 2 {
fmt.Printf("usage: %s pid", os.Args[0])
os.Exit(1)
}
pid, err := strconv.ParseInt(os.Args[1], 10, 64)
if err != nil {
panic(err)
}
process, err := os.FindProcess(int(pid))
err = process.Signal(syscall.Signal(0))
for err == nil {
err = process.Signal(syscall.Signal(0))
time.Sleep(500 * time.Millisecond)
}
fmt.Println(err)
}
Any idea of how to improve or properly implement this.
Thanks in advance.
UPDATE
Adding a sleep within the loop like suggested, helps reducing the load.
From the provided links, seems to be possible to attach to the existing pid, I will give a try PtraceAttach but don't know if this may have side effects, any idea?
As suggested I was available to use kqueue:
package main
import (
"fmt"
"log"
"os"
"strconv"
"syscall"
)
func main() {
if len(os.Args) != 2 {
fmt.Printf("usage: %s pid", os.Args[0])
os.Exit(1)
}
pid, err := strconv.ParseInt(os.Args[1], 10, 64)
if err != nil {
panic(err)
}
process, _ := os.FindProcess(int(pid))
kq, err := syscall.Kqueue()
if err != nil {
fmt.Println(err)
}
ev1 := syscall.Kevent_t{
Ident: uint64(process.Pid),
Filter: syscall.EVFILT_PROC,
Flags: syscall.EV_ADD,
Fflags: syscall.NOTE_EXIT,
Data: 0,
Udata: nil,
}
for {
events := make([]syscall.Kevent_t, 1)
n, err := syscall.Kevent(kq, []syscall.Kevent_t{ev1}, events, nil)
if err != nil {
log.Println("Error creating kevent")
}
if n > 0 {
break
}
}
fmt.Println("fin")
}
Works fine, but wondering how to implement/achieve the same on linux since I think kqueue not available on it, any ideas ?
One solution would be to use the netlink proc connector, which is a socket the kernel uses to let userspace know about different process events. The official documentation is somewhat lacking, although there are a couple of good examples in C which are probably better to read.
The main caveat to using the proc connector is the process must be run as root. If running your program as a non-root user is a requirement, you should consider other options, such as periodically polling /proc to watch for changes. Any approach which uses polling, as others have pointed out, is susceptible to a race condition if the process is terminated and another one is started with the same PID in between polls.
Anyway, to use the proc connector in Go, we will have to do some translation from C. Specifically, we need to define the proc_event and exit_proc_event structs from cn_proc.h, and the cn_msg and cb_id structs from connector.h.
// CbID corresponds to cb_id in connector.h
type CbID struct {
Idx uint32
Val uint32
}
// CnMsg corresponds to cn_msg in connector.h
type CnMsg struct {
ID CbID
Seq uint32
Ack uint32
Len uint16
Flags uint16
}
// ProcEventHeader corresponds to proc_event in cn_proc.h
type ProcEventHeader struct {
What uint32
CPU uint32
Timestamp uint64
}
// ExitProcEvent corresponds to exit_proc_event in cn_proc.h
type ExitProcEvent struct {
ProcessPid uint32
ProcessTgid uint32
ExitCode uint32
ExitSignal uint32
}
We also need to make a netlink socket and call bind.
sock, err := unix.Socket(unix.AF_NETLINK, unix.SOCK_DGRAM, unix.NETLINK_CONNECTOR)
if err != nil {
fmt.Println("socket: %v", err)
return
}
addr := &unix.SockaddrNetlink{Family: unix.AF_NETLINK, Groups: C.CN_IDX_PROC, Pid: uint32(os.Getpid())}
err = unix.Bind(sock, addr)
if err != nil {
fmt.Printf("bind: %v\n", err)
return
}
Next, we have to send the PROC_CN_MCAST_LISTEN message to the kernel to let it know we want to receive events. We can import this directly from C, where it's defined as an enum, to save some typing, and put it in a function since we will have to call it again with PROC_CN_MCAST_IGNORE when we are done receiving data from the kernel.
// #include <linux/cn_proc.h>
// #include <linux/connector.h>
import "C"
func send(sock int, msg uint32) error {
destAddr := &unix.SockaddrNetlink{Family: unix.AF_NETLINK, Groups: C.CN_IDX_PROC, Pid: 0} // the kernel
cnMsg := CnMsg{}
header := unix.NlMsghdr{
Len: unix.NLMSG_HDRLEN + uint32(binary.Size(cnMsg) + binary.Size(msg)),
Type: uint16(unix.NLMSG_DONE),
Flags: 0,
Seq: 1,
Pid: uint32(unix.Getpid()),
}
msg.ID = CbID{Idx: C.CN_IDX_PROC, Val: C.CN_VAL_PROC}
msg.Len = uint16(binary.Size(msg))
msg.Ack = 0
msg.Seq = 1
buf := bytes.NewBuffer(make([]byte, 0, header.Len))
binary.Write(buf, binary.LittleEndian, header)
binary.Write(buf, binary.LittleEndian, cnMsg)
binary.Write(buf, binary.LittleEndian, msg)
return unix.Sendto(sock, buf.Bytes(), 0, destAddr)
}
After we let the kernel know we're ready to receive events, we can receive them on the socket we're created. Once we receive them, we need to parse them, and check for relevant data. We only care about messages that meet the following criteria:
Come from the kernel
Have a header type of NLMSG_DONE
Have a proc_event_header.what value of PROC_EVENT_EXIT
Match our PID
If they meet these criteria, we can extract the relevant process information into a proc_event_exit struct, which contains the PID of the process.
for {
p := make([]byte, 1024)
nr, from, err := unix.Recvfrom(sock, p, 0)
if sockaddrNl, ok := from.(*unix.SockaddrNetlink); !ok || sockaddrNl.Pid != 0 {
continue
}
if err != nil {
fmt.Printf("Recvfrom: %v\n", err)
continue
}
if nr < unix.NLMSG_HDRLEN {
continue
}
// the sys/unix package doesn't include the ParseNetlinkMessage function
nlmessages, err := syscall.ParseNetlinkMessage(p[:nr])
if err != nil {
fmt.Printf("ParseNetlinkMessage: %v\n", err)
continue
}
for _, m := range(nlmessages) {
if m.Header.Type == unix.NLMSG_DONE {
buf := bytes.NewBuffer(m.Data)
msg := &CnMsg{}
hdr := &ProcEventHeader{}
binary.Read(buf, binary.LittleEndian, msg)
binary.Read(buf, binary.LittleEndian, hdr)
if hdr.What == C.PROC_EVENT_EXIT {
event := &ExitProcEvent{}
binary.Read(buf, binary.LittleEndian, event)
pid := int(event.ProcessTgid)
fmt.Printf("%d just exited.\n", pid)
}
}
}
}
A full code example is here.

program only prints last string of input file

i am trying to create a simple program to read lines from a text file and print them out to the console in golang. I spent lots of time going over my code and I simply can't understand why only the last line is being printed out to the screen. can anyone tell me where I am going wrong here? Everything here should compile and run.
package main
import (
"bufio"
"fmt"
"os"
)
func Readln(r *bufio.Reader) (string, error) {
var (
isPrefix bool = true
err error = nil
line, ln []byte
)
for isPrefix && err == nil {
line, isPrefix, err = r.ReadLine()
ln = append(ln, line...)
}
return string(ln), err
}
func main() {
f, err := os.Open("tickers.txt")
if err != nil {
fmt.Printf("error opening file: %v\n", err)
os.Exit(1)
}
r := bufio.NewReader(f)
s, e := Readln(r)
for e == nil {
fmt.Println(s)
s, e = Readln(r)
}
}
I therefore suspect that the problem is in your tickers.txt file line endings. The docs for ReadLine() also indicate that for most situations a Scanner is more suitable.
The following SO question has some useful information for alternative implementations: reading file line by line in go
I then used the example in the above question to re-implement your main function as follows:
f, err := os.Open("tickers.txt")
if err != nil {
fmt.Printf("error opening file: %v\n", err)
os.Exit(1)
}
scanner := bufio.NewScanner(f)
for scanner.Scan() {
fmt.Println(scanner.Text())
}
if err := scanner.Err(); err != nil {
fmt.Println(err)
}

Resources