<commit_before>require "pathname"

Ohai.plugin(:Hardware) do
  provides "hardware"

  def read_sysctl_link(file)
    File.basename(File.readlink(file))
  rescue Errno::ENOENT
  end

  def read_sysctl_file(file)
    IO.read(file).strip
  rescue Errno::ENOENT, Errno::EINVAL
  end

  def parse_memory_size(size)
    if size =~ /^(\d+(?:\.\d+)?)\s*TB/i
      Regexp.last_match(1).to_f * 2**30
    elsif size =~ /^(\d+(?:\.\d+)?)\s*GB/i
      Regexp.last_match(1).to_f * 2**20
    elsif size =~ /^(\d+(?:\.\d+)?)\s*MB/i
      Regexp.last_match(1).to_f * 2**10
    end
  end

  def format_disk_size(kb)
    if kb == 0
      ""
    else
      kblog10 = Math.log10(kb).floor

      kb = kb.to_f * 2 / 10**kblog10
      kb = kb.round.to_f / 2

      if kblog10 >= 9
        format "%gTB", kb * 10**(kblog10 - 9)
      elsif kblog10 >= 6
        format "%dGB", kb * 10**(kblog10 - 6)
      else
        format "%dMB", kb * 10**(kblog10 - 3)
      end
    end
  end

  def memory_to_disk_size(size)
    format_disk_size(parse_memory_size(size))
  end

  def find_sas_device(address)
    file = Dir.glob("/sys/class/scsi_generic/sg*/device/sas_address").find do |file|
      read_sysctl_file(file) == "0x#{address}"
    end

    if file
      dir = File.dirname(file)
      device = Dir.glob("#{dir}/block/*").first ||
               Dir.glob("#{dir}/scsi_generic/*").first

      "/dev/#{File.basename(device)}"
    end
  end

  def pci_devices
    devices = {}
    device = nil

    IO.popen(["lspci", "-Dkvmm"]).each do |line|
      if line =~ /^Slot:\s+((\h{4}):(\h{2}):(\h{2}).(\h))\s*$/
        device = {
          :slot => Regexp.last_match(1),
          :domain => Regexp.last_match(2),
          :bus => Regexp.last_match(3),
          :device => Regexp.last_match(4),
          :function => Regexp.last_match(5)
        }
      elsif device && line =~ /^([A-Z]+):\s+(.*)\s*$/i
        case Regexp.last_match(1)
        when "Class" then device[:class_name] = Regexp.last_match(2)
        when "Vendor" then device[:vendor_name] = Regexp.last_match(2)
        when "Device" then device[:device_name] = Regexp.last_match(2)
        when "SVendor" then device[:subsystem_vendor_name] = Regexp.last_match(2)
        when "SDevice" then device[:subsystem_device_name] = Regexp.last_match(2)
        when "PhySlot" then device[:physical_slot] = Regexp.last_match(2)
        when "Rev" then device[:revision] = Regexp.last_match(2)
        when "ProgIf" then device[:programming_interface] = Regexp.last_match(2)
        when "Driver" then device[:driver] = Regexp.last_match(2)
        when "Module" then device[:modules] = Array(device[:modules]) << Regexp.last_match(2)
        end
      elsif device && line =~ /^\s*$/
        devices[device[:slot]] = device
        device = nil
      end
    end

    IO.popen(["lspci", "-Dkvmmn"]).each do |line|
      if line =~ /^Slot:\s+((\h{4}):(\h{2}):(\h{2}).(\h))\s*$/
        device = devices[Regexp.last_match(1)]
      elsif device && line =~ /^([A-Z]+):\s+(.*)\s*$/i
        case Regexp.last_match(1)
        when "Class" then device[:class_id] = Regexp.last_match(2)
        when "Vendor" then device[:vendor_id] = Regexp.last_match(2)
        when "Device" then device[:device_id] = Regexp.last_match(2)
        when "SVendor" then device[:subsystem_vendor_id] = Regexp.last_match(2)
        when "SDevice" then device[:subsystem_device_id] = Regexp.last_match(2)
        end
      elsif device && line =~ /^\s*$/
        device = nil
      end
    end

    devices
  end

  def network_devices
    Dir.glob("/sys/class/net/*").each_with_object(Mash.new) do |device, devices|
      name = File.basename(device)

      devices[name] = {
        :device => read_sysctl_link("#{device}/device"),
        :duplex => read_sysctl_file("#{device}/duplex"),
        :speed => read_sysctl_file("#{device}/speed")
      }.delete_if { |_, v| v.nil? }
    end
  end

  def memory_devices
    device = nil

    IO.popen(["dmidecode", "-t", "memory"]).each_with_object([]) do |line, devices|
      if line =~ /^Memory Device\s*$/
        device = {}
      elsif device && line =~ /^\s+([A-Z ]+):\s+(.*)\s*$/i
        device[Regexp.last_match(1).tr(" ", "_").downcase.to_sym] = Regexp.last_match(2).strip
      elsif device && line =~ /^\s*$/
        devices << device
        device = nil
      end
    end
  end

  def disk_devices
    disk = Mash.new

    disk[:controllers] = []
    disk[:arrays] = []
    disk[:disks] = []

    find_direct_disks(disk)
    find_nvme_disks(disk)

    find_hp_disks(disk) if File.exist?("/usr/sbin/hpssacli")
    find_megaraid_disks(disk) if File.exist?("/usr/sbin/megacli")
    find_mpt_disks(disk) if File.exist?("/usr/sbin/sas2ircu")
    find_adaptec_disks(disk) if File.exist?("/usr/sbin/arcconf")
    find_areca_disks(disk) if File.exist?("/opt/areca/x86_64/cli64")

    find_md_arrays(disk)

    disk[:disks].each do |disk|
      if disk[:vendor] =~ /^CVPR/ && disk[:model] == "INTEL"
        disk[:model] = disk[:serial_number]
        disk[:serial_number] = disk[:vendor]
        disk[:vendor] = "INTEL"
      end

      if disk[:vendor].nil? && disk[:model] =~ /^ATA\s+(.*)$/
        disk[:vendor] = "ATA"
        disk[:model] = Regexp.last_match(1)
      end

      if disk[:vendor].nil? || disk[:vendor] == "ATA"
        if disk[:model] =~ /^(\S+)\s+(.*)$/
          disk[:vendor] = Regexp.last_match(1)
          disk[:model] = Regexp.last_match(2)
        elsif disk[:model] =~ /^ST/
          disk[:vendor] = "SEAGATE"
        elsif disk[:model] =~ /^C300-(.*)$/
          disk[:vendor] = "CRUCIAL"
          disk[:model] = Regexp.last_match(1)
        end
      end

      disk[:model].sub!(/-.*$/, "")
    end

    disk
  end

  def find_direct_disks(devices)
    Dir.glob("/sys/class/scsi_host/host*") do |host|
      driver = read_sysctl_file("#{host}/proc_name")

      if %w(ahci mptsas sata_mv sata_nv).include?(driver)
        bus = host.sub("/sys/class/scsi_host/host", "")

        Dir.glob("/sys/bus/scsi/devices/#{bus}:0:*").each do |device|
          next unless File.exist?("#{device}/scsi_disk")

          block = Dir.glob("#{device}/block/*").first
          size = read_sysctl_file("#{block}/size").to_f / 2

          devices[:disks] << {<commit_msg>Avoid exception for disks with no model<commit_after>require "pathname"

Ohai.plugin(:Hardware) do
  provides "hardware"

  def read_sysctl_link(file)
    File.basename(File.readlink(file))
  rescue Errno::ENOENT
  end

  def read_sysctl_file(file)
    IO.read(file).strip
  rescue Errno::ENOENT, Errno::EINVAL
  end

  def parse_memory_size(size)
    if size =~ /^(\d+(?:\.\d+)?)\s*TB/i
      Regexp.last_match(1).to_f * 2**30
    elsif size =~ /^(\d+(?:\.\d+)?)\s*GB/i
      Regexp.last_match(1).to_f * 2**20
    elsif size =~ /^(\d+(?:\.\d+)?)\s*MB/i
      Regexp.last_match(1).to_f * 2**10
    end
  end

  def format_disk_size(kb)
    if kb == 0
      ""
    else
      kblog10 = Math.log10(kb).floor

      kb = kb.to_f * 2 / 10**kblog10
      kb = kb.round.to_f / 2

      if kblog10 >= 9
        format "%gTB", kb * 10**(kblog10 - 9)
      elsif kblog10 >= 6
        format "%dGB", kb * 10**(kblog10 - 6)
      else
        format "%dMB", kb * 10**(kblog10 - 3)
      end
    end
  end

  def memory_to_disk_size(size)
    format_disk_size(parse_memory_size(size))
  end

  def find_sas_device(address)
    file = Dir.glob("/sys/class/scsi_generic/sg*/device/sas_address").find do |file|
      read_sysctl_file(file) == "0x#{address}"
    end

    if file
      dir = File.dirname(file)
      device = Dir.glob("#{dir}/block/*").first ||
               Dir.glob("#{dir}/scsi_generic/*").first

      "/dev/#{File.basename(device)}"
    end
  end

  def pci_devices
    devices = {}
    device = nil

    IO.popen(["lspci", "-Dkvmm"]).each do |line|
      if line =~ /^Slot:\s+((\h{4}):(\h{2}):(\h{2}).(\h))\s*$/
        device = {
          :slot => Regexp.last_match(1),
          :domain => Regexp.last_match(2),
          :bus => Regexp.last_match(3),
          :device => Regexp.last_match(4),
          :function => Regexp.last_match(5)
        }
      elsif device && line =~ /^([A-Z]+):\s+(.*)\s*$/i
        case Regexp.last_match(1)
        when "Class" then device[:class_name] = Regexp.last_match(2)
        when "Vendor" then device[:vendor_name] = Regexp.last_match(2)
        when "Device" then device[:device_name] = Regexp.last_match(2)
        when "SVendor" then device[:subsystem_vendor_name] = Regexp.last_match(2)
        when "SDevice" then device[:subsystem_device_name] = Regexp.last_match(2)
        when "PhySlot" then device[:physical_slot] = Regexp.last_match(2)
        when "Rev" then device[:revision] = Regexp.last_match(2)
        when "ProgIf" then device[:programming_interface] = Regexp.last_match(2)
        when "Driver" then device[:driver] = Regexp.last_match(2)
        when "Module" then device[:modules] = Array(device[:modules]) << Regexp.last_match(2)
        end
      elsif device && line =~ /^\s*$/
        devices[device[:slot]] = device
        device = nil
      end
    end

    IO.popen(["lspci", "-Dkvmmn"]).each do |line|
      if line =~ /^Slot:\s+((\h{4}):(\h{2}):(\h{2}).(\h))\s*$/
        device = devices[Regexp.last_match(1)]
      elsif device && line =~ /^([A-Z]+):\s+(.*)\s*$/i
        case Regexp.last_match(1)
        when "Class" then device[:class_id] = Regexp.last_match(2)
        when "Vendor" then device[:vendor_id] = Regexp.last_match(2)
        when "Device" then device[:device_id] = Regexp.last_match(2)
        when "SVendor" then device[:subsystem_vendor_id] = Regexp.last_match(2)
        when "SDevice" then device[:subsystem_device_id] = Regexp.last_match(2)
        end
      elsif device && line =~ /^\s*$/
        device = nil
      end
    end

    devices
  end

  def network_devices
    Dir.glob("/sys/class/net/*").each_with_object(Mash.new) do |device, devices|
      name = File.basename(device)

      devices[name] = {
        :device => read_sysctl_link("#{device}/device"),
        :duplex => read_sysctl_file("#{device}/duplex"),
        :speed => read_sysctl_file("#{device}/speed")
      }.delete_if { |_, v| v.nil? }
    end
  end

  def memory_devices
    device = nil

    IO.popen(["dmidecode", "-t", "memory"]).each_with_object([]) do |line, devices|
      if line =~ /^Memory Device\s*$/
        device = {}
      elsif device && line =~ /^\s+([A-Z ]+):\s+(.*)\s*$/i
        device[Regexp.last_match(1).tr(" ", "_").downcase.to_sym] = Regexp.last_match(2).strip
      elsif device && line =~ /^\s*$/
        devices << device
        device = nil
      end
    end
  end

  def disk_devices
    disk = Mash.new

    disk[:controllers] = []
    disk[:arrays] = []
    disk[:disks] = []

    find_direct_disks(disk)
    find_nvme_disks(disk)

    find_hp_disks(disk) if File.exist?("/usr/sbin/hpssacli")
    find_megaraid_disks(disk) if File.exist?("/usr/sbin/megacli")
    find_mpt_disks(disk) if File.exist?("/usr/sbin/sas2ircu")
    find_adaptec_disks(disk) if File.exist?("/usr/sbin/arcconf")
    find_areca_disks(disk) if File.exist?("/opt/areca/x86_64/cli64")

    find_md_arrays(disk)

    disk[:disks].each do |disk|
      if disk[:vendor] =~ /^CVPR/ && disk[:model] == "INTEL"
        disk[:model] = disk[:serial_number]
        disk[:serial_number] = disk[:vendor]
        disk[:vendor] = "INTEL"
      end

      if disk[:vendor].nil? && disk[:model] =~ /^ATA\s+(.*)$/
        disk[:vendor] = "ATA"
        disk[:model] = Regexp.last_match(1)
      end

      if disk[:vendor].nil? || disk[:vendor] == "ATA"
        if disk[:model] =~ /^(\S+)\s+(.*)$/
          disk[:vendor] = Regexp.last_match(1)
          disk[:model] = Regexp.last_match(2)
        elsif disk[:model] =~ /^ST/
          disk[:vendor] = "SEAGATE"
        elsif disk[:model] =~ /^C300-(.*)$/
          disk[:vendor] = "CRUCIAL"
          disk[:model] = Regexp.last_match(1)
        end
      end

      disk[:model].sub!(/-.*$/, "") if disk[:model]
    end

    disk
  end

  def find_direct_disks(devices)
    Dir.glob("/sys/class/scsi_host/host*") do |host|
      driver = read_sysctl_file("#{host}/proc_name")

      if %w(ahci mptsas sata_mv sata_nv).include?(driver)
        bus = host.sub("/sys/class/scsi_host/host", "")

        Dir.glob("/sys/bus/scsi/devices/#{bus}:0:*").each do |device|
          next unless File.exist?("#{device}/scsi_disk")

          block = Dir.glob("#{device}/block/*").first
          size = read_sysctl_file("#{block}/size").to_f / 2

          devices[:disks] << {
{'fraction_non_alphanumeric': 0.18139052782650295, 'fraction_numerical': 0.014670706426407271, 'mean_word_length': 2.5282700421940927, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, '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': '4145780', 'n_tokens_mistral': 4862, 'n_tokens_neox': 4658, 'n_words': 810}