func lockPortable(name string) (io.Closer, error) {
	fi, err := os.Stat(name)
	if err == nil && fi.Size() > 0 {
		st := portableLockStatus(name)
		switch st {
		case statusLocked:
			return nil, fmt.Errorf("file %q already locked", name)
		case statusStale:
			os.Remove(name)
		case statusInvalid:
			return nil, fmt.Errorf("can't Lock file %q: has invalid contents", name)
		}
	}
	f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_EXCL, 0666)
	if err != nil {
		return nil, fmt.Errorf("failed to create lock file %s %v", name, err)
	}
	if err := json.NewEncoder(f).Encode(&pidLockMeta{OwnerPID: os.Getpid()}); err != nil {
		return nil, fmt.Errorf("cannot write owner pid: %v", err)
	}
	return &unlocker{
		f:        f,
		abs:      name,
		portable: true,
	}, nil
}
lockPortable is a portable version not using fcntl. Doesn't handle crashes as gracefully,
since it can leave stale lock files.
package lock  
import (
	"encoding/json"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"sync"
)
func Lock(name string) (io.Closer, error) {
	abs, err := filepath.Abs(name)
	if err != nil {
		return nil, err
	}
	lockmu.Lock()
	defer lockmu.Unlock()
	if locked[abs] {
		return nil, fmt.Errorf("file %q already locked", abs)
	}
	c, err := lockFn(abs)
	if err != nil {
		return nil, fmt.Errorf("cannot acquire lock: %v", err)
	}
	locked[abs] = true
	return c, nil
}
var lockFn = lockPortable