Continuously execute tshark from Go script - go

I am trying to execute tskarh from golang script using the example from
https://tutorialedge.net/golang/executing-system-commands-with-golang/
The script works fine, but i don't receive any kind of output
What i want to get is the following:
Continuously run the script,
capture some packets,
extract some fields values,
and assign to variables
Any help please ?
https://pastebin.com/PeAz7vh9
package main
import (
"fmt"
"os/exec"
"runtime"
)
func execute() {
// here we perform the pwd command.
// we can store the output of this in our out variable
// and catch any errors in err
out, err := exec.Command("tshark", "-i", "em1").CombinedOutput()
// if there is an error with our execution
// handle it here
if err != nil {
fmt.Printf("%s", err)
}
fmt.Println("Command Successfully Executed")
// as the out variable defined above is of type []byte we need to convert
// this to a string or else we will see garbage printed out in our console
// this is how we convert it to a string
output := string(out[:])
// once we have converted it to a string we can then output it.
fmt.Println(output)
}
func main() {
fmt.Println("Simple Shell")
fmt.Println("---------------------")
if runtime.GOOS == "windows" {
fmt.Println("Can't Execute this on a windows machine")
} else {
execute()
}
}

I have no idea of tshark, but here is a code that will work continously, you need os.Interrupt, and select.
package main
import (
"os"
"os/exec"
"os/signal"
)
func main() {
out := exec.Command("ping", "8.8.8.8")
f1, _ := os.OpenFile("./outfile.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0755)
f2, _ := os.OpenFile("./errfile.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0755)
out.Stdout = f1
out.Stderr = f2
defer func() {
f1.Close()
f2.Close()
}()
err := out.Run()
if err != nil {
panic(err)
}
var ctrlcInt chan os.Signal
ctrlcInt = make(chan os.Signal, 1)
signal.Notify(ctrlcInt, os.Interrupt)
for {
select {
case <-ctrlcInt:
break
default:
continue
}
}
return
}
this code pings 8.8.8.8 and writes out put to outfile.txt, it will exit when you press ctrl+c. If there is error it will write to errfile.txt. You can tail the files and see the output. Hope this helps.

Related

Golang execute shell command and return as channel

I am new to golang tried but not getting in my mind. I wanted to execute a shell command and then return the error (if exists) as a channel or stdoutput as a channel.
So far I have done this:
package main
import (
"bufio"
"io"
"os"
"os/exec"
)
type CommandRequest struct {
Command string
Args string
}
type CommandResponse struct {
StdOut chan string
StdErr chan string
}
func main() {
ExecuteCommand();
}
func ExecuteCommand() CommandResponse {
cmd := exec.Command("ping", "192.168.0.1")
_, err := cmd.Output()
var returnValue CommandResponse
if err != nil {
output := make(chan string)
go func() { output <- read(os.Stdout) }()
returnValue = CommandResponse{output, nil} //Reading from Stdin
}
return returnValue
}
func read(r io.Reader) <-chan string {
lines := make(chan string)
go func() {
defer close(lines)
scan := bufio.NewScanner(r)
for scan.Scan() {
lines <- scan.Text()
}
}()
return lines
}
Playground Link https://play.golang.org/p/pJ2R6fzK8gR
I tried as much as possible to reduce the error and what is left same i am getting in my workspace as well
There are a couple of ways to read from a command output.
1. Output Method
This is the easiest one. Get directly from Output
func main() {
out, _ := exec.Command("./ping", "192.168.0.1").Output()
fmt.Printf("Stdout: %s\n", string(out))
}
2. Redirect Outputs to bytes.Buffer
func main() {
var stdout, stderr bytes.Buffer
cmd := exec.Command("./ping", "192.168.0.1")
cmd.Stdout = &stdout
cmd.Stderr = &stderr
_ := cmd.Run()
fmt.Printf("Stdout: %s\n", stdout.String())
fmt.Printf("Stderr: %s\n", stderr.String())
}
2. Stdout Pipe with Channel
We generally do not return channel as in your code because their usage to hold and move data is different then variables. We pass them as argument to functions and read/write those channels from different processes (goroutines).
You can use StdoutPipe() method to get output from a pipe as io.Readcloser. Then read it with bufio.Scanner. As you can see I used channel here.
func main() {
cmd := exec.Command("./ping", "192.168.0.1")
cmdReader, _ := cmd.StdoutPipe()
scanner := bufio.NewScanner(cmdReader)
out := make(chan string)
go reader(scanner, out)
done := make(chan bool)
go func() {
value := <-out
println(value)
done <- true
}()
_ = cmd.Run()
<-done
}
func reader(scanner *bufio.Scanner, out chan string) {
for scanner.Scan() {
out <- scanner.Text()
}
}
Channels are the pipes that connect concurrent goroutines. You can send values into channels from one goroutine and receive those values into another goroutine.
If buffered channel is not used, sends and receives block until the other side is ready.
Returning Channel may not be appropriate channel usage.
There are two options to solve your question
Option1 : Not to use the channel and just simply return CommandResponse.
package main
import (
"fmt"
"os/exec"
)
type CommandRequest struct {
Command string
Args string
}
func main() {
cr := CommandRequest{"ls", "-la"}
fmt.Println(ExecuteCommand(cr))
}
func ExecuteCommand(cr CommandRequest) string{
cmd := exec.Command(cr.Command, cr.Args)
stdout, err := cmd.Output()
if err != nil {
return err.Error()
}
return string(stdout)
}
Option2: Use channel but without return. Create a channel and pass it as argument and keep blocked on the receive in main(). So the ExecuteCommand() could execute the shell command and send the return status through the channel.
package main
import (
"fmt"
"os/exec"
)
type CommandRequest struct {
Command string
Args string
}
func main() {
cr := CommandRequest{"ls", "-la"}
retc := make(chan string)
go ExecuteCommand(cr, retc)
ret := <-retc
fmt.Println(ret)
}
func ExecuteCommand(cr CommandRequest, retc chan string) {
cmd := exec.Command(cr.Command, cr.Args)
stdout, err := cmd.Output()
if err != nil {
retc <- err.Error()
return
}
retc <- string(stdout)
}

Writing to file from cmd output

I am trying to write a small code in Go that will collect and save stats from IPFS.
So my Go code will execute IPFS command and save its output in .txt file and keep updating that .txt file.
I am having trouble doing that.
This is my code:
package main
import (
"fmt"
"io"
"log"
"os"
"os/exec"
"time"
)
func ipfsCommand() (ipfsOutput string) {
// output and error
out, err := exec.Command("ipfs","stats","bitswap","--human").Output()
// if there are errors, print/log them
if err != nil {
log.Printf("error!")
log.Fatal(err)
} else {
log.Printf("no error, printing output")
fmt.Printf("%s", out)
}
return
}
func writeToFile(message string) error {
f, err := os.Create("outputTest2_2.txt")
if err != nil {
return err
}
defer f.Close()
l, err := io.WriteString(f, message)
if err != nil {
fmt.Println(err)
f.Close()
return err
}
fmt.Println(l, "bytes written successfully")
return f.Sync()
}
func main() {
// get current time
currentTime := time.Now()
fmt.Println("YYYY.MM.DD : ", currentTime.Format("2006.01.02 15:04:05"))
writeToFile(currentTime)
// get output from ipfs command
msg := ipfsCommand()
// write the output to file
writeToFile(msg)
fmt.Println("file written!!!")
/* // write to file many times
for i:=0;i<3;i++{
// get output from ipfs command
msg := ipfsCommand()
// write the output to file
writeToFile(msg)
}*/
}
When the above code is run, this is the error:
# command-line-arguments
.\test2.go:49:13: cannot use currentTime (type time.Time) as type string in argument to writeToFile
Again, I want to get output from IPFS and save it to .txt file along with current time. I want to do this in loop because I want to save output from IPFS over a long period of time.
I tried to fix your script as is, but it just has too many issues. Here is a
rewrite, maybe you can use it as a new starting point:
package main
import (
"os"
"os/exec"
"time"
)
func main() {
f, err := os.Create("outputTest2_2.txt")
if err != nil {
panic(err)
}
defer f.Close()
currentTime, err := time.Now().MarshalText()
if err != nil {
panic(err)
}
f.Write(append(currentTime, '\n'))
msg, err := exec.Command("go", "env").Output()
if err != nil {
panic(err)
}
f.Write(msg)
}

behave like a "cat" linux command using io/ioutil

have a task to creat a go file, which bahaves like cat command. I have some ideas how to do it, but i don't know how to read input if no file names written.
student#ubuntu:~/div-01/cat$ go build cat.go
student#ubuntu:~/div-01/cat$ ./cat
Hello
Hello
^C
student#ubuntu:~/div-01/cat$
Also i can use only ioutil, io, os packages and one of schools packages to print output.
In internet found this, but it just saves all input in data and then, after I press ctrl+C it prints it back.
package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
var lenght int
args := os.Args[1:]
for i := range args {
lenght++
i++
}
if lenght == 0 {
data, err := ioutil.ReadAll(os.Stdin)
if err == nil {
fmt.Println(data)
}
}
}
To check the number of arguments, use len:
package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
// No arguments give, read from STDIN.
if len(os.Args) == 1 {
data, err := ioutil.ReadAll(os.Stdin)
if err != nil {
os.Exit(1)
}
fmt.Printf("%s", data)
os.Exit(0)
}
// TODO Read the content of all files.
}
well, I found this and it works
if len(os.Args) == 1 {
_, err := io.Copy(os.Stdout, os.Stdin)
if err != nil {
fmt.Println(err)
}
fmt.Println("^C")
}

How to create a .lock file in golang and remove it before exiting?

I'm trying to prevent a program from opening another instance if it's already open, to do this I create a file with .lock extension and remove it when exiting the program. However everything except the remove works.
package main
import (
"os"
"os/signal"
"fmt"
)
func main() {
var test string
exitsig := make(chan os.Signal, 1)
signal.Notify(exitsig, os.Interrupt)
var (
lockstate bool = false
)
if _, err := os.Stat("ms.lock"); err == nil {
return
} else if os.IsNotExist(err) {
var file, err = os.Create("ms.lock")
if err != nil {
return
}
file.Close()
lockstate = true
}
go func() {
<- exitsig
fmt.Println("Error removing file")
fmt.Scanf("%s", &test)
if lockstate {
var err = os.Remove("ms.lock")
if err != nil {
fmt.Println("Error removing file")
fmt.Scanf("%s", &test)
}
}
os.Exit(0)
}()
}
I've tried exiting by ctrl+c, exiting by pressing the close button on the top right corner of the window but it never sends a signal, the os.Interrupt signal is never caught. What is the reason for this?
Also, I need the signal to be non-platform specific, so it should work on both windows and unix based systems.
I think it's because your main function exists soon after launching the goroutine. If the main function ends, all running goroutines will die too.
Here's code that works for me:
package main
import (
"fmt"
"os"
"os/signal"
"sync"
)
func main() {
exitsig := make(chan os.Signal, 1)
signal.Notify(exitsig, os.Interrupt)
var (
lockstate bool = false
)
if _, err := os.Stat("ms.lock"); err == nil {
return
} else if os.IsNotExist(err) {
var file, err = os.Create("ms.lock")
if err != nil {
return
}
file.Close()
lockstate = true
}
go func() {
<-exitsig
if lockstate {
var err = os.Remove("ms.lock")
if err != nil {
fmt.Println("Error removing file: ", err)
}
}
os.Exit(0)
}()
wg := &sync.WaitGroup{}
wg.Add(1)
wg.Wait()
}
I added the waitgroup to wait in the main thread. Works fine on MacOS - creates ms.lock file and waits. Killing it with Cmd + C removes the file.
Should work anywhere as long as the signal fires.

Interrupt current tail and start new one

So I am creating some log analyzer in golang and what I need is real-time tail -f of newly created files.
I am using tail package together with fsnotify package but I'm not very familiar with channels and routines in go so I need some assistance.
Currently program looks like this:
package main
import(
"fmt"
"github.com/hpcloud/tail"
"strings"
"log"
"net/smtp"
"time"
"github.com/fsnotify/fsnotify"
)
//this function needs to monitor for new files in directory
func newFileCheck() (newFilename chan string, err error) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
return
}
err = watcher.Add("myDir")
if err != nil {
return
}
newFilename = make(chan string)
// Process events
go func() {
for {
select {
case ev := <-watcher.Events:
log.Println("event:", ev)
newFilename <- ev.Name // Relative path to the file
//t.Stop() //if I pass reference to t THIS IS NOT HAPPENING ?
case err := <-watcher.Errors:
log.Println("error:", err)
}
}
}()
return
}
func main() {
newFileName = "mylog_0000.log.txt"
fmt.Println("Processing log: ",newFileName)
newFilenameChan, err := newFileCheck()
if err != nil {
fmt.Println("ERR: ",err)
}
t := tailLog(newFileName)
go func() {
for {
select {
case name := <-newFilenameChan:
fmt.Println("New file created: ",name) //this will be printed only once and then on new events nothing is printed ?
//NONE of the lines abowe doesn't work
t.Stop()
t.Dead()
t.Done()
t = tailLog(name)
}
}
}()
}
func tailLog(fileName string) *tail.Tail{
var count = 0
// close the old one and read new file
t, err := tail.TailFile("/mydir/"+fileName, tail.Config{Follow: true, ReOpen: true})
for line := range t.Lines {
//fmt.Println("Line is:", line.Text)
//check do we have what we need
if strings.Contains(strings.ToLower(line.Text), "mfc"){
count++
//do other stuff
}
}
fmt.Println(err)
return t
}
So I can't figure out why newFileCheck functions prints event only for the fist time, and also I'm not able to figure out how to cancel active tail when new event happens, and then start tail again after that event ?
Consider this:
When the function main returns, the program exits. It does not wait
for other (non-main) goroutines to complete.
And look at this block of your code:
func main() {
newFileName = "mylog_0000.log.txt"
fmt.Println("Processing log: ",newFileName)
newFilenameChan, err := newFileCheck()
if err != nil {
fmt.Println("ERR: ",err)
}
t := tailLog(newFileName)
go func() {
for {
select {
case name := <-newFilenameChan:
fmt.Println("New file created: ",name) //this will be printed only once and then on new events nothing is printed ?
//NONE of the lines abowe doesn't work
t.Stop()
t.Dead()
t.Done()
t = tailLog(name)
}
}
}()
}
To handle this job with grace, you should learn more about concurrency in Golang. Use channels to control goroutines like stopping/starting/etc and WaitGroup if you are interested in order of executing/finishing tasks. When there is no control over your program flow, goroutines can lives their own lives and that is bad practice.
If you about this package https://github.com/hpcloud/tail
You need to create one goroutine after you are open file, then you need to check a new file.
I make it for checking a new logfile of SoftetherVPN-Server:
package main
import (
"fmt"
"github.com/hpcloud/tail"
"log"
"time"
)
func CheckFileName(filename string, f chan<- string) {
for {
newFilename := fmt.Sprintf("%v", time.Now().Format("vpn_20060102.log"))
// We have a new filename, that send it into channel
if newFilename != filename {
log.Println("A new logfile", newFilename)
f <- newFilename
return
}
}
}
func main() {
filenameChan := make(chan string)
for {
filename = fmt.Sprintf("%v", time.Now().Format("vpn_20060102.log"))
t, err := tail.TailFile(filename, tail.Config{Follow: true, ReOpen: true, MustExist: true})
if err != nil {
log.Println("No log file", filename, ". Waiting for 10 minute")
time.Sleep(time.Minute * 10)
continue
}
// Send goroutine for checking filename in loop
go CheckFileName(filename, filenameChan)
// Send goroutine that stops lines read in range
go func() {
for {
select {
case name := <-filenameChan:
log.Println("Received a new name for log:", name)
t.Stop()
return
}
}
}()
if err != nil {
log.Fatalln(err)
}
for line := range t.Lines {
fmt.Println(line)
}
}
}
So, that works for me

Resources