SysRq를 위한 pyserial-miniterm에 send_break() 기능 추가하기

임베디드 리눅스 디바이스를 개발할 때, 시리얼 콘솔을 통해 커널 디버깅 또는 긴급 명령을 보내는 경우가 있다. 그중 하나가 Magic SysRq 키 조합을 시리얼 포트를 통해 보내는 기능이다. Magic SysRq는 리눅스 커널에서 정의된 특수한 시스템 요청 명령어로, 시스템 디버깅이나 복구에 사용된다. 이 기능을 시리얼 환경에서도 사용하려면 BREAK 신호를 전송해야 하는데, 필자가 Ubuntu에서 사용하는 pyserial의 miniterm은 이 기능을 지원하지 않는다. 이 글에서는 pyserial의 miniterm 도구에 send_break() 기능을 추가하는 방법을 알아본다.

pyserial-miniterm란?

pyserial-minitermpyserial 패키지에 포함된 시리얼 터미널 유틸리티다. 사용자는 키보드를 통해 시리얼 장치에 명령을 입력하고, 장치로부터 응답을 받을 수 있다.

실행 예시

python3 -m serial.tools.miniterm /dev/ttyUSB0 115200

miniterm에 BREAK 전송 핫키 추가하기

pyserial 소스 경로 확인

pyserial은 설치 후 보통 아래 경로에 존재한다 (Python 버전에 따라 다를 수 있음).

/usr/lib/python3.*/dist-packages/serial/tools/miniterm.py

필자의 경우는 /usr/lib/python3/dist-packages/serial/tools/miniterm.py를 사용하고 있었다.

키 입력 핸들러에 BREAK 전송 로직 추가

아래와 같이 miniterm.py를 수정해 k 키를 누르면 send break가 되도록 로직을 추가한다.

~$ diff -urN miniterm.py.old miniterm.py.new
--- miniterm.py.old     2025-03-27 16:00:06.404465438 +0900
+++ miniterm.py.new     2025-03-27 15:58:32.800830722 +0900
@@ -629,11 +629,18 @@
         elif c in 'rR':                         # R -> change hardware flow control
             self.serial.rtscts = (c == 'R')
             self.dump_port_settings()
+        elif c in 'kK':                         # K -> send break
+            self.send_break()
         elif c in 'qQ':
             self.stop()                         # Q -> exit app
         else:
             sys.stderr.write('--- unknown menu character {} --\n'.format(key_description(c)))

+    def send_break(self):
+        """Send BREAK signal (for SysRq)"""
+        sys.stderr.write('--- Sending BREAK (SysRq) ---\n')
+        self.serial.send_break()
+
     def upload_file(self):
         """Ask user for filenname and send its contents"""
         sys.stderr.write('\n--- File to upload: ')
@@ -793,6 +800,7 @@
 ---    b          change baud rate
 ---    x X        disable/enable software flow control
 ---    r R        disable/enable hardware flow control
+---    k          send break for SysRq
 """.format(version=getattr(serial, 'VERSION', 'unknown version'),
            exit=key_description(self.exit_character),
            menu=key_description(self.menu_character),
  • handle_menu_key() 함수에 k 키를 누르면 send_break()가 호출되도록 한다.
  • send_break() 함수를 추가한다. BREAK를 보낸다는 메시지를 출력하고 serial.send_break()를 호출한다.
  • get_help_text() 함수에 k 키가 SysRq용 send break라는 도움말을 추가한다.

동작 확인

동작 확인을 위해 Ctrl+tk를 눌러서 아래와 같이 출력되는지 확인한다.

--- Sending BREAK (SysRq) ---

이어서 h를 입력하면 SysRq에서 어떤 키를 쓸 수 있는지 확인할 수 있다.

--- Sending BREAK (SysRq) ---
[15105.052884] sysrq: HELP : loglevel(0-9) reboot(b) crash(c) terminate-all-tasks(e) memory-full-oom-kill(f) kill-all-tasks(i) thaw-filesystems(j) sak(k) show-backtrace-all-active-cpus(l) show-memory-usage(m) nice-all-RT-tasks(n) poweroff(o) show-registers(p) show-all-timers(q) unraw(r) sync(s) show-task-states(t) unmount(u) show-blocked-tasks(w) dump-ftrace-buffer(z) replay-kernel-logs(R)

동작을 확인했으므로, send break 후에 show-task-states(t)도 확인해 본다.

--- Sending BREAK (SysRq) ---
[   55.543055] sysrq: Show State
[   55.637848] Sched Debug Version: v0.11, 6.12.0-332 #1
[   55.642893] ktime                                   : 55636.023040
[   55.649061] sched_clk                               : 55637.847775
[   55.655229] cpu_clk                                 : 55637.847905
[   55.661395] jiffies                                 : 4294906210
[   55.667389]
[   55.668868] sysctl_sched
[   55.671388]   .sysctl_sched_base_slice                 : 2.250000
[   55.677469]   .sysctl_sched_features                   : 32695263
[   55.683549]   .sysctl_sched_tunable_scaling            : 1 (logarithmic)
[   55.690237]
[   55.691716] cpu#0
[   55.693630]   .nr_running                    : 1
[   55.698234]   .nr_switches                   : 513937
[   55.698237]   .nr_uninterruptible            : -4
[   55.698238]   .next_balance                  : 4294.906177
[   55.698240]   .curr->pid                     : 4918
[   55.698242]   .clock                         : 55543.171340
[   55.698244]   .clock_task                    : 55543.171340
[   55.698246]   .avg_idle                      : 640355
[   55.698247]   .max_idle_balance_cost         : 500000
[   55.698249]
[   55.698252] cfs_rq[0]:/
[   55.698255]   .left_deadline                 : 0.000001
[   55.698257]   .left_vruntime                 : 0.000001
[   55.698258]   .min_vruntime                  : 2666830.375357
[   55.698261]   .avg_vruntime                  : 2666830.375357
[   55.698262]   .right_vruntime                : 0.000001
[   55.698264]   .spread                        : 0.000000
[   55.698266]   .nr_running                    : 1
[   55.698267]   .h_nr_running                  : 1
...

Magic SysRq는 시스템 디버깅과 복구를 위한 강력한 커널 기능이며, pyserial의 minitermsend_break()를 연동하면 시리얼 콘솔만으로도 실전 디버깅 환경에서 이 기능을 그대로 쓸 수 있다. 이 글에서는 간단한 코드 수정으로 BREAK 전송 기능을 직접 구현하고 실제 동작을 확인했다.

참고 사이트

답글 남기기