<commit_before># frozen_string_literal: true

module Facter
  module Resolvers
    module Linux
      class Hostname < BaseResolver
        # :fqdn
        # :domain
        # :hostname

        init_resolver

        class << self
          private

          def post_resolve(fact_name, _options)
            @fact_list.fetch(fact_name) { retrieve_info(fact_name) }
          end

          def retrieve_info(fact_name)
            require 'socket'
            require 'facter/util/resolvers/ffi/hostname'

            output = retrieving_hostname
            return nil unless output

            # Check if the gethostname method retrieved fqdn
            hostname, domain = parse_fqdn(output)

            fqdn = retrieve_fqdn_for_host(hostname) if hostname_and_no_domain?(hostname, domain)

            _, domain = parse_fqdn(fqdn) if exists_and_valid_fqdn?(fqdn, hostname)

            domain = read_domain unless exists_and_not_empty?(domain)

            construct_fact_list(hostname, domain, fqdn)
            @fact_list[fact_name]
          end

          def retrieving_hostname
            output = Socket.gethostname
            if !output || output.empty? || output['0.0.0.0']
              output = Facter::Util::Resolvers::Ffi::Hostname.getffihostname
            end

            log.debug("Tried to retrieve hostname and got: #{output}")
            output && !output.empty? ? output : nil
          end

          def parse_fqdn(output)
            if output =~ /(.*?)\.(.+$)/
              log.debug("Managed to read hostname: #{Regexp.last_match(1)} and domain: #{Regexp.last_match(2)}")
              [Regexp.last_match(1), Regexp.last_match(2)]
            else
              log.debug("Only managed to read hostname: #{output}, no domain was found.")
              [output, '']
            end
          end

          def retrieve_fqdn_for_host(host)
            begin
              name = Socket.getaddrinfo(host, 0, Socket::AF_UNSPEC, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME)[0]
            rescue StandardError => e
              log.debug("Socket.getaddrinfo failed to retrieve fqdn for hostname #{host} with: #{e}")
            end

            return name[2] if !name.nil? && !name.empty? && host != name[2] && name[2] != name[3]

            retrieve_fqdn_for_host_with_ffi(host)
          end

          def retrieve_fqdn_for_host_with_ffi(host)
            fqdn = Facter::Util::Resolvers::Ffi::Hostname.getffiaddrinfo(host)
            log.debug("FFI getaddrinfo was called and it retrieved: #{fqdn}")
            fqdn
          end

          def exists_and_valid_fqdn?(fqdn, hostname)
            exists_and_not_empty?(fqdn) && fqdn.start_with?("#{hostname}.")
          end

          def hostname_and_no_domain?(hostname, domain)<commit_msg>(FACT-2989) load ffi only when needed<commit_after># frozen_string_literal: true

module Facter
  module Resolvers
    module Linux
      class Hostname < BaseResolver
        # :fqdn
        # :domain
        # :hostname

        init_resolver

        class << self
          private

          def post_resolve(fact_name, _options)
            @fact_list.fetch(fact_name) { retrieve_info(fact_name) }
          end

          def retrieve_info(fact_name)
            require 'socket'

            output = retrieving_hostname
            return nil unless output

            # Check if the gethostname method retrieved fqdn
            hostname, domain = parse_fqdn(output)

            fqdn = retrieve_fqdn_for_host(hostname) if hostname_and_no_domain?(hostname, domain)

            _, domain = parse_fqdn(fqdn) if exists_and_valid_fqdn?(fqdn, hostname)

            domain = read_domain unless exists_and_not_empty?(domain)

            construct_fact_list(hostname, domain, fqdn)
            @fact_list[fact_name]
          end

          def retrieving_hostname
            output = Socket.gethostname
            if !output || output.empty? || output['0.0.0.0']
              require 'facter/util/resolvers/ffi/hostname'

              output = Facter::Util::Resolvers::Ffi::Hostname.getffihostname
            end

            log.debug("Tried to retrieve hostname and got: #{output}")
            output && !output.empty? ? output : nil
          end

          def parse_fqdn(output)
            if output =~ /(.*?)\.(.+$)/
              log.debug("Managed to read hostname: #{Regexp.last_match(1)} and domain: #{Regexp.last_match(2)}")
              [Regexp.last_match(1), Regexp.last_match(2)]
            else
              log.debug("Only managed to read hostname: #{output}, no domain was found.")
              [output, '']
            end
          end

          def retrieve_fqdn_for_host(host)
            begin
              name = Socket.getaddrinfo(host, 0, Socket::AF_UNSPEC, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME)[0]
            rescue StandardError => e
              log.debug("Socket.getaddrinfo failed to retrieve fqdn for hostname #{host} with: #{e}")
            end

            return name[2] if !name.nil? && !name.empty? && host != name[2] && name[2] != name[3]

            retrieve_fqdn_for_host_with_ffi(host)
          end

          def retrieve_fqdn_for_host_with_ffi(host)
            require 'facter/util/resolvers/ffi/hostname'

            fqdn = Facter::Util::Resolvers::Ffi::Hostname.getffiaddrinfo(host)
            log.debug("FFI getaddrinfo was called and it retrieved: #{fqdn}")
            fqdn
          end

          def exists_and_valid_fqdn?(fqdn, hostname)
            exists_and_not_empty?(fqdn) && fqdn.start_with?("#{hostname}.")
          end

          def hostname_and_no_domain?(hostname, domain)
{'fraction_non_alphanumeric': 0.09945239357004063, 'fraction_numerical': 0.005652711535064477, 'mean_word_length': 2.0294275013376137, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4109242', 'n_tokens_mistral': 1726, 'n_tokens_neox': 1717, 'n_words': 356}