//go:build linux
// +build linux

package zapjournal

import (
	
	
	

	
	
)

// memfdName is a name used for memfd file descriptor.
const memfdName = "zapjournal"

// checkEnabled returns true if journald socket exists on the current system.
func () (bool, error) {
	,  := os.Stat(socketPath)
	switch {
	case os.IsNotExist():
		return false, nil
	case  != nil:
		return false, 
	default:
		return true, nil
	}
}

func ( UnixConn,  Config) zapcore.Core {
	 := getVarsEncoder(.Prefix)
	return &journalCore{
		LevelEnabler: .Level,
		path:         .Path,
		conn:         ,
		enc:          ,
	}
}

type journalCore struct {
	zapcore.LevelEnabler
	path string
	conn UnixConn
	enc  *varsEncoder
}

func ( *journalCore) ( []zapcore.Field) zapcore.Core {
	 := cloneVarsEncoder(.enc)
	addFields(, )
	return &journalCore{
		LevelEnabler: .LevelEnabler,
		path:         .path,
		conn:         .conn,
		enc:          ,
	}
}

func ( *journalCore) ( zapcore.Entry,  []zapcore.Field) error {
	 := .enc.encodeEntry(, )
	defer putVarsEncoder()

	 := &net.UnixAddr{
		Name: .path,
		Net:  "unixgram",
	}

	, ,  := .conn.WriteMsgUnix(.buf, nil, )
	if  == nil {
		return nil
	}
	if !isSocketSpaceError() {
		return 
	}

	,  := unix.MemfdCreate(memfdName, unix.MFD_CLOEXEC|unix.MFD_ALLOW_SEALING)
	if  != nil {
		return fmt.Errorf("create memfd: %w", )
	}

	 := os.NewFile(uintptr(), memfdName)
	defer func() { _ = .Close() }()

	if ,  := .Write(.buf);  != nil {
		return fmt.Errorf("write to memfd: %w", )
	}

	 := unix.F_SEAL_SHRINK | unix.F_SEAL_GROW | unix.F_SEAL_WRITE | unix.F_SEAL_SEAL
	if ,  := unix.FcntlInt(uintptr(), unix.F_ADD_SEALS, );  != nil {
		return fmt.Errorf("seal memfd: %w", )
	}

	 := unix.UnixRights()
	_, _,  = .conn.WriteMsgUnix(nil, , )
	return 
}

func ( *journalCore) ( zapcore.Entry,  *zapcore.CheckedEntry) *zapcore.CheckedEntry {
	if .Enabled(.Level) {
		return .AddCore(, )
	}
	return 
}

func ( *journalCore) () error {
	return nil
}

// isSocketSpaceError checks whether the error is signaling an "overlarge
// message" condition.
func ( error) bool {
	,  := .(*net.OpError)
	if ! ||  == nil {
		return false
	}

	,  := .Err.(*os.SyscallError)
	if ! ||  == nil {
		return false
	}

	return .Err == unix.EMSGSIZE || .Err == unix.ENOBUFS
}