• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

yast / yast-kdump / 9611059066

21 Jun 2024 09:00AM UTC coverage: 40.556% (+0.4%) from 40.11%
9611059066

Pull #138

github

schubi2
removed frozen_string_literal
Pull Request #138: kdump is currently not compatible with Systemd Boot

40 of 159 new or added lines in 8 files covered. (25.16%)

22 existing lines in 5 files now uncovered.

730 of 1800 relevant lines covered (40.56%)

4.03 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.25
/src/modules/Kdump.rb
1
# ------------------------------------------------------------------------------
2
# Copyright (c) 2006 Novell, Inc. All Rights Reserved.
3
#
4
#
5
# This program is free software; you can redistribute it and/or modify it under
6
# the terms of version 2 of the GNU General Public License as published by the
7
# Free Software Foundation.
8
#
9
# This program is distributed in the hope that it will be useful, but WITHOUT
10
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License along with
14
# this program; if not, contact Novell, Inc.
15
#
16
# To contact Novell about this file by physical or electronic mail, you may find
17
# current contact information at www.novell.com.
18
# ------------------------------------------------------------------------------
19

20
# File:        modules/Kdump.ycp
21
# Package:        Configuration of kdump
22
# Summary:        Kdump settings, input and output functions
23
# Authors:        Jozef Uhliarik <juhliarik@suse.com>
24
#
25
# $Id: Kdump.ycp 27914 2006-02-13 14:32:08Z locilka $
26
#
27
# Representation of the configuration of kdump.
28
# Input and output routines.
29
require "yast"
1✔
30
require "kdump/kdump_system"
1✔
31
require "kdump/kdump_calibrator"
1✔
32

33
require "shellwords"
1✔
34

35
module Yast
1✔
36
  class KdumpClass < Module
1✔
37
    include Yast::Logger
1✔
38

39
    FADUMP_KEY = "KDUMP_FADUMP"
1✔
40
    KDUMP_SERVICE_NAME = "kdump"
1✔
41
    KDUMP_PACKAGES = ["kexec-tools", "kdump"].freeze
1✔
42
    TEMPORARY_CONFIG_FILE = "/var/lib/YaST2/kdump.sysconfig"
1✔
43
    TEMPORARY_CONFIG_PATH = Path.new(".temporary.sysconfig.kdump")
1✔
44

45
    # Space on disk reserved for dump additionally to memory size in bytes
46
    # @see FATE #317488
47
    RESERVED_DISK_SPACE_BUFFER_B = 4 * (1024**3)
1✔
48

49
    def main
1✔
50
      textdomain "kdump"
1✔
51

52
      Yast.import "Arch"
1✔
53
      Yast.import "Bootloader"
1✔
54
      Yast.import "Directory"
1✔
55
      Yast.import "FileUtils"
1✔
56
      Yast.import "Map"
1✔
57
      Yast.import "Message"
1✔
58
      Yast.import "Mode"
1✔
59
      Yast.import "Package"
1✔
60
      Yast.import "PackagesProposal"
1✔
61
      Yast.import "Popup"
1✔
62
      Yast.import "ProductControl"
1✔
63
      Yast.import "ProductFeatures"
1✔
64
      Yast.import "Progress"
1✔
65
      Yast.import "Report"
1✔
66
      Yast.import "Service"
1✔
67
      Yast.import "SpaceCalculation"
1✔
68
      Yast.import "String"
1✔
69
      Yast.import "Summary"
1✔
70

71
      reset
1✔
72
    end
73

74
    def reset
1✔
75
      # Data was modified?
76
      @modified = false
91✔
77

78
      # kdump config file
79

80
      @kdump_file = "/etc/sysconfig/kdump"
91✔
81

82
      @proposal_valid = false
91✔
83

84
      # Boolean option indicates that "crashkernel" includes
85
      # several values for the same kind of memory (low, high)
86
      # or several ranges in one of the values
87
      #
88
      # boolean true if there are several ranges (>1) or overriden values
89
      @crashkernel_list_ranges = false
91✔
90

91
      #  list of packages for installation
92
      @kdump_packages = []
91✔
93

94
      # Boolean option indicates kernel parameter
95
      # "crashkernel"
96
      #
97
      # boolean true if kernel parameter is set
98
      @crashkernel_param = false
91✔
99

100
      # Array (or String) with the values of the kernel parameter
101
      # "crashkernel"
102
      # It can also contain :missing or :present.
103
      # See Yast::Bootloader.kernel_param for details about those special values
104
      #
105
      # array values of kernel parameter
106
      @crashkernel_param_values = []
91✔
107

108
      # array values of kernel parameter for Xen hypervisor
109
      # see @crashkernel_param_values for details
110
      @crashkernel_xen_param_values = []
91✔
111

112
      # Boolean option indicates add kernel param
113
      # "crashkernel"
114
      #
115
      # boolean true if kernel parameter will be add
116
      @add_crashkernel_param = false
91✔
117

118
      # Set of values (high and low) for allocation of memory for boot param
119
      # "crashkernel"
120
      #
121
      # hash with up to two keys (:low and :high) and string values
122
      @allocated_memory = {}
91✔
123

124
      # Boolean option indicates that Import()
125
      # was called and data was proposed
126
      #
127
      # boolean true if import was called with data
128

129
      @import_called = false
91✔
130

131
      # Write only, used during autoinstallation/autoupgrade.
132
      # Don't run services and SuSEconfig, it's all done at one place.
133
      @write_only = false
91✔
134

135
      # Abort function
136
      # return boolean return true if abort
137
      @AbortFunction = nil
91✔
138

139
      # map of deafult values for options in UI
140
      #
141
      # global map <string, string >
142

143
      @DEFAULT_CONFIG = {
144
        "KDUMP_KERNELVER"          => "",
91✔
145
        "KDUMP_CPUS"               => "1",
146
        "KDUMP_COMMANDLINE"        => "",
147
        "KDUMP_COMMANDLINE_APPEND" => "",
148
        "KDUMP_AUTO_RESIZE"        => "false",
149
        "KEXEC_OPTIONS"            => "",
150
        "KDUMP_IMMEDIATE_REBOOT"   => "true",
151
        "KDUMP_TRANSFER"           => "",
152
        "KDUMP_SAVEDIR"            => "file:///var/crash",
153
        "KDUMP_KEEP_OLD_DUMPS"     => "0",
154
        "KDUMP_FREE_DISK_SIZE"     => "64",
155
        "KDUMP_VERBOSE"            => "0",
156
        "KDUMP_DUMPLEVEL"          => "31",
157
        "KDUMP_DUMPFORMAT"         => "compressed",
158
        "KDUMP_CONTINUE_ON_ERROR"  => "true",
159
        "KDUMP_REQUIRED_PROGRAMS"  => "",
160
        "KDUMP_PRESCRIPT"          => "",
161
        "KDUMP_POSTSCRIPT"         => "",
162
        "KDUMP_NETCONFIG"          => "auto",
163
        "KDUMP_NET_TIMEOUT"        => "30",
164
        "KDUMP_SMTP_SERVER"        => "",
165
        "KDUMP_SMTP_USER"          => "",
166
        "KDUMP_SMTP_PASSWORD"      => "",
167
        "KDUMP_NOTIFICATION_TO"    => "",
168
        "KDUMP_NOTIFICATION_CC"    => "",
169
        "KDUMP_HOST_KEY"           => ""
170
      }
171

172
      # map <string, string > of kdump settings
173
      #
174
      @KDUMP_SETTINGS = {}
91✔
175

176
      # initial kdump settings replaced in Read function
177
      @initial_kdump_settings = deep_copy(@KDUMP_SETTINGS)
91✔
178
    end
179

180
    # Abort function
181
    # @return [Boolean] return true if abort
182
    def Abort
1✔
183
      return @AbortFunction.call == true if !@AbortFunction.nil?
×
184

UNCOV
185
      false
×
186
    end
187

188
    # Data was modified?
189
    # @return true if modified
190
    def GetModified
1✔
191
      Builtins.y2debug("modified=%1", @modified)
1✔
192
      @modified
1✔
193
    end
194

195
    # Set data was modified
196
    def SetModified
1✔
197
      @modified = true
1✔
198
      Builtins.y2debug("modified=%1", @modified)
1✔
199

200
      nil
201
    end
202

203
    # Function set permission for file.
204
    #
205
    # @return        [Boolean] true on success
206
    # @param        string file name
207
    # @param [String] permissions
208
    #
209
    # @example
210
    #        FileUtils::Chmod ("/etc/sysconfig/kdump", "600") -> true
211
    #        FileUtils::Chmod ("/tmp/doesnt_exist", "644") -> false
212
    def Chmod(target, permissions)
1✔
213
      if !FileUtils.Exists(target)
×
214
        Builtins.y2error("Target %1 doesn't exist", target)
×
215
        return false
×
216
      end
217

218
      if !FileUtils.Exists("/bin/chmod")
×
219
        Builtins.y2error("tool: /bin/chmod not found")
×
220
        return false
×
221
      end
222

223
      cmd = Builtins.sformat("/bin/chmod %1 %2", permissions.shellescape, target.shellescape)
×
224
      cmd_out = Convert.to_map(SCR.Execute(path(".target.bash_output"), cmd))
×
225

226
      if Ops.get_integer(cmd_out, "exit", -1) != 0
×
227
        Builtins.y2error("Command >%1< returned %2", cmd, cmd_out)
×
228
        return false
×
229
      end
230
      Builtins.y2milestone("Command: %1 finish successful.", cmd)
×
231
      true
×
232
    end
233

234
    # Function check if KDUMP_SAVEDIR or
235
    # KDUMP_SMTP_PASSWORD include password
236
    #
237
    # @return [Boolean] true if inlude password
238

239
    def checkPassword
1✔
240
      return true if Ops.get(@KDUMP_SETTINGS, "KDUMP_SMTP_PASSWORD", "") != ""
×
241

242
      if Ops.get(@KDUMP_SETTINGS, "KDUMP_SAVEDIR", "").include?("file") ||
×
243
          Ops.get(@KDUMP_SETTINGS, "KDUMP_SAVEDIR", "").include?("nfs") ||
244
          Ops.get(@KDUMP_SETTINGS, "KDUMP_SAVEDIR", "") == ""
245
        return false
×
246
      end
247

NEW
248
      return false if !Ops.get(@KDUMP_SETTINGS, "KDUMP_SAVEDIR", "").include?("@")
×
249

250
      temp = Builtins.splitstring(
×
251
        Ops.get(@KDUMP_SETTINGS, "KDUMP_SAVEDIR", ""),
252
        "@"
253
      )
NEW
254
      position = Builtins.findlastof(Ops.get(temp, 0, ""), ":")
×
255
      return false if position.nil?
×
256

257
      # if there is 2 times ":" -> it means that password is defined
258
      # for example cifs://login:password@server....
259
      position > 6
×
260
    end
261

262
    # Read current kdump configuration
263
    #
264
    # read kernel parameter "crashkernel"
265
    #  @return [Boolean] successfull
266
    def ReadKdumpKernelParam
1✔
267
      result = Bootloader.kernel_param(:common, "crashkernel")
51✔
268
      xen_result = Bootloader.kernel_param(:xen_host, "crashkernel")
51✔
269
      # result could be [String,Array,:missing,:present]
270
      # String   - the value of the only occurrence
271
      # Array    - the values of the multiple occurrences
272
      # :missing - crashkernel is missed
273
      # :present - crashkernel is defined but no value is available
274

275
      if result == :missing
51✔
276
        @crashkernel_param = false
5✔
277
        @add_crashkernel_param = false
5✔
278
      else
279
        @crashkernel_param = true
46✔
280
        @add_crashkernel_param = true
46✔
281
      end
282

283
      if [:missing, :present].include?(result)
51✔
284
        @crashkernel_param_values = result
8✔
285
      else
286
        # Let's make sure it's an array
287
        # filtering nils and empty entries bnc#991140
288
        @crashkernel_param_values = Array(result).compact.reject(&:empty?)
43✔
289
        # Read the current value only if crashkernel parameter is set.
290
        # (bnc#887901)
291
        @allocated_memory = get_allocated_memory(@crashkernel_param_values)
43✔
292
      end
293

294
      @crashkernel_xen_param_values = if [:missing, :present].include?(xen_result)
51✔
295
        xen_result
8✔
296
      else
297
        # Let's make sure it's an array
298
        # filtering nils and empty entries bnc#991140
299
        Array(xen_result).compact.reject(&:empty?)
43✔
300
      end
301

302
      true
51✔
303
    end
304

305
    # Returns the KdumpSystem instance
306
    def system
1✔
307
      @system ||= Yast::KdumpSystem.new
×
308
    end
309

310
    def write_temporary_config_file
1✔
311
      SCR.RegisterAgent(TEMPORARY_CONFIG_PATH,
×
312
        term(:ag_ini,
313
          term(:SysConfigFile, TEMPORARY_CONFIG_FILE)))
314
      WriteKdumpSettingsTo(TEMPORARY_CONFIG_PATH, TEMPORARY_CONFIG_FILE)
×
315
      SCR.UnregisterAgent(TEMPORARY_CONFIG_PATH)
×
316
    end
317

318
    # Return the Kdump calibrator instance
319
    #
320
    # @return [Yast::KdumpCalibrator] Calibrator instance
321
    def calibrator
1✔
322
      return @calibrator unless @calibrator.nil?
82✔
323

324
      if Mode.normal
1✔
325
        @calibrator = Yast::KdumpCalibrator.new
1✔
326
      else
327
        write_temporary_config_file
×
328
        @calibrator = Yast::KdumpCalibrator.new(TEMPORARY_CONFIG_FILE)
×
329
      end
330
    end
331

332
    # Returns the Kdump memory limits
333
    #
334
    # It relies on the calibrator but it adjust the low memory limits when using firmware-assisted
335
    # dumps. The reason is that those limits might contradict the recommended value. See
336
    # jsc#SLE-21644 for more information.
337
    #
338
    # @return [Hash] The hash contains the following keys: :min_low, :max_low,
339
    #   :default_low, :min_high, :max_high, :default_high, :min_fadump,
340
    #    :max_fadump, :default_fadump
341
    def memory_limits
1✔
342
      calibrator.memory_limits
1✔
343
    end
344

345
    # Propose reserved/allocated memory
346
    # Store the result as a hash to @allocated_memory
347
    # @return [Boolean] true, always successful
348
    def ProposeAllocatedMemory
1✔
349
      # only propose once
350
      return true unless @allocated_memory.empty?
10✔
351

352
      @allocated_memory = { low: calibrator.default_low.to_s, high: calibrator.default_high.to_s }
8✔
353
      Builtins.y2milestone(
8✔
354
        "[kdump] allocated memory if not set in \"crashkernel\" param: %1",
355
        @allocated_memory
356
      )
357
      true
8✔
358
    end
359

360
    # Returns total size of physical memory in MiB
361
    def total_memory
1✔
362
      calibrator.total_memory
1✔
363
    end
364

365
    def log_settings_censoring_passwords(message)
1✔
366
      debug_KDUMP_SETTINGS = deep_copy(@KDUMP_SETTINGS)
2✔
367
      debug_KDUMP_SETTINGS["KDUMP_SAVEDIR"]       = "********"
2✔
368
      debug_KDUMP_SETTINGS["KDUMP_SMTP_PASSWORD"] = "********"
2✔
369

370
      log.info "-------------KDUMP_SETTINGS-------------------"
2✔
371
      log.info "#{message}; here with censored passwords: #{debug_KDUMP_SETTINGS}"
2✔
372
      log.info "---------------------------------------------"
2✔
373
    end
374

375
    # Read current kdump configuration
376
    #
377
    #  @return [Boolean] successful
378
    def ReadKdumpSettings
1✔
379
      @KDUMP_SETTINGS = deep_copy(@DEFAULT_CONFIG)
2✔
380
      SCR.Dir(path(".sysconfig.kdump")).each do |key|
2✔
381
        val = Convert.to_string(
×
382
          SCR.Read(path(".sysconfig.kdump") + key)
383
        )
384
        @KDUMP_SETTINGS[key] = val
×
385
      end
386

387
      log_settings_censoring_passwords("kdump configuration has been read")
2✔
388

389
      @initial_kdump_settings = deep_copy(@KDUMP_SETTINGS)
2✔
390

391
      true
2✔
392
    end
393

394
    # Updates initrd and reports whether it was successful.
395
    # Failed update is reported using Report library.
396
    #
397
    # @return [Boolean] whether successful
398
    def update_initrd
1✔
399
      # when /boot is ro, we need to use transactional update to be able to
400
      # rebuild initrd. In the end tu script below is used, but needs sauce
401
      # around
402
      if Package.IsTransactionalSystem
1✔
403
        update_initrd_with("transactional-update --continue kdump")
1✔
404
      else
NEW
405
        update_initrd_with("mkdumprd")
×
406
      end
407
    end
408

409
    # @param update_command [String] a command for .target.bash
410
    # @return [Boolean] whether successful
411
    def update_initrd_with(update_command)
1✔
412
      update_logfile = File.join(Directory.logdir, "y2logmkinitrd")
×
413

414
      run_command = update_command + " >> #{update_logfile.shellescape} 2>&1"
×
415
      y2milestone("Running command: #{run_command}")
×
416
      ret = SCR.Execute(path(".target.bash"), run_command)
×
417

418
      if ret != 0
×
419
        y2error("Error updating initrd, see #{update_logfile} or call #{update_command} manually")
×
NEW
420
        Report.Error(format(_(
×
421
          "Error updating initrd while calling '%{cmd}'.\n" \
422
          "See %{log} for details."
423
        ), :cmd => update_command, :log => update_logfile))
424
        return false
×
425
      end
426

427
      true
×
428
    end
429

430
    # Writes a file in the /etc/sysconfig/kdump format
431
    def WriteKdumpSettingsTo(scr_path, file_name)
1✔
432
      log_settings_censoring_passwords("kdump configuration for writing")
×
433

434
      @KDUMP_SETTINGS.each do |option_key, option_val|
×
435
        SCR.Write(scr_path + option_key, option_val)
×
436
      end
437
      SCR.Write(scr_path, nil)
×
438

439
      if checkPassword
×
440
        Chmod(file_name, "600")
×
441
      else
442
        Chmod(file_name, "644")
×
443
      end
444
    end
445

446
    # Write current kdump configuration
447
    #
448
    #  @return [Boolean] successful
449
    def WriteKdumpSettings
1✔
450
      WriteKdumpSettingsTo(path(".sysconfig.kdump"), @kdump_file)
×
451

452
      update_initrd
×
453
    end
454

455
    # Write kdump boot arguments - crashkernel and fadump
456
    # set kdump start at boot
457
    #
458
    #  @return [Boolean] successfull
459
    def WriteKdumpBootParameter
1✔
460
      reboot_needed = using_fadump_changed?
23✔
461

462
      # First, write or remove the fadump param if needed
463
      write_fadump_boot_param
23✔
464

465
      # Then, do the same for the crashkernel param
466
      #
467
      # If we need to add crashkernel param
468
      if @add_crashkernel_param
23✔
469
        if Mode.autoinst || Mode.autoupgrade
19✔
470
          # Use the value(s) read by import
471
          crash_values = @crashkernel_param_values
12✔
472
          crash_xen_values = @crashkernel_xen_param_values
12✔
473
          # Always write the value
474
          skip_crash_values = false
12✔
475
        else
476
          # Calculate the param values based on @allocated_memory
477
          crash_values = crash_kernel_values
7✔
478
          crash_xen_values = crash_xen_kernel_values
7✔
479
          remove_offsets!(crash_values) if Mode.update
7✔
480
          remove_offsets!(crash_xen_values) if Mode.update
7✔
481
          # Skip writing of param if it's already set to the desired values
482
          skip_crash_values = @crashkernel_param && @crashkernel_param_values == crash_values
7✔
483
          skip_crash_values &&= @crashkernel_xen_param_values && @crashkernel_xen_param_values == crash_xen_values
7✔
484
        end
485

486
        if skip_crash_values
19✔
487
          # start kdump at boot
488
          Service.Enable(KDUMP_SERVICE_NAME)
2✔
489
          Service.Restart(KDUMP_SERVICE_NAME) if Service.active?(KDUMP_SERVICE_NAME)
2✔
490
        else
491
          Bootloader.modify_kernel_params(:common, :recovery, "crashkernel" => crash_values)
17✔
492
          Bootloader.modify_kernel_params(:xen_host, "crashkernel" => crash_xen_values)
17✔
493
          # do mass write in installation to speed up, so skip this one
494
          if !Stage.initial
17✔
495
            old_progress = Progress.set(false)
17✔
496
            Bootloader.Write
17✔
497
            Progress.set(old_progress)
17✔
498
          end
499
          Builtins.y2milestone(
17✔
500
            "[kdump] (WriteKdumpBootParameter) adding crashkernel options with values: %1",
501
            crash_values
502
          )
503
          Builtins.y2milestone(
17✔
504
            "[kdump] (WriteKdumpBootParameter) adding xen crashkernel options with values: %1",
505
            crash_xen_values
506
          )
507
          reboot_needed = true
17✔
508
          Service.Enable(KDUMP_SERVICE_NAME)
17✔
509
        end
510
      else
511
        # If we don't need the param but it is there
512
        if @crashkernel_param
4✔
513
          # delete crashkernel parameter from bootloader
514
          Bootloader.modify_kernel_params(:common, :xen_guest, :recovery, :xen_host, "crashkernel" => :missing)
1✔
515
          if !Stage.initial
1✔
516
            old_progress = Progress.set(false)
1✔
517
            Bootloader.Write
1✔
518
            Progress.set(old_progress)
1✔
519
          end
520
          reboot_needed = true
1✔
521
        end
522
        Service.Disable(KDUMP_SERVICE_NAME)
4✔
523
        Service.Stop(KDUMP_SERVICE_NAME) if Service.active?(KDUMP_SERVICE_NAME)
4✔
524
      end
525

526
      if reboot_needed && Mode.normal && !Mode.commandline
23✔
527
        Popup.Message(_("To apply changes a reboot is necessary."))
18✔
528
      end
529

530
      true
23✔
531
    end
532

533
    # Read all kdump settings
534
    # @return true on success
535
    def Read
1✔
536
      # Kdump read dialog caption
537
      caption = _("Initializing kdump Configuration")
×
538
      steps = 4
×
539

540
      Progress.New(
×
541
        caption,
542
        " ",
543
        steps,
544
        [
545
          # Progress stage 1/4
546
          _("Reading the config file..."),
547
          # Progress stage 3/4
548
          _("Reading kernel boot options..."),
549
          # Progress stage 4/4
550
          _("Calculating memory limits...")
551
        ],
552
        [
553
          # Progress step 1/4
554
          _("Reading the config file..."),
555
          # Progress step 2/4
556
          _("Reading partitions of disks..."),
557
          # Progress finished 3/4
558
          _("Reading available memory and calibrating usage..."),
559
          # Progress finished 4/4
560
          Message.Finished
561
        ],
562
        ""
563
      )
564

565
      # read database
566
      return false if Abort()
×
567

UNCOV
568
      Progress.NextStage
×
569
      # Error message
NEW
570
      Report.Error(_("Cannot read config file /etc/sysconfig/kdump")) if !ReadKdumpSettings()
×
571

572
      # read another database
573
      return false if Abort()
×
574

UNCOV
575
      Progress.NextStep
×
576
      # Error message
NEW
577
      Report.Error(_("Cannot read kernel boot options.")) if !ReadKdumpKernelParam()
×
578

579
      # read another database
580
      return false if Abort()
×
581

582
      Progress.NextStep
×
583
      ProposeAllocatedMemory()
×
584
      # Error message
585
      Report.Error(_("Cannot read available memory.")) if total_memory.zero?
×
586

587
      return false if Abort()
×
588

589
      # Progress finished
590
      Progress.NextStage
×
591

592
      return false if Abort()
×
593

594
      @modified = false
×
595
      true
×
596
    end
597

598
    # Update crashkernel argument during update of OS
599
    # @return true on success
600

601
    def Update
1✔
602
      Builtins.y2milestone("Update kdump settings")
2✔
603
      ReadKdumpKernelParam() unless Mode.autoupgrade
2✔
604
      WriteKdumpBootParameter()
2✔
605
      true
2✔
606
    end
607

608
    # Write all kdump settings
609
    # @return true on success
610
    def Write
1✔
611
      # Kdump read dialog caption
612
      caption = _("Saving kdump Configuration")
×
613

614
      # number of stages
615
      steps = 2
×
616
      if (Mode.installation || Mode.autoinst) && !@add_crashkernel_param
×
617
        Builtins.y2milestone(
×
618
          "Skip writing of configuration for kdump during installation"
619
        )
620
        return true
×
621
      end
622

623
      # We do not set help text here, because it was set outside
624
      Progress.New(
×
625
        caption,
626
        " ",
627
        steps,
628
        [
629
          # Progress stage 1/2
630
          _("Write the settings"),
631
          # Progress stage 2/2
632
          _("Update boot options")
633
        ],
634
        [
635
          # Progress step 1/2
636
          _("Writing the settings..."),
637
          # Progress step 2/2
638
          _("Updating boot options..."),
639
          # Progress finished
640
          _("Finished")
641
        ],
642
        ""
643
      )
644

645
      # write settings
646
      return false if Abort()
×
647

UNCOV
648
      Progress.NextStage
×
649
      # Error message
650
      if !WriteKdumpSettings()
×
651
        Report.Error(_("Cannot write settings."))
×
652
        return false
×
653
      end
654

655
      # write/delete bootloader options for kernel - "crashkernel" and "fadump"
656
      return false if Abort()
×
657

UNCOV
658
      Progress.NextStage
×
659
      # Error message
660
      if !WriteKdumpBootParameter()
×
661
        Report.Error(_("Adding crashkernel parameter to bootloader fault."))
×
662
      end
663

664
      return false if Abort()
×
665

666
      # Progress finished
667
      Progress.NextStage
×
668

669
      return false if Abort()
×
670

UNCOV
671
      true
×
672
    end
673

674
    # Adding necessary packages for installation
675
    #
676

677
    def AddPackages
1✔
678
      return unless Mode.installation
1✔
679

680
      @kdump_packages.concat KDUMP_PACKAGES
×
681
    end
682

683
    # Proposes default state of kdump (enabled/disabled)
684
    #
685
    # @return [Boolean] the default proposed state
686

687
    def ProposeCrashkernelParam
1✔
688
      # proposing disabled kdump because it does not work with systemd-boot together
689
      if Bootloader.getLoaderType == "systemd-boot"
5✔
NEW
690
        log.info("kdump disabled because systemd-boot is active.")
×
NEW
691
        false
×
692
      # proposing disabled kdump if product wants it (bsc#1071242)
693
      elsif !ProductFeatures.GetBooleanFeature("globals", "enable_kdump")
5✔
694
        log.info "Kdump disabled in control file"
1✔
695
        false
1✔
696
      # proposing disabled kdump if PC has less than 1024MB RAM
697
      elsif total_memory < 1024
4✔
698
        log.info "not enough memory - kdump proposed as disabled"
1✔
699
        false
1✔
700
      # proposing disabled kdump on aarch64 (bsc#989321) - kdump not implemented
701
      elsif Arch.aarch64
3✔
702
        log.info "aarch64 - kdump proposed as disabled"
1✔
703
        false
1✔
704
      else
705
        true
2✔
706
      end
707
    end
708

709
    # Propose global variables once...
710
    # after that remember user settings
711

712
    def ProposeGlobalVars
1✔
713
      # Settings have not been imported by AutoYaST and have not already
714
      # been changed. (bnc#930950, bnc#995750, bnc#890719).
715
      if !@modified && !@import_called
1✔
716
        # added default settings
717
        @KDUMP_SETTINGS = deep_copy(@DEFAULT_CONFIG)
×
718
        @add_crashkernel_param = ProposeCrashkernelParam()
×
719
        @crashkernel_param = false
×
720
      end
721

722
      nil
723
    end
724

725
    # Check if user enabled kdump
726
    # if no deselect packages for installing
727
    # if yes add necessary packages for installation
728
    def CheckPackages
1✔
729
      # remove duplicates
730
      @kdump_packages.uniq!
1✔
731
      if @add_crashkernel_param
1✔
732
        Builtins.y2milestone(
1✔
733
          "select packages for installation: %1",
734
          @kdump_packages
735
        )
736
        @kdump_packages.each do |p|
1✔
NEW
737
          PackagesProposal.AddResolvables("yast2-kdump", :package, [p])
×
738
        end
739
        if !@kdump_packages.empty?
1✔
740
          Builtins.y2milestone(
×
741
            "Selected kdump packages for installation: %1",
742
            @kdump_packages
743
          )
744
        end
745
      else
UNCOV
746
        Builtins.y2milestone(
×
747
          "deselect packages for installation: %1",
748
          @kdump_packages
749
        )
UNCOV
750
        @kdump_packages.each do |p|
×
NEW
751
          PackagesProposal.RemoveResolvables("yast2-kdump", :package, [p])
×
752
        end
UNCOV
753
        if !@kdump_packages.empty?
×
754
          Builtins.y2milestone(
×
755
            "Deselected kdump packages for installation: %1",
756
            @kdump_packages
757
          )
758
        end
759
      end
760

761
      nil
762
    end
763

764
    # Propose all kdump settings
765
    #
766
    def Propose
1✔
767
      Builtins.y2milestone("Proposing new settings of kdump")
1✔
768
      # set default values for global variables
769
      ProposeGlobalVars()
1✔
770
      # check available memory and execute the calibrator
771
      ProposeAllocatedMemory()
1✔
772
      # add packages for installation
773
      AddPackages()
1✔
774
      # select packages for installation
775
      CheckPackages()
1✔
776

777
      nil
778
    end
779

780
    # Create a textual summary
781
    # @return summary of the current configuration
782
    def Summary
1✔
783
      result = []
1✔
784
      result = Builtins.add(
1✔
785
        result,
786
        Builtins.sformat(
787
          _("Kdump status: %1"),
788
          @add_crashkernel_param ? _("enabled") : _("disabled")
1✔
789
        )
790
      )
791
      if @add_crashkernel_param
1✔
792
        result = Builtins.add(
×
793
          result,
794
          Builtins.sformat(
795
            _("Value(s) of crashkernel option: %1"),
796
            crash_kernel_values.join(" ")
797
          )
798
        )
799
        result = Builtins.add(
×
800
          result,
801
          Builtins.sformat(
802
            _("Dump format: %1"),
803
            Ops.get(@KDUMP_SETTINGS, "KDUMP_DUMPFORMAT", "")
804
          )
805
        )
806
        result = Builtins.add(
×
807
          result,
808
          Builtins.sformat(
809
            _("Target of dumps: %1"),
810
            Ops.get(@KDUMP_SETTINGS, "KDUMP_SAVEDIR", "")
811
          )
812
        )
813
        result = Builtins.add(
×
814
          result,
815
          Builtins.sformat(
816
            _("Number of dumps: %1"),
817
            Ops.get(@KDUMP_SETTINGS, "KDUMP_KEEP_OLD_DUMPS", "")
818
          )
819
        )
820
      end
821
      deep_copy(result)
1✔
822
    end
823

824
    # Returns available space (in bytes) for Kernel dump according to KDUMP_SAVEDIR option
825
    # only local space is evaluated (starts with file://)
826
    #
827
    # @return [Integer] free space in bytes or nil if filesystem is not local or no
828
    #                   packages proposal is made yet
829
    def free_space_for_dump_b
1✔
830
      kdump_savedir = @KDUMP_SETTINGS.fetch("KDUMP_SAVEDIR", "file:///var/log/dump").dup
8✔
831
      log.info "Using savedir #{kdump_savedir}"
8✔
832

833
      if kdump_savedir.start_with?("/")
8✔
UNCOV
834
        log.warn "Using old format"
×
835
      elsif kdump_savedir.start_with?("file://")
8✔
836
        kdump_savedir.sub!(/file:\/\//, "")
6✔
837
      else
838
        log.info "KDUMP_SAVEDIR #{kdump_savedir.inspect} is not local"
2✔
839
        return nil
2✔
840
      end
841

842
      # unified format of directory
843
      kdump_savedir = format_dirname(kdump_savedir)
6✔
844

845
      partitions_info = SpaceCalculation.GetPartitionInfo()
6✔
846
      if partitions_info.empty?
6✔
847
        log.warn "No partitions info available"
1✔
848
        return nil
1✔
849
      end
850

851
      log.info "Disk usage: #{partitions_info}"
5✔
852
      # Create a hash of partitions and their free space { partition => free_space, ... }
853
      # "name" usually does not start with "/", but does so for root filesystem
854
      # File.join ensures that paths do not contain dulplicit "/" characters
855
      partitions_info = partitions_info.map do |partition|
5✔
856
        { format_dirname(partition["name"]) => partition["free"] }
15✔
857
      end.inject(:merge)
858

859
      # All partitions matching KDUMP_SAVEDIR
860
      matching_partitions = partitions_info.select do |partition, _space|
5✔
861
        kdump_savedir.start_with?(partition)
15✔
862
      end
863

864
      # The longest match
865
      partition = matching_partitions.keys.max_by { |partiton| partiton.length }
13✔
866
      free_space = matching_partitions[partition]
5✔
867

868
      if free_space.nil? || !free_space.is_a?(::Integer)
5✔
869
        log.warn "Available space for partition #{partition} not provided (#{free_space.inspect})"
2✔
870
        return nil
2✔
871
      end
872

873
      # packager counts in kB, we need bytes
874
      free_space *= 1024
3✔
875
      log.info "Available space for dump: #{free_space} bytes in #{partition} directory"
3✔
876

877
      free_space
3✔
878
    end
879

880
    # Returns disk space in bytes requested for kernel dump (as defined in FATE#317488)
881
    #
882
    # @return [Integer] bytes
883
    def space_requested_for_dump_b
1✔
884
      # Total memory is in MB, converting to bytes
885
      (total_memory * (1024**2)) + RESERVED_DISK_SPACE_BUFFER_B
1✔
886
    end
887

888
    # Returns installation proposal warning as part of the MakeProposal map result
889
    # includes 'warning' and 'warning_level' keys
890
    #
891
    # @param returns [Hash] with warnings
892
    def proposal_warning
1✔
893
      return {} unless @add_crashkernel_param
3✔
894

895
      free_space = free_space_for_dump_b
2✔
896
      requested_space = space_requested_for_dump_b
2✔
897

898
      log.info "Free: #{free_space}, requested: #{requested_space}"
2✔
899
      return {} if free_space.nil? || requested_space.nil?
2✔
900

901
      warning = {}
2✔
902
      warning_string = ""
2✔
903

904
      if free_space < requested_space
2✔
905
        # TRANSLATORS: warning message in installation proposal. Do not translate %{requested} and
906
        # %{available} - they are replaced with actual sizes later.
907
        warning_string = format(_(
1✔
908
          "Warning! There might not be enough free space to have kdump enabled. " \
909
          "%{required} required for saving a kernel dump, but only %{available} are available."
910
        ), required: String.FormatSizeWithPrecision(requested_space, 2, true), available: String.FormatSizeWithPrecision(free_space, 2, true))
911
      end
912

913
      if Bootloader.getLoaderType == "systemd-boot" && @add_crashkernel_param
2✔
NEW
914
        warning_string += "<br>" if !warning_string.empty?
×
NEW
915
        warning_string += _("Kdump will not be installed correctly if Systemd Boot is used.")
×
916
      end
917

918
      if !warning_string.empty?
2✔
919
        warning = {
920
          "warning_level" => :warning,
1✔
921
          "warning"       => "<ul><li>" + warning_string + "</li></ul>"
922
        }
923
      end
924

925
      log.warn warning["warning"] if warning["warning"]
2✔
926
      warning
2✔
927
    end
928

929
    # bnc# 480466 - fix problem with validation autoyast profil
930
    # Function filters keys for autoyast profil
931
    #
932
    # @param map <string, string > KDUMP_SETTINGS
933
    # @return [Hash{String => String}] filtered KDUMP_SETTINGS by DEFAULT_CONFIG
934

935
    def filterExport(settings)
1✔
936
      settings = deep_copy(settings)
1✔
937
      keys = Map.Keys(@DEFAULT_CONFIG)
1✔
938
      Builtins.filter(settings) do |key, _value|
1✔
939
        Builtins.contains(keys, key)
26✔
940
      end
941
    end
942

943
    # Export kdump settings to a map
944
    # @return kdump settings
945
    def Export
1✔
946
      if @add_crashkernel_param
3✔
947
        crash_kernel = crash_kernel_values
1✔
948
        crash_kernel = crash_kernel[0] if crash_kernel.size == 1
1✔
949
        crash_xen_kernel = crash_xen_kernel_values
1✔
950
        crash_xen_kernel = crash_xen_kernel[0] if crash_xen_kernel.size == 1
1✔
951
        out = {
952
          "crash_kernel"     => crash_kernel,
1✔
953
          "crash_xen_kernel" => crash_xen_kernel,
954
          "add_crash_kernel" => true,
955
          "general"          => filterExport(@KDUMP_SETTINGS)
956
        }
957
      else
958
        out = { "add_crash_kernel" => false }
2✔
959
      end
960

961
      Builtins.y2milestone("Kdump exporting settings: %1", out)
3✔
962
      deep_copy(out)
3✔
963
    end
964

965
    # Import settings from a map
966
    # @param [Hash, nil] settings map of kdump settings
967
    # @return [Boolean] true on success
968
    def Import(settings)
1✔
969
      settings ||= {}
16✔
970
      Builtins.y2milestone("Importing settings for kdump #{settings.inspect}")
16✔
971

972
      my_import_map = Ops.get_map(settings, "general", {})
16✔
973
      @DEFAULT_CONFIG.each_pair do |key, def_value|
16✔
974
        value = my_import_map[key]
416✔
975
        @KDUMP_SETTINGS[key] = value.nil? ? def_value : value
416✔
976
      end
977

978
      if settings.key?("crash_kernel")
16✔
979
        # Make sure it's an array
980
        @crashkernel_param_values = Array(settings.fetch("crash_kernel", ""))
9✔
981
        # In order not to overwrite the values by the proposal we will have to set
982
        # according allocated memory too. (bnc#995750)
983
        @allocated_memory = get_allocated_memory(@crashkernel_param_values)
9✔
984
      else
985
        # Taking proposed values (bnc#997448)
986
        ProposeAllocatedMemory()
7✔
987
        # Make sure it's an array
988
        @crashkernel_param_values = Array(crash_kernel_values)
7✔
989
      end
990

991
      @crashkernel_xen_param_values = if settings.key?("crash_xen_kernel")
16✔
992
        # Make sure it's an array
993
        Array(settings.fetch("crash_xen_kernel", ""))
6✔
994
      else
995
        Array(crash_xen_kernel_values)
10✔
996
      end
997

998
      @add_crashkernel_param = if settings.key?("add_crash_kernel")
16✔
999
        settings["add_crash_kernel"]
15✔
1000
      else
1001
        ProposeCrashkernelParam()
1✔
1002
      end
1003

1004
      if settings.key?("crash_kernel") || settings.key?("add_crash_kernel") ||
16✔
1005
          !my_import_map.empty?
1006
        @import_called = true
15✔
1007
      end
1008

1009
      true
16✔
1010
    end
1011

1012
    # Sets whether to use FADump (Firmware assisted dump)
1013
    #
1014
    # @param [Boolean] new state
1015
    # @return [Boolean] whether successfully set
1016
    def use_fadump(new_value)
1✔
1017
      # Trying to use fadump on unsupported hardware
1018
      if !fadump_supported? && new_value
7✔
1019
        Builtins.y2milestone("FADump is not supported on this hardware")
1✔
1020
        Report.Error(_("Cannot use Firmware-assisted dump.\nIt is not supported on this hardware."))
1✔
1021
        return false
1✔
1022
      end
1023

1024
      @KDUMP_SETTINGS[FADUMP_KEY] = (new_value ? "true" : "false")
6✔
1025
      true
6✔
1026
    end
1027

1028
    # Returns whether FADump (Firmware assisted dump) is currently in use
1029
    #
1030
    # @return [Boolean] currently in use
1031
    def using_fadump?
1✔
1032
      ["yes", "true", "1"].include?(@KDUMP_SETTINGS[FADUMP_KEY])
3✔
1033
    end
1034

1035
    # Has the using_fadump? been changed?
1036
    #
1037
    # @return [Boolean] whether changed
1038
    def using_fadump_changed?
1✔
1039
      @initial_kdump_settings[FADUMP_KEY] != @KDUMP_SETTINGS[FADUMP_KEY]
25✔
1040
    end
1041

1042
    # Returns whether usage of high memory in the crashkernel bootloader param
1043
    # is supported by the current system
1044
    #
1045
    # @return [Boolean] is supported
1046
    def high_memory_supported?
1✔
1047
      calibrator.high_memory_supported?
×
1048
    end
1049

1050
    # Returns whether usage of fadump is supported by the current system
1051
    #
1052
    # @return [Boolean] is supported
1053
    def fadump_supported?
1✔
1054
      calibrator.fadump_supported?
5✔
1055
    end
1056

1057
    publish :function => :GetModified, :type => "boolean ()"
1✔
1058
    publish :function => :SetModified, :type => "void ()"
1✔
1059
    publish :variable => :modified, :type => "boolean"
1✔
1060
    publish :variable => :proposal_valid, :type => "boolean"
1✔
1061
    publish :function => :total_memory, :type => "integer ()"
1✔
1062
    publish :variable => :crashkernel_list_ranges, :type => "boolean"
1✔
1063
    publish :variable => :kdump_packages, :type => "list <string>"
1✔
1064
    publish :variable => :crashkernel_param, :type => "boolean"
1✔
1065
    publish :variable => :add_crashkernel_param, :type => "boolean"
1✔
1066
    publish :variable => :allocated_memory, :type => "map"
1✔
1067
    publish :function => :memory_limits, :type => "map ()"
1✔
1068
    publish :variable => :import_called, :type => "boolean"
1✔
1069
    publish :variable => :write_only, :type => "boolean"
1✔
1070
    publish :variable => :AbortFunction, :type => "boolean ()"
1✔
1071
    publish :variable => :DEFAULT_CONFIG, :type => "map <string, string>"
1✔
1072
    publish :variable => :KDUMP_SETTINGS, :type => "map <string, string>"
1✔
1073
    publish :function => :Abort, :type => "boolean ()"
1✔
1074
    publish :function => :Read, :type => "boolean ()"
1✔
1075
    publish :function => :Update, :type => "boolean ()"
1✔
1076
    publish :function => :Write, :type => "boolean ()"
1✔
1077
    publish :function => :CheckPackages, :type => "void ()"
1✔
1078
    publish :function => :Propose, :type => "void ()"
1✔
1079
    publish :function => :Summary, :type => "list <string> ()"
1✔
1080
    publish :function => :Export, :type => "map ()"
1✔
1081
    publish :function => :Import, :type => "boolean (map)"
1✔
1082

1083
    # Offer this to ensure backward compatibility
1084
    def allocated_memory=(memory)
1✔
1085
      @allocated_memory = if memory.is_a?(::String)
10✔
1086
        if memory.empty?
3✔
1087
          {}
1✔
1088
        else
1089
          { low: memory }
2✔
1090
        end
1091
      else
1092
        memory
7✔
1093
      end
1094
    end
1095

1096
  private
1✔
1097

1098
    # Returns unified directory name with leading and ending "/"
1099
    # for exact matching
1100
    def format_dirname(dirname)
1✔
1101
      "/#{dirname}/".gsub(/\/+/, "/")
21✔
1102
    end
1103

1104
    # get allocated memory from the set of values of the crashkernel option
1105
    #
1106
    # each value can be a set of ranges (first range will be taken) or a
1107
    # concrete value for high or low memory
1108
    # syntax for ranges: 64M@16M or 128M-:64M@16M [(reserved_memory*2)-:reserved_memory]
1109
    # syntax for concrete value: 64M or 64M,high or 64M,low
1110
    #
1111
    #  @param crash_values [Array<string>] list of values
1112
    #  @return [Hash] values of allocated memory ({low: "64", high: "16"})
1113
    def get_allocated_memory(crash_values)
1✔
1114
      result = {}
52✔
1115
      crash_values.each do |crash_value|
52✔
1116
        pieces = crash_value.split(",")
62✔
1117

1118
        if pieces.last =~ /^(low|high)$/i
62✔
1119
          key = pieces.last.downcase.to_sym
28✔
1120
          @crashkernel_list_ranges ||= (pieces.size > 2)
28✔
1121
        else
1122
          key = :low
34✔
1123
          @crashkernel_list_ranges ||= (pieces.size > 1)
34✔
1124
        end
1125
        # Skip everything but the first occurrence
1126
        if result[key]
62✔
1127
          @crashkernel_list_ranges = true
4✔
1128
          next
4✔
1129
        end
1130

1131
        range = pieces.first
58✔
1132
        Builtins.y2milestone("The 1st range from crashkernel is %1", range)
58✔
1133
        value = range.split(":").last.split("M").first
58✔
1134
        result[key] = value
58✔
1135
      end
1136
      Builtins.y2milestone("Allocated memory is %1", result)
52✔
1137
      result
52✔
1138
    end
1139

1140
    # Build crashkernel values from allocated memory
1141
    #
1142
    # @return [Array<String>] list of values of crashkernel
1143
    def crash_kernel_values
1✔
1144
      # If the current values include "nasty" things and the user has not
1145
      # overriden the value of @crashkernel_list_ranges to autorize the
1146
      # modification.
1147
      # The old value (ensuring the Array format) will be returned.
1148
      if @crashkernel_list_ranges
15✔
1149
        return Array(@crashkernel_param_values.to_s) if @crashkernel_param_values.is_a?(Symbol)
2✔
1150

1151
        return Array(@crashkernel_param_values.dup)
2✔
1152
      end
1153

1154
      result = []
13✔
1155
      if ["yes", "true", "1"].include?(@KDUMP_SETTINGS["KDUMP_AUTO_RESIZE"])
13✔
1156
        maxsize = total_memory / 2
×
1157
        if high_memory_supported?
×
1158
          low = memory_limits[:default_low]
×
1159
          high = memory_limits[:max_high]
×
1160
          high = (maxsize - low.to_i).to_s if high.to_i > maxsize
×
1161
        else
1162
          high = memory_limits[:min_high]
×
1163
          low = memory_limits[:max_low]
×
1164
          low = maxsize.to_s if low.to_i > maxsize
×
1165
        end
1166
      else
1167
        high = @allocated_memory[:high]
13✔
1168
        low = @allocated_memory[:low]
13✔
1169
      end
1170
      result << "#{high}M,high" if high && high.to_i != 0
13✔
1171
      # Add the ',low' suffix only there is a ',high' one
1172
      result << (result.empty? ? "#{low}M" : "#{low}M,low") if low && low.to_i != 0
13✔
1173

1174
      log.info "built crashkernel values are #{result}"
13✔
1175

1176
      result
13✔
1177
    end
1178

1179
    def crash_xen_kernel_values
1✔
1180
      # If the current values include "nasty" things and the user has not
1181
      # overriden the value of @crashkernel_list_ranges to autorize the
1182
      # modification.
1183
      # The old value (ensuring the Array format) will be returned.
1184
      if @crashkernel_list_ranges
18✔
1185
        if @crashkernel_xen_param_values.is_a?(Symbol)
2✔
1186
          return Array(@crashkernel_xen_param_values.to_s)
×
1187
        end
1188

1189
        return Array(@crashkernel_xen_param_values.dup)
2✔
1190
      end
1191

1192
      result = []
16✔
1193
      if ["yes", "true", "1"].include?(@KDUMP_SETTINGS["KDUMP_AUTO_RESIZE"])
16✔
1194
        high = memory_limits[:default_high]
×
1195
        low = memory_limits[:default_low]
×
1196
      else
1197
        high = @allocated_memory[:high]
16✔
1198
        low = @allocated_memory[:low]
16✔
1199
      end
1200
      sum = 0
16✔
1201
      sum += low.to_i if low
16✔
1202
      sum += high.to_i if high
16✔
1203

1204
      result << "#{sum}M\\<4G" if sum != 0
16✔
1205

1206
      log.info "built xen crashkernel values are #{result}"
16✔
1207

1208
      result
16✔
1209
    end
1210

1211
    # Removes offsets from all the crashkernel values
1212
    #
1213
    # Beware: not functional, it modifies the passed argument
1214
    #
1215
    # @param values [Array,Symbol] list of values or one of the special values
1216
    #       returned by Bootloader.kernel_param
1217
    def remove_offsets!(values)
1✔
1218
      # It could also be :missing or :present
1219
      return unless values.is_a?(Array)
4✔
1220

1221
      values.map! do |value|
4✔
1222
        pieces = value.split("@")
4✔
1223
        Builtins.y2milestone("Delete offset crashkernel value: %1", value) if pieces.size > 1
4✔
1224
        pieces.first
4✔
1225
      end
1226
    end
1227

1228
    def write_fadump_boot_param
1✔
1229
      return unless fadump_supported?
23✔
1230

1231
      # If fdump is selected and we want to enable kdump
NEW
1232
      value = "on" if using_fadump? && @add_crashkernel_param
×
NEW
1233
      Bootloader.modify_kernel_params(:common, :recovery, "fadump" => value)
×
NEW
1234
      Bootloader.Write unless Yast::Stage.initial # do mass write in installation to speed up
×
1235
    end
1236
  end
1237

1238
  Kdump = KdumpClass.new
1✔
1239
  Kdump.main
1✔
1240
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc