Пример #1
0
func watch(p string, event chan<- EventItem) {
	watcher, err := inotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}

	dir := path.Dir(p)
	err = watcher.Watch(dir)
	if err != nil {
		log.Fatal(err)
	}

	register(p)

	go func() {
		defer watcher.Close()
		for {
			select {
			case ev := <-watcher.Event:
				if ev.Mask&(inotify.IN_CLOSE_WRITE) > 0 &&
					p == ev.Name {

					event <- diff(p)
				}
			case err := <-watcher.Error:
				log.Println("error:", err)
			}
		}
	}()
}
Пример #2
0
func Watch(restart string, done <-chan struct{}, change func()) error {
	lastStat, err := os.Stat(restart)
	if err != nil {
		return err
	}

	watcher, err := inotify.NewWatcher()
	if err != nil {
		return err
	}

	err = watcher.AddWatch(restart, inotify.IN_ATTRIB|inotify.IN_MODIFY)
	if err != nil {
		return err
	}

	defer watcher.Close()

	for {
		select {
		case <-watcher.Event:
			cur, err := os.Stat(restart)
			if err != nil {
				return err
			}

			if cur.ModTime().After(lastStat.ModTime()) {
				change()
			}
		case <-done:
			return nil
		}
	}
}
Пример #3
0
func init() {
	// Generate the reverse of our enum so we can work backwards and reload
	// a file with the name instead of the enum.
	//
	// The issue arises because we've decided to use an array instead of a map
	// to describe our in-memory templates. While this is more efficient, it
	// causes issues with our hot reloading because the name of the file
	// given to us from inotify is the string representation of the file's
	// name, and we can't match that up with the enum on the fly (or generate
	// code that does that using //go: generate). So, we run an init func that
	// generates a map of the names to the enum so we can work backwards to
	// reload the file.
	for i := 0; i < len(_TmplName_index)-1; i++ {
		key := _TmplName_name[_TmplName_index[i]:_TmplName_index[i+1]]
		TmplMap[key] = TmplName(i)
	}

	// Set up our watcher for hot reloads of modified files.
	watcher, err := inotify.NewWatcher()
	if err != nil {
		glog.Fatalln(err)
	}

	err = watcher.Watch(templatePath)
	if err != nil {
		glog.Fatalln(err)
	}

	Tmpls.Watcher = watcher
	Tmpls.Watch()

	cleanup.Register("reload", watcher.Close) // Close watcher.
}
Пример #4
0
func ExampleNewWatcher() {
	watcher, err := inotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	defer watcher.Close()

	done := make(chan bool)
	go func() {
		for {
			select {
			case ev := <-watcher.Event:
				//log.Println("event:", ev.Name)
				log.Println("event:", ev.Name, ev.Mask, ev.Cookie)
				log.Println("event:", ev)

			case err := <-watcher.Error:
				log.Println("error:", err)
			}
		}
	}()

	//err = watcher.Add("./testDir")
	//watcher.Watch("/testDir")
	watcher.AddWatch("./testDir", inotify.IN_CLOSE_WRITE)
	if err != nil {
		log.Fatal(err)
	}
	<-done
}
Пример #5
0
//watch filesystem, execute command on changes
func main() {
	if len(os.Args) == 3 {
		watchpath = os.Args[1]
		command = os.Args[2]
	} else {
		fmt.Println("Usage: reloader <path> <command> &")
		return
	}
	watcher, err := inotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	err = watcher.Watch(watchpath)
	if err != nil {
		log.Fatal(err)
	}
	log.Println("watching:", watchpath)
	for {
		select {
		case ev := <-watcher.Event:
			if ev.Mask == syscall.IN_CLOSE_WRITE ||
				ev.Mask == syscall.IN_DELETE {
				if hasExt(path.Ext(ev.Name)) {
					log.Println("Reloader:", command)
					doCmd(command)
				}
			}
		case err := <-watcher.Error:
			log.Println("error:", err)
		}
	}
}
Пример #6
0
//NewWatcher creates a new RecursiveWatcher and returns any errors
func NewWatcher() (*RecursiveWatcher, error) {
	watcher, err := inotify.NewWatcher()
	if err != nil {
		return nil, err
	}

	rw := &RecursiveWatcher{watcher: watcher, Event: make(chan *inotify.Event, 100), Error: make(chan error, 10), done: make(chan bool)}

	go func() {
		for {
			select {
			case <-rw.done:
				return
			case event := <-rw.watcher.Event:
				//We need to intercept create events and add watches for them. Removal is handled by inotify on deletion
				if event.Mask&inotify.IN_CREATE == inotify.IN_CREATE || event.Mask&inotify.IN_MOVED_FROM == inotify.IN_MOVED_FROM || event.Mask&inotify.IN_MOVED_TO == inotify.IN_MOVED_TO {
					rw.Watch(event.Name)
				}

				rw.Event <- event
			case err := <-rw.watcher.Error:
				rw.Error <- err
			}
		}
	}()

	return rw, err
}
Пример #7
0
func (u *NetNSTopoUpdater) start() {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	watcher, err := inotify.NewWatcher()
	if err != nil {
		logging.GetLogger().Error("Unable to create a new Watcher: %s", err.Error())
		return
	}
	err = watcher.Watch(runBaseDir)
	if err != nil {
		logging.GetLogger().Error("Unable to Watch %s: %s", runBaseDir, err.Error())
		return
	}

	u.initialize()

	for {
		select {
		case ev := <-watcher.Event:
			if ev.Mask&inotify.IN_CREATE > 0 {
				u.onNetNsCreated(ev.Name)
			}
			if ev.Mask&inotify.IN_DELETE > 0 {
				u.onNetNsDeleted(ev.Name)
			}

		case err := <-watcher.Error:
			logging.GetLogger().Error("Error while watching network namespace: %s", err.Error())
		}
	}
}
Пример #8
0
func main() {
	var stop bool
	sigs := make(chan os.Signal, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	watcher, err := inotify.NewWatcher()
	check(err)

	err = watcher.Watch("/tmp")
	check(err)

	for {
		select {
		case ev := <-watcher.Event:
			log.Println("event:", ev)
		case err := <-watcher.Error:
			log.Println("error:", err)
		case <-time.After(time.Second * 1):
			log.Println("-- timeout --")
		case <-sigs:
			log.Println("got signal")
			stop = true
		}

		if true == stop {
			break
		}
	}

	err = watcher.Close()
	check(err)

	log.Println("bye!")
}
Пример #9
0
// NewFeatureMonitor watches the specified state directory, or the default
// state directory if an empty string is given.  The directory must exist.  The
// logger is used for I/O errors, unless nil.
func NewFeatureMonitor(stateDir string, logger Logger) (m *FeatureMonitor, err error) {
	if stateDir == "" {
		stateDir = DefaultStateDir
	}

	featureDir := filepath.Join(stateDir, "features")

	if err = os.Mkdir(featureDir, 0755); err != nil {
		if info, statErr := os.Stat(featureDir); statErr != nil || !info.IsDir() {
			return
		}
		err = nil
	}

	if featureDir, err = filepath.Abs(featureDir); err != nil {
		return
	}

	if featureDir, err = filepath.EvalSymlinks(featureDir); err != nil {
		return
	}

	watcher, err := inotify.NewWatcher()
	if err != nil {
		return
	}

	if err = watcher.AddWatch(featureDir, inotify.IN_ONLYDIR|inotify.IN_CREATE|inotify.IN_DELETE|inotify.IN_DELETE_SELF); err != nil {
		watcher.Close()
		return
	}

	c := make(chan *Feature)
	boot := make(chan struct{})

	m = &FeatureMonitor{
		C:       c,
		Boot:    boot,
		logger:  logger,
		closed:  make(chan struct{}, 1),
		watcher: watcher,
	}

	if infos, err := ioutil.ReadDir(featureDir); err == nil {
		for _, info := range infos {
			m.addFeature(filepath.Join(featureDir, info.Name()))
		}
	} else {
		m.log(err)
	}

	m.queued = append(m.queued, nil) // indicates end of boot

	go m.watchLoop(c, boot, featureDir)

	return
}
Пример #10
0
// eventloop prepares the inotify events and waits for them
func eventloop(mongo MongoInserter) {

	var currentlog LogFileReader

	// open current file
	if logtype == ALPS {
		currentlog = newAlpsLogfile(todayname(), mongo)
	} else {
		currentlog = newTorqueLogfile(todayname(), mongo)
	}
	watcher, err := inotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}

	err = watcher.Watch(config.WatchDirectory)
	if err != nil {
		log.Fatal(err)
	}

	// endless event loop, can be ended by QUIT channel
	for {

		select {

		case ev := <-watcher.Event:
			if (ev.Mask & inotify.IN_CREATE) > 0 {
				// if a file is created, check if it is same file or not, and if it could be
				// todays file
				//if ev.Name != currentlog.name && ev.Name == "testdata/apsched-c2-0c0s0n1-20160820" {
				if ev.Name != currentlog.getName() && ev.Name == todayname() {
					currentlog.readToEnd() // read rest of file in case we missed something
					if logtype == ALPS {
						currentlog = newAlpsLogfile(ev.Name, mongo)
					} else {
						currentlog = newTorqueLogfile(ev.Name, mongo)
					}
				}
			} else if (ev.Mask & inotify.IN_MODIFY) > 0 {
				// if a file is updated, read file to end if it is current file
				if ev.Name == currentlog.getName() {
					currentlog.readToEnd()
				}
			} else {
				// log.Println("inotify event:", ev)
			}

		case err := <-watcher.Error:
			log.Println("inotify error:", err)

		case <-QUIT: // end for testing
			return
		}

	}

}
Пример #11
0
func NewInotifyWatcher() (*InotifyWatcher, error) {
	w, err := inotify.NewWatcher()
	if err != nil {
		return nil, err
	}

	return &InotifyWatcher{
		watcher:           w,
		containersWatched: make(map[string]map[string]bool),
	}, nil
}
Пример #12
0
func inotifySetup(dir string) *inotify.Watcher {
	watcher, err := inotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	err = watcher.Watch(dir)
	if err != nil {
		log.Fatal(err)
	}

	return watcher
}
Пример #13
0
func main() {

	configFile := flag.String("c", "config.toml", "Config file path")
	flag.Parse()

	findSocatBinary()

	services := parseConfig(*configFile)

	for _, s := range services {
		if !s.Enabled {
			log.Println(fmt.Sprintf("Service %s is disabled", s.Name))
		} else {
			s.Start()
		}
	}

	var watch *inotify.Watcher
	var err error
	if watch, err = inotify.NewWatcher(); err != nil {
		log.Println(fmt.Sprintf("Could not create a watcher: %s. Changes will need a restart to become effective", err))
	} else {
		setWatch(watch, filepath.Dir(*configFile))
	}

	for {
		select {
		case ev := <-watch.Event:
			if filepath.Base(ev.Name) == *configFile {
				log.Println("Change on the config file detected. Reloading services...")

				unsetWatch(watch, filepath.Dir(*configFile))

				for _, s := range services {
					s.Stop()
				}

				<-time.NewTimer(time.Millisecond * 500).C
				services = parseConfig(*configFile)

				for _, s := range services {
					if !s.Enabled {
						log.Println(fmt.Sprintf("Service %s is disabled", s.Name))
					} else {
						s.Start()
					}
				}
				setWatch(watch, filepath.Dir(*configFile))
			}
		}
	}
}
Пример #14
0
// NewTail starts opens the given file and watches it for deletion/rotation
func NewTail(filename string) (*Tail, error) {
	t := &Tail{
		filename: filename,
	}
	var err error
	t.stop = make(chan bool)
	t.watcher, err = inotify.NewWatcher()
	if err != nil {
		return nil, fmt.Errorf("inotify init failed on %s: %v", t.filename, err)
	}
	go t.watchLoop()
	return t, nil
}
Пример #15
0
func (b *builder) watchDir(ctx context.Context, dir string, f func(*inotify.Event)) error {
	infos, err := ioutil.ReadDir(dir)
	if err != nil {
		return err
	}

	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	errc := make(chan error)
	for _, info := range infos {
		if !info.IsDir() {
			continue
		}
		go func(info os.FileInfo) {
			fn := func(ev *inotify.Event) {
				ev.Name = filepath.Join(dir, ev.Name)
				f(ev)
			}
			select {
			case errc <- b.watchDir(ctx, filepath.Join(dir, info.Name()), fn):
			case <-ctx.Done():
			}
		}(info)
	}

	w, err := inotify.NewWatcher()
	if err != nil {
		return err
	}
	defer w.Close()
	if err := w.AddWatch(dir, flags); err != nil {
		return err
	}
	for {
		select {
		case ev := <-w.Event:
			if ignore(ev.Name) {
				continue
			}
			f(ev)
		case err := <-w.Error:
			return err
		case err := <-errc:
			return err
		case <-ctx.Done():
			return ctx.Err()
		}
	}
}
Пример #16
0
func main() {
	hiddenPtr := flag.Bool("h", false, "include hidden")
	recursivePtr := flag.Bool("r", false, "recursive watcher")
	flag.Parse()

	args := flag.Args()
	if len(args) < 2 {
		fmt.Printf("Usage: %s PATH ACTION\n", os.Args[0])
		return
	}

	watcher, err := inotify.NewWatcher()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}

	err = addWatch(args[0], *recursivePtr, *hiddenPtr, watcher)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}

	acceptRate := int64(250) // multiple events are sent at once
	now := timestamp()
	child := make(chan error, 1)
	var cmd *exec.Cmd
	for {
		select {
		case <-watcher.Event:
			curr := timestamp()
			if curr-now > acceptRate {
				now = curr
				cmd = waitNext(cmd, args[1])
				cmd.Stdout = os.Stdout
				cmd.Stderr = os.Stderr
				go func() {
					child <- cmd.Run()
				}()
			}
		case err := <-watcher.Error:
			fmt.Fprintln(os.Stderr, err)
			return
		case err := <-child:
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
			}
		}
	}
}
Пример #17
0
// newTail creates a Tail object.
func newTail(filename string) (*Tail, error) {
	t := &Tail{
		filename: filename,
	}
	var err error
	t.stop = make(chan bool)
	t.watcher, err = inotify.NewWatcher()
	if err != nil {
		return nil, fmt.Errorf("inotify init failed on %s: %v", t.filename, err)
	}
	// Initialize readerErr as io.EOF, so that the reader can work properly
	// during initialization.
	t.readerErr = io.EOF
	return t, nil
}
Пример #18
0
func NewWatcher() (*Watcher, error) {
	w, err := inotify.NewWatcher()
	if err != nil {
		return nil, err
	}
	res := &Watcher{
		watcher: w,
		Event:   make(chan *Event),
		Error:   make(chan error),
		globs:   make([]string, 0),
	}
	go res.watchEvent()

	return res, nil
}
Пример #19
0
func initWatcher() (watcher *inotify.Watcher, err error) {
	LogWriter.Info("Initializing paxrat watcher")
	watcher, err = inotify.NewWatcher()
	if err != nil {
		return
	}
	for path, setting := range (*Conf).Settings {
		addWatchToClosestPath(watcher, path)
		err = setFlagsWatchMode(watcher, path, setting.Flags, setting.Nonroot)
		if err != nil {
			msg := fmt.Sprintf("setFlags error in initWatcher: %s", err)
			LogWriter.Err(msg)
		}
	}
	return
}
Пример #20
0
/* This is where we do the actual location monitoring. This
   is started as a concurent go routine, and monitors loc_id
   indefinatly.
   - loc_id is the index to the config.Locations array to
     monitor*/
func monitor(loc_id int, cont chan bool) {
	log.Println("Spinning up monitor on location ID:", loc_id)

	stop := false
	location := config.Locations[loc_id]
	if st, err := checkPermissions(location); err != nil {
		log.Error(err)
		return
	} else {
		log.Infoln("Permissions check for", location, "passed:", st.Mode())
	}
	watcher, err := inotify.NewWatcher()
	if err != nil {
		log.Error(err)
		return
	}
	err = watcher.Watch(location)
	if err != nil {
		log.Error(err)
		return
	}
	log.Infoln("Watcher up; monitoring:", location)
	for !stop {
		cached_id := uuid.New().String() //cache a new uuid
		select {
		case ev := <-watcher.Event:
			log.Debugln("monitored directory event:", ev)
			if ev.Mask == inotify.IN_CLOSE_WRITE {
				log.Info("Found; ", path.Base(ev.Name), " Moving to staging")
				os.Rename(ev.Name, config.Staging_loc+"/"+cached_id)
				var op Operation
				op.Code = ProcessFile
				op.Id = cached_id
				op.Name = path.Base(ev.Name)
				op.Location = path.Dir(ev.Name)
				op.Overwrite = false //TODO determine if this should be gleamed from the file name
				meta.stash <- op
			}
		case err := <-watcher.Error:
			log.Error("Monitor error;", err)
			continue
		case stop = <-cont:
			log.Infoln("Spinning down monitor on ", location)
			break
		}
	}
}
Пример #21
0
func TestWatch(t *testing.T) {
	log.SetLevel(log.DebugLevel)
	watcher, err := inotify.NewWatcher()
	if err != nil {
		t.Fatal(err)
	}

	watch(watcher, []string{testdataDir}, inotify.IN_ALL_EVENTS, false, true)

	if err := watcher.RemoveWatch(testdataDir); err != nil {
		t.Fatal(err)
	}

	if err := watcher.RemoveWatch(filepath.Join(testdataDir, "rec")); err == nil {
		t.Fatal("Should not watch recursively!")
	}
}
Пример #22
0
func DirectoryWatcher(dir string) {
	watcher, err := inotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	err = watcher.AddWatch(dir, inotify.IN_CLOSE_WRITE)
	if err != nil {
		log.Fatal(err)
	}
	for {
		select {
		case ev := <-watcher.Event:
			directoryWatcherFile(dir, ev.Name)
		case err := <-watcher.Error:
			log.Printf("directory watch: %s", err)
		}
	}
}
Пример #23
0
func watchDir(name string) {
	watcher, err := inotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	err = watcher.AddWatch(name, inotify.IN_CREATE)
	if err != nil {
		log.Fatal(err)
	}
	for {
		select {
		case ev := <-watcher.Event:
			watchEventChannel <- ev
		case err := <-watcher.Error:
			log.Println("error:", err)
		}
	}
}
Пример #24
0
func main() {
	X, err := xgbutil.NewConn()
	if err != nil {
		log.Fatal(err)
	}
	keybind.Initialize(X)

	currentuser, err := user.Current()
	if err != nil {
		log.Fatal(err)
	}
	configfile := currentuser.HomeDir + "/.config/hotkeys.conf.json"

	watcher, err := inotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	err = watcher.AddWatch(configfile, inotify.IN_CLOSE_WRITE)
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		for {
			select {
			case ev := <-watcher.Event:
				log.Println(ev)
				err := bindall(configfile, X)
				if err != nil {
					log.Println(err)
					continue
				}

			case err := <-watcher.Error:
				log.Println("error:", err)
			}
		}
	}()
	err = bindall(configfile, X)
	if err != nil {
		log.Panicln(err)
	}
	xevent.Main(X)
}
Пример #25
0
func monitorDHCPLeases() {
	watcher, err := inotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	err = watcher.AddWatch(dhcp_lease_file, inotify.IN_CLOSE_WRITE)
	if err != nil {
		log.Fatal(err)
	}
	for {
		select {
		case <-watcher.Event:
			log.Println("file modified, attempting to refresh DHCP")
			refreshConnectedClients()
		case err := <-watcher.Error:
			log.Println("error with DHCP file system watcher:", err)
		}
	}
}
Пример #26
0
func Watch() {
	watcher, err := inotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}

	paths, err := filepath.Glob(fmt.Sprintf("%s/*/*", *index))
	if err != nil {
		log.Fatal(err)
	}

	for _, path := range paths {
		fmt.Printf("watching %s\n", path)
		err = watcher.AddWatch(path, inotify.IN_MODIFY|inotify.IN_DELETE_SELF)
		if err != nil {
			log.Fatal(err)
		}
	}

	go func() {
		for {
			select {
			case ev := <-watcher.Event:
				if ev == nil {
					continue
				}

				log.Println("file was updated, reloading:", ev)
				LoadTemplates()
				BuildCache()

				if ev.Mask&inotify.IN_DELETE_SELF != 0 {
					log.Println("file was deleted, restartig:", ev)
					watcher.Close()
					Watch()
				}
			case <-watcher.Error:
				break
			}
		}
	}()
}
Пример #27
0
func (u *NetNSProbe) start() {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()

	watcher, err := inotify.NewWatcher()
	if err != nil {
		logging.GetLogger().Errorf("Unable to create a new Watcher: %s", err.Error())
		return
	}

	// wait for the path creation
	for {
		_, err := os.Stat(runBaseDir)
		if err == nil {
			break
		}
		time.Sleep(5 * time.Second)
	}

	err = watcher.Watch(runBaseDir)
	if err != nil {
		logging.GetLogger().Errorf("Unable to Watch %s: %s", runBaseDir, err.Error())
		return
	}

	u.initialize()

	for {
		select {
		case ev := <-watcher.Event:
			if ev.Mask&inotify.IN_CREATE > 0 {
				u.Register(ev.Name, nil)
			}
			if ev.Mask&inotify.IN_DELETE > 0 {
				u.Unregister(ev.Name)
			}

		case err := <-watcher.Error:
			logging.GetLogger().Errorf("Error while watching network namespace: %s", err.Error())
		}
	}
}
Пример #28
0
func main() {
	flags, err := config.LoadFlags("enqueued", &conf)
	if err != nil {
		log.Fatal(err)
	}
	flags.Parse(os.Args[1:])
	os.Chdir(conf.Root)

	if conf.Templates != "" {
		enqueuedMailer, err = mailer.NewMailer(conf.Templates)
		if err != nil {
			log.Fatal(err)
		}
	}

	files, err := ioutil.ReadDir(conf.Root)
	if err != nil {
		log.Fatal(err)
	}

	watcher, err := inotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}

	for _, file := range files {
		if err := Watch(watcher, file); err != nil {
			log.Fatal(err)
		}
	}

	for {
		select {
		case ev := <-watcher.Event:
			if ev.Mask^inotify.IN_CLOSE_WRITE != 0 ||
				!strings.HasSuffix(ev.Name, ".changes") {
				continue
			}
			Process(ev.Name)
		}
	}
}
Пример #29
0
func run(c *cli.Context) {
	var (
		flag uint32
		tpl  *template.Template
		ctx  = context.Background()
	)
	if !c.Args().Present() {
		cli.ShowAppHelp(c)
		return
	}

	log.SetLevel(log.Level(c.Int("verbose")))

	watcher, err := inotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}

	// Format.
	if fmtString := c.String("format"); fmtString != "" {
		tpl = template.Must(template.New("event-format").Parse(fmtString))
	}

	// Event flags.
	for _, event := range c.StringSlice("event") {
		flag |= parseEvent(event)
	}
	if flag == 0 {
		flag = inotify.IN_ALL_EVENTS
	}

	watch(watcher, c.Args(), flag, c.Bool("recursive"), true)

	// Configure timeout.
	if timeout := time.Duration(c.Int("timeout")) * time.Second; timeout > 0 {
		ctx, _ = context.WithTimeout(ctx, timeout)
	}

	match := buildMatcherFunc(c.StringSlice("exclude"), c.StringSlice("include"))
	waitForWatcher(ctx, watcher, match, tpl, c.Bool("monitor"))
}
Пример #30
0
// sysWatcher starts the watcher.
func sysWatcher(cmdTocompile string, pkgTowatch []string, logg *log.Logger) (*pkgWatcher, error) {
	watcher, err := inotify.NewWatcher()
	if err != nil {
		logg.Print("FAIL! sysWatcher: ", err)
		return nil, errWatcher
	}

	ok := true
	// Watch every path
	for _, path := range pkgTowatch {
		if err = watcher.AddWatch(path, inotify.IN_MODIFY); err != nil {
			logg.Print("FAIL! sysWatcher: ", err)
			ok = false
		}
	}

	if !ok {
		return nil, errWatcher
	}
	return &pkgWatcher{watcher, logg, cmdTocompile}, nil
}