func main() { fd, fd_err := syscall.Open(LOCK_PATH, syscall.O_CREAT, 0) if fd_err != nil { fmt.Printf("FD ERR:%v\n", fd_err) os.Exit(1) } flock_err := syscall.Flock(fd, syscall.LOCK_EX) if flock_err != nil { fmt.Printf("LOCK ERR:%v\n", flock_err) os.Exit(1) } // beginning of the code getting the exclusive lock fmt.Printf(".") time.Sleep(time.Second * 10) // end of the code getting the exclusive lock funlock_err := syscall.Flock(fd, syscall.LOCK_UN) if funlock_err != nil { fmt.Printf("UNLOCK ERR:%v\n", funlock_err) unlink_err := syscall.Unlink(LOCK_PATH) if unlink_err != nil { fmt.Printf("UNLINK ERR:%v\n", unlink_err) } os.Exit(1) } close_err := syscall.Close(fd) if close_err != nil { fmt.Printf("CLOSE ERR:%v\n", close_err) } unlink_err := syscall.Unlink(LOCK_PATH) if unlink_err != nil { fmt.Printf("UNLINK ERR:%v\n", unlink_err) } }
func setFileLock(f *os.File, lock bool) error { how := syscall.LOCK_UN if lock { how = syscall.LOCK_EX } return syscall.Flock(int(f.Fd()), how|syscall.LOCK_NB) }
/* Append a line to a file f, locking it first. Will return if f is empty */ func appendLine(fname, line string) { if 0 == len(fname) { return } /* Try to open the successes file */ f, err := os.OpenFile(fname, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644) /* Close on return */ defer f.Close() /* Give up if we can't */ if err != nil { log.Printf("Unable to open file %v: %v", f, err) return } /* Acquire an exclusive lock */ if syscall.Flock(int(f.Fd()), syscall.LOCK_EX) != nil { log.Printf("Unable to lock %v: %v", f, err) return } /* Release it when we're done */ defer syscall.Flock(int(f.Fd()), syscall.LOCK_UN) /* Write line to file */ r, err := f.WriteString(line) if err != nil { log.Printf("Error writing %\"%v\" to %v: %v", line, f, err) } if r < len(line) { log.Printf("Only wrote %v/%v bytes of \"%v\" to %v", r, len(line), line, f) } }
func (auth *Authinfo) Store() (err error) { authFile, err := os.Open(auth.path) auth.daemonLog.LogError(fmt.Sprintf("Unable to open %s for reading.", auth.path), err) err = syscall.Flock(int(authFile.Fd()), 2) //2 is exclusive lock if err != nil { err = errors.New(fmt.Sprintf("Failed to lock %s for reading.", auth.path)) } auth.lock.RLock() defer auth.lock.RUnlock() data, err := json.Marshal(auth.Users) _, err = authFile.Write(data) auth.daemonLog.LogError("Unable to write to file .", err) err = syscall.Flock(int(authFile.Fd()), 8) //8 is unlock if err != nil { err = errors.New(fmt.Sprintf("Unable to unlock %s for reading.", auth.path)) } fi, err := authFile.Stat() auth.dbstamp = fi.ModTime().Unix() authFile.Close() return }
// AcquireRepoLock opens the lock file and acquires the lock. // Dies if the lock cannot be successfully acquired. func AcquireRepoLock() { var err error // There is of course technically a bit of a race condition between the file & flock operations here, // but it shouldn't matter much since we're trying to mutually exclude plz processes started by the user // which (one hopes) they wouldn't normally do simultaneously. os.MkdirAll(path.Dir(lockFilePath), DirPermissions) // TODO(pebers): This doesn't seem quite as intended, I think the file still gets truncated sometimes. // Not sure why since I'm not passing O_TRUNC... if lockFile, err = os.OpenFile(lockFilePath, os.O_RDWR|os.O_CREATE, 0644); err != nil && !os.IsNotExist(err) { log.Fatalf("Failed to acquire lock: %s", err) } else if lockFile, err = os.Create(lockFilePath); err != nil { log.Fatalf("Failed to create lock: %s", err) } // Try a non-blocking acquire first so we can warn the user if we're waiting. log.Debug("Attempting to acquire lock %s...", lockFilePath) if err := syscall.Flock(int(lockFile.Fd()), syscall.LOCK_EX|syscall.LOCK_NB); err == nil { log.Debug("Acquired lock %s", lockFilePath) } else { log.Warning("Looks like another plz is already running in this repo. Waiting for it to finish...") if err := syscall.Flock(int(lockFile.Fd()), syscall.LOCK_EX); err != nil { log.Fatalf("Failed to acquire lock: %s", err) } } // Record the operation performed. if _, err = lockFile.Seek(0, os.SEEK_SET); err == nil { if n, err := lockFile.Write([]byte(strings.Join(os.Args[1:], " ") + "\n")); err == nil { lockFile.Truncate(int64(n)) } } }
// Checks status of daemonized process. // Can be used in daemon actions to perate with daemonized process. func Status() (isRunning bool, pr *os.Process, e error) { const errLoc = "daemonigo.Status()" var ( err error file *os.File ) file, err = os.Open(PidFile) if err != nil { if !os.IsNotExist(err) { e = fmt.Errorf( "%s: could not open PID file, reason -> %s", errLoc, err.Error(), ) } return } defer file.Close() fd := int(file.Fd()) if err = syscall.Flock( fd, syscall.LOCK_EX|syscall.LOCK_NB, ); err != syscall.EWOULDBLOCK { if err == nil { syscall.Flock(fd, syscall.LOCK_UN) } else { e = fmt.Errorf( "%s: PID file locking attempt failed, reason -> %s", errLoc, err.Error(), ) } return } isRunning = true var n, pid int content := make([]byte, 128) n, err = file.Read(content) if err != nil && err != io.EOF { e = fmt.Errorf( "%s: could not read from PID file, reason -> %s", errLoc, err.Error(), ) return } pid, err = strconv.Atoi(string(content[:n])) if n < 1 || err != nil { e = fmt.Errorf( "%s: bad PID format, PID file is possibly corrupted", errLoc, ) return } pr, err = os.FindProcess(pid) if err != nil { e = fmt.Errorf( "%s: cannot find process by PID, reason -> %s", errLoc, err.Error(), ) } return }
func (config *ConfigInfo) load() (err error) { configFile, err := os.Open(config.path) config.daemonLog.LogError(fmt.Sprintf("Cannot open %s for reading", config.path), err) if err != nil { os.Exit(1) } err = syscall.Flock(int(configFile.Fd()), 2) config.daemonLog.LogError("Error: Cannot read file for configurations", err) configContents, err := ioutil.ReadAll(configFile) config.daemonLog.LogError(fmt.Sprintf("Cannot read data from %s", config.path), err) err = syscall.Flock(int(configFile.Fd()), 8) if err != nil { config.daemonLog.LogError("Cannot unlock the config file for reading.", errors.New("Flock sys call Failed")) } fi, err := configFile.Stat() config.daemonLog.LogError(fmt.Sprintf("Stat of %s failed", err), err) err = configFile.Close() config.daemonLog.LogError("Cannot close file", err) config.lock.Lock() defer config.lock.Unlock() err = json.Unmarshal(configContents, &config.Data) config.daemonLog.LogError("Cannot unmarshall config.Data", err) config.tmstamp = fi.ModTime().Unix() return }
func readPid(fileName string) (int, error) { fd, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE, 0644) if err != nil { return 0, err } defer fd.Close() if err := syscall.Flock(int(fd.Fd()), syscall.LOCK_EX|syscall.LOCK_NB); err != nil { return 0, fmt.Errorf("can't lock '%s', lock is held", fd.Name()) } if _, err := fd.Seek(0, 0); err != nil { return 0, err } data, err := ioutil.ReadAll(fd) if err != nil { return 0, err } pid, err := strconv.Atoi(string(bytes.TrimSpace(data))) if err != nil { return 0, fmt.Errorf("error parsing pid from %s: %s", fd.Name(), err) } if err := syscall.Flock(int(fd.Fd()), syscall.LOCK_UN); err != nil { return 0, fmt.Errorf("can't release lock '%s', lock is held", fd.Name()) } return pid, nil }
func (r *Samjung) writeDataToFile(rowData []byte) (uint64, error) { // open file f, err := os.OpenFile(r.baseDir+"/"+tableFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0664) if err != nil { return 0, err } defer f.Close() // file lock err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX) if err != nil { return 0, err } defer syscall.Flock(int(f.Fd()), syscall.LOCK_UN) // seek end offset of file offset, err := f.Seek(0, os.SEEK_END) if err != nil { return 0, err } // write to file _, err = f.WriteAt(rowData, offset) if err != nil { return 0, err } return uint64(offset), nil }
func setFileLock(fp *os.File, lock bool) error { if lock { return syscall.Flock(int(fp.Fd()), syscall.LOCK_EX|syscall.LOCK_NB) } else { return syscall.Flock(int(fp.Fd()), syscall.LOCK_UN|syscall.LOCK_NB) } }
func storeVols() error { log.Info("Storing volume list...") VolData.lock.RLock() js, err := json.MarshalIndent(VolData, "", " ") VolData.lock.RUnlock() volFile, err := os.OpenFile(VolData.volFileName, syscall.O_WRONLY|syscall.O_CREAT, 0600) if err != nil { log.Error("DV: Cannot open for writing, file: " + DV_VOL_LIST_FILE) return err } defer volFile.Close() for err := syscall.Flock(int(volFile.Fd()), syscall.LOCK_EX); err == syscall.EINTR; { } defer syscall.Flock(int(volFile.Fd()), syscall.LOCK_UN) volFile.Truncate(0) _, err = volFile.Write(js) if err != nil { log.Errorf("Cannot write vol file - %v", err) return err } return nil }
func (v *Add) Run(c cli.Command) { jobName := c.Param("jobname").String() var job job.Job if _, err := toml.DecodeFile(metl.GetJobFilePath(jobName)+".toml", &job); err != nil { log.Fatal(err) } cronfile := filepath.Join(metl.Etl.GetLocalStoragePath(), crontabFile) file, err := os.Open(cronfile) if err != nil { file, err = os.Create(cronfile) if err != nil { log.WithFields( log.Fields{ "filename": cronfile, }, ).Fatal("Unable to create cronfile: ", err) } } defer file.Close() err = syscall.Flock(int(file.Fd()), syscall.LOCK_EX) if err != nil { log.Fatal("Failed to lock file") } defer func() { err = syscall.Flock(int(file.Fd()), syscall.LOCK_UN) if err != nil { log.Fatal("Failed to unlock file") } }() buffer := make([]string, 0) if err = jobIsInFile(file, jobName, &buffer); err != nil { log.Fatal(err) } buffer = append(buffer, fmt.Sprintf("%s %s >> %s%s.log", cmd, jobName, logDir, jobName)) tmpf, err := ioutil.TempFile(metl.Etl.GetLocalStoragePath(), "tmp") if err != nil { log.Fatal("Unable to create temporary file.") } for _, line := range buffer { if _, err := tmpf.WriteString(line + "\n"); err != nil { log.Fatal("Unable to write to temporary file") } } if err := os.Rename(tmpf.Name(), cronfile); err != nil { log.Fatal("Failed to rename temporary lock file:", err) } // execute /usr/bin/env crontab cronfile }
// writeKeys serializes the given key in the authorized_keys file (of the // current user). func writeKey(k *Key) error { file, err := fs.Filesystem().OpenFile(authKey(), os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644) if err != nil { return err } defer file.Close() syscall.Flock(int(file.Fd()), syscall.LOCK_EX) defer syscall.Flock(int(file.Fd()), syscall.LOCK_UN) return k.dump(file) }
func cat_new_mids() (floor uint64, ceiling uint64, tsh uint64, err error) { tsh = uint64(time.Now().Unix() / 3600) file, err := OpenFile(TEMPFILE, O_CREATE|O_RDWR, 0664) if err != nil { return 0, 0, tsh, errors.New("Unable to open temp file") } defer func() { file.Sync() file.Close() syscall.Flock(int(file.Fd()), syscall.LOCK_UN) }() share := make([]byte, 16) syscall.Flock(int(file.Fd()), syscall.LOCK_EX) n, err := file.Read(share) if err != nil && err != io.EOF { return 0, 0, tsh, errors.New("Unable to read temp file") } if n == 16 { var f uint64 = binary.BigEndian.Uint64(share[:8]) var l uint64 = binary.BigEndian.Uint64(share[8:]) if tsh > l { floor = 1 ceiling = 100000 buf := make([]byte, 8) binary.BigEndian.PutUint64(buf, uint64(ceiling)) file.WriteAt(buf, 0) binary.BigEndian.PutUint64(buf, uint64(tsh)) file.WriteAt(buf, 8) } else { floor = f ceiling = f + 100000 buf := make([]byte, 8) binary.BigEndian.PutUint64(buf, uint64(ceiling)) file.WriteAt(buf, 0) } } else if n == 0 { floor = 1 ceiling = 100000 buf := make([]byte, 8) binary.BigEndian.PutUint64(buf, uint64(ceiling)) n, err = file.WriteAt(buf, 0) if err != nil { return 0, 0, tsh, errors.New("Unable to write index to temp file") } binary.BigEndian.PutUint64(buf, uint64(tsh)) n, err = file.WriteAt(buf, 8) if err != nil { return 0, 0, tsh, errors.New("Unable to write tsh to temp file") } } else { return 0, 0, tsh, errors.New("Temp file is herpahs corrupted") } return floor, ceiling, tsh, nil }
func (r *Samjung) getAutoIncrement() (uint64, error) { isExist := true if _, err := os.Stat(r.baseDir + "/" + autoIncFile); os.IsNotExist(err) { isExist = false } // autoIncFile 없으면 파일 생성하면서 1 집어넣음 if isExist == false { f, err := os.OpenFile(r.baseDir+"/"+autoIncFile, os.O_WRONLY|os.O_CREATE, 0664) if err != nil { return 0, err } defer f.Close() _, err = f.WriteString("1") if err != nil { return 0, err } return 1, nil } // 있으면 + 1 해서 리턴해주고 저장 f, err := os.OpenFile(r.baseDir+"/"+autoIncFile, os.O_WRONLY, 0664) if err != nil { return 0, err } defer f.Close() // file lock err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX) if err != nil { return 0, err } defer syscall.Flock(int(f.Fd()), syscall.LOCK_UN) numByte, err := ioutil.ReadFile(r.baseDir + "/" + autoIncFile) if err != nil { return 0, err } number, err := strconv.ParseUint(string(numByte), 10, 64) if err != nil { return 0, err } number = number + 1 _, err = f.WriteString(strconv.FormatUint(number, 10)) if err != nil { return 0, err } return number, nil }
// Write writes a json marshalled, base64 encoded string // to file. `data` must be json serializable. func (f *Failover) Write(data interface{}) { msg, err := json.Marshal(data) if err != nil { log.Println(err) return } encodedData := string(base64.StdEncoding.EncodeToString(msg)) fd := int(f.File.Fd()) syscall.Flock(fd, syscall.LOCK_SH) f.File.WriteString(fmt.Sprintf("%s\n", encodedData)) syscall.Flock(fd, syscall.LOCK_UN) }
// Saves Meta data from dirTree to meta File func saveMeta(data *ReveloData) error { var Meta *horcrux.Meta var err error data.lock.RLock() Meta, err = dirTree.GetMeta(data.Root) Meta.Config = data.Config Meta.CurrVer = data.CurrVer data.lock.RUnlock() if err != nil { log.Error("saveMeta: Cannot get Meta data") return err } js, err := json.MarshalIndent(Meta, "", " ") if err != nil { log.WithFields( log.Fields{"Meta": Meta, "Error": err}).Error("saveMeta: Cannot marshal meta") return err } metaFile, err := os.OpenFile(data.cacheDir+"/"+data.metaName, os.O_WRONLY|os.O_SYNC, 0600) if err != nil { log.WithFields(log.Fields{"Meta File": data.metaName, "Error": err}).Error("saveMeta: Cannot open meta file") return err } defer metaFile.Close() // XXX Using File EX lock to avoid multiple access for err = syscall.Flock(int(metaFile.Fd()), syscall.LOCK_EX); err == syscall.EINTR; { } if err != nil { log.WithFields(log.Fields{"Error": err}).Error("saveMeta: Cannot lock meta file") return err } defer syscall.Flock(int(metaFile.Fd()), syscall.LOCK_UN) metaFile.Truncate(0) //XXX: Do Truncate(n) after write succeeds!! n, err := metaFile.Write(js) if err != nil { log.WithFields(log.Fields{ "Meta file": data.metaName, "Wrote": n, "Size": len(js), "Error": err, }).Error("saveMeta: Cannot write to meta file") return err } log.Debug("saveMeta: Done") return nil }
func deleteReservation(checkUser bool, args []string) { if len(args) != 1 { fatalf("Invalid arguments") } user, err := user.Current() path := filepath.Join(igorConfig.TFTPRoot, "/igor/reservations.json") resdb, err := os.OpenFile(path, os.O_RDWR, 664) if err != nil { fatalf("failed to open reservations file: %v", err) } defer resdb.Close() err = syscall.Flock(int(resdb.Fd()), syscall.LOCK_EX) defer syscall.Flock(int(resdb.Fd()), syscall.LOCK_UN) // this will unlock it later reservations := getReservations(resdb) var newres []Reservation var deletedReservation Reservation found := false if checkUser { for _, r := range reservations { if r.ResName == args[0] && r.Owner != user.Username { fatalf("You are not the owner of %v", args[0]) } } } for _, r := range reservations { if r.ResName != args[0] { newres = append(newres, r) } else { deletedReservation = r found = true } } if !found { fatalf("Couldn't find reservation %v", args[0]) } // Truncate the existing reservation file resdb.Truncate(0) resdb.Seek(0, 0) // Write out the new reservations enc := json.NewEncoder(resdb) enc.Encode(newres) resdb.Sync() // Delete all the PXE files in the reservation for _, pxename := range deletedReservation.PXENames { os.Remove(igorConfig.TFTPRoot + "/pxelinux.cfg/" + pxename) } }
func (l *layerStore) DoLocked(id string, fn func() error) error { f, err := os.OpenFile(l.lockPath(id), os.O_CREATE|os.O_RDWR, 0644) if err != nil { return err } defer os.Remove(f.Name()) defer f.Close() if err := syscall.Flock(int(f.Fd()), syscall.LOCK_EX); err != nil { return err } defer syscall.Flock(int(f.Fd()), syscall.LOCK_UN) return fn() }
func realMain() int { flag.Parse() if filesFlag == 0 || directoryFlag == "" { flag.Usage() return 1 } fmt.Println("Creating files...") var wg sync.WaitGroup for i := 1; i <= filesFlag; i++ { wg.Add(1) go func() { filename := fmt.Sprintf("%s/%s.lock", directoryFlag, uuid.NewUUID().String()) err := ioutil.WriteFile(filename, []byte("foo"), 0644) if err != nil { log.Fatalln(err) } wg.Done() }() } wg.Wait() defer cleanUp() fmt.Println("Getting all files in " + directoryFlag + "...") files, err := ioutil.ReadDir(directoryFlag) if err != nil { log.Fatalln(err) } fmt.Println("Opening all files and applying locks") for i, file := range files { fi, err := os.Open(directoryFlag + "/" + file.Name()) if err != nil { log.Fatalln(err) } defer fi.Close() fd := fi.Fd() if i%2 == 0 { syscall.Flock(int(fd), syscall.LOCK_EX|syscall.LOCK_NB) } else { syscall.Flock(int(fd), syscall.LOCK_SH) } } time.Sleep(time.Second * 3000) return 0 }
func TestAcquireRepoLock(t *testing.T) { // Grab the lock AcquireRepoLock() // Now we should be able to open the file (ie. it exists) lockFile, err := os.Open(lockFilePath) assert.NoError(t, err) defer lockFile.Close() assert.Error(t, syscall.Flock(int(lockFile.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)) // Let it go again ReleaseRepoLock() // Now we can get it assert.NoError(t, syscall.Flock(int(lockFile.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)) // Let it go so the following tests aren't confused :) assert.NoError(t, syscall.Flock(int(lockFile.Fd()), syscall.LOCK_UN)) }
func (f *FileLock) performLock(flockHow int) (performErr error) { if f.fileH != nil { return errors.Newf("FileLock is already acquired!") } filePath := path.Join(f.path, f.prefix+f.name) // GoLang os.OpenFile creates file with FD_CLOEXEC flag already set on it. // This means file will get closed automatically once the process exits, // thus we dont need to manually set that flag. fileH, err := os.Create(filePath) if err != nil { return err } defer func() { if performErr != nil { _ = fileH.Close() } }() if err := syscall.Flock(int(fileH.Fd()), flockHow); err != nil { return err } f.fileH = fileH return nil }
// TrySharedLock takes a co-operative (shared) lock without blocking. // This is idempotent when the Lock already represents a shared lock, // and tries demote an exclusive lock to shared atomically. // It will return ErrLocked if an exclusive lock already exists. func (l *FileLock) TrySharedLock() error { err := syscall.Flock(l.fd, syscall.LOCK_SH|syscall.LOCK_NB) if err == syscall.EWOULDBLOCK { err = ErrLocked } return err }
// TryExclusiveLock takes an exclusive lock without blocking. // This is idempotent when the Lock already represents an exclusive lock, // and tries promote a shared lock to exclusive atomically. // It will return ErrLocked if any lock is already held. func (l *FileLock) TryExclusiveLock() error { err := syscall.Flock(l.fd, syscall.LOCK_EX|syscall.LOCK_NB) if err == syscall.EWOULDBLOCK { err = ErrLocked } return err }
// PidfileOpen opens new pidfile, locks it, truncates and writes current pid to it func PidfileOpen(path string) (*Pidfile, error) { pf, err := pidfileOpenFile(path) if err != nil { return nil, err } defer func() { if err != nil { pf.Close() } }() err = syscall.Flock(int(pf.Fd()), syscall.LOCK_EX|syscall.LOCK_NB) if err != nil { return nil, fmt.Errorf("flock failed (other process running?): %s, %v", path, err) } err = pf.Truncate(0) if err != nil { return nil, err } _, err = fmt.Fprintf(pf, "%d\n", os.Getpid()) if err != nil { return nil, err } // everything is ok return &Pidfile{ f: pf, path: path, }, nil }
func GetLock(file *os.File, locktype int) { fmt.Println("Acquiring lock on ", file.Name()) Info.Println("Acquiring lock on ", file.Name()) syscall.Flock(int(file.Fd()), locktype) Info.Println("Acquired exclusive lock on ", file.Name()) fmt.Println("Acquired filelock on ", file.Name()) }
// LockWithErr locks a file as exclusively with error handling. // // If you use with blocking mode, Lock waits until obtaining a lock. // Else if you use with non-blocking mode, Lock doesn't wait to obtain a lock (means Lock makes failure immediately if cannot obtain a lock). func (l *Locker) LockWithErr() error { if l.file != nil { return ErrFailedToAcquireLock } if l.filename == "" { return ErrLockFileEmpty } var flags int if l.nonblock { flags = syscall.LOCK_EX | syscall.LOCK_NB } else { flags = syscall.LOCK_EX } file, err := os.OpenFile(l.filename, syscall.O_RDWR|syscall.O_NONBLOCK|syscall.O_APPEND|syscall.O_CREAT, 0600) // open append if err != nil { return fmt.Errorf("setlock: fatal: unable to open %s: temporary failure", l.filename) } defer func() { if l.file == nil { // Only close if we failed to flock file.Close() } }() err = syscall.Flock(int(file.Fd()), flags) if err != nil { return ErrFailedToAcquireLock } l.file = file return nil }
// TryShare is the non-blocking form of Share and will return an error if the // lock could not be obtained immediately. func TryShare(file *os.File) error { lock := syscall.LOCK_SH | syscall.LOCK_NB if err := syscall.Flock(int(file.Fd()), lock); err != nil { return err } return nil }
// TryExclusive is the non-blocking form of Exclusive and will return an // error if the lock could not be obtained immediately. func TryExclusive(file *os.File) error { lock := syscall.LOCK_EX | syscall.LOCK_NB if err := syscall.Flock(int(file.Fd()), lock); err != nil { return err } return nil }
// CreateLockFile tries to create a file with given name and acquire an // exclusive lock on it. If the file already exists AND is still locked, it will // fail. func CreateLockFile(filename string) (*os.File, error) { file, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE, 0600) if err != nil { return nil, err } err = syscall.Flock(int(file.Fd()), syscall.LOCK_EX|syscall.LOCK_NB) if err != nil { file.Close() return nil, err } // Write PID to lock file contents := strconv.Itoa(os.Getpid()) if err := file.Truncate(0); err != nil { file.Close() return nil, err } if _, err := file.WriteString(contents); err != nil { file.Close() return nil, err } return file, nil }