misc: bug fixes and improvements for stats Fuse fs
[vpp.git] / extras / vpp_stats_fs / cmd.go
1 /*
2  * Copyright (c) 2021 Cisco Systems and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 /*
17  * Copyright 2016 the Go-FUSE Authors. All rights reserved.
18  * Use of this source code is governed by a BSD-style
19  * license that can be found in the LICENSE file.
20  */
21
22 // This file is the main program driver to mount the stats segment filesystem.
23 package main
24
25 import (
26         "flag"
27         "fmt"
28         "log"
29         "log/syslog"
30         "os"
31         "os/signal"
32         "runtime"
33         "strings"
34         "syscall"
35
36         "git.fd.io/govpp.git/adapter/statsclient"
37         "git.fd.io/govpp.git/core"
38         "github.com/hanwen/go-fuse/v2/fs"
39 )
40
41 func LogMsg(msg string) {
42         fmt.Fprint(os.Stderr, msg)
43         log.Print(msg)
44 }
45
46 func main() {
47         syslogger, err := syslog.New(syslog.LOG_ERR|syslog.LOG_DAEMON, "statsfs")
48         if err != nil {
49                 log.Fatalln(err)
50         }
51         log.SetOutput(syslogger)
52
53         statsSocket := flag.String("socket", statsclient.DefaultSocketName, "Path to VPP stats socket")
54         debug := flag.Bool("debug", false, "print debugging messages.")
55         flag.Parse()
56
57         if flag.NArg() < 1 {
58                 LogMsg(fmt.Sprintf("usage: %s MOUNTPOINT\n", os.Args[0]))
59                 os.Exit(2)
60         }
61         //Conection to the stat segment socket.
62         sc := statsclient.NewStatsClient(*statsSocket)
63         fmt.Println("Waiting for the VPP socket to be available. Be sure a VPP instance is running.")
64         c, err := core.ConnectStats(sc)
65         if err != nil {
66                 LogMsg(fmt.Sprintf("Failed to connect to the stats socket: %v\n", err))
67                 os.Exit(1)
68         }
69         defer c.Disconnect()
70         fmt.Printf("Connected to the socket\n")
71         //Creating the filesystem instance
72         root, err := NewStatsFileSystem(sc)
73         if err != nil {
74                 LogMsg(fmt.Sprintf("NewStatsFileSystem failed: %v\n", err))
75                 os.Exit(1)
76         }
77
78         //Mounting the filesystem.
79         opts := &fs.Options{}
80         opts.Debug = *debug
81         opts.AllowOther = true
82         server, err := fs.Mount(flag.Arg(0), root, opts)
83         if err != nil {
84                 LogMsg(fmt.Sprintf("Mount fail: %v\n", err))
85                 os.Exit(1)
86         }
87
88         sigs := make(chan os.Signal)
89         signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
90
91         fmt.Printf("Successfully mounted the file system in directory: %s\n", flag.Arg(0))
92         runtime.GC()
93
94         for {
95                 go server.Wait()
96
97                 <-sigs
98                 fmt.Println("Unmounting...")
99                 err := server.Unmount()
100                 if err == nil || !strings.Contains(err.Error(), "Device or resource busy") {
101                         break
102                 }
103                 LogMsg(fmt.Sprintf("Unmount fail: %v\n", err))
104         }
105 }