<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>blogs on CatnapzZ&#39;s world</title>
    <link>https://catnapzz.site/posts/</link>
    <description>Recent content in blogs on CatnapzZ&#39;s world</description>
    <generator>Hugo -- 0.145.0</generator>
    <language>zh-CN</language>
    <lastBuildDate>Sun, 25 Oct 2026 00:56:28 +0800</lastBuildDate>
    <atom:link href="https://catnapzz.site/posts/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>关于O_NOCTTY的一些边角料</title>
      <link>https://catnapzz.site/posts/some-o-noctty/</link>
      <pubDate>Sat, 24 Oct 2026 23:44:27 +0800</pubDate>
      <guid>https://catnapzz.site/posts/some-o-noctty/</guid>
      <description>在Linux上写一个简陋的串口通讯工具时关于O_NOCTTY的一些思考</description>
      <content:encoded><![CDATA[<h2 id="什么是controlling-terminal">什么是controlling terminal？</h2>
<p>总的来说，controlling terminal是Unix 内核给一个 session 绑定的一个特殊 TTY 设备。 比如说在一个Terminal Emulator里运行一个shell:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Kitty
</span></span><span class="line"><span class="cl">  │
</span></span><span class="line"><span class="cl">  │ 申请创建 PTY
</span></span><span class="line"><span class="cl">  ▼
</span></span><span class="line"><span class="cl">/dev/pts/3
</span></span><span class="line"><span class="cl">  ├── bash
</span></span><span class="line"><span class="cl">  ├── vim
</span></span><span class="line"><span class="cl">  ├── ffmpeg
</span></span><span class="line"><span class="cl">  └── ./hello
</span></span></code></pre></div><p>这个bash所在session的controlling terminal通常就是/dev/pts/3，它主要负责把TTY产生的终端事件和一个session 中的进程关联起来。</p>
<h2 id="为什么usb串口也能成为-controlling-terminal">为什么USB串口也能成为 controlling terminal</h2>
<p>插入一个USB转串口设备时：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">USB 转串口芯片
</span></span><span class="line"><span class="cl">  │
</span></span><span class="line"><span class="cl">  ▼
</span></span><span class="line"><span class="cl">Linux USB serial driver
</span></span><span class="line"><span class="cl">  │
</span></span><span class="line"><span class="cl">  ▼
</span></span><span class="line"><span class="cl">TTY subsystem
</span></span><span class="line"><span class="cl">  │
</span></span><span class="line"><span class="cl">  ▼
</span></span><span class="line"><span class="cl">/dev/ttyUSB0
</span></span></code></pre></div><p>这个时候Linux 内核向用户空间暴露的是一个TTY对象。在内核看来，只要它是一个TTY，理论上就可以成为controlling terminal。 假设一个程序 open(&quot;/dev/ttyUSB0&quot;, O_RDWR) （没有指定O_NOCTTY）又恰好这个进程是session leader并且当前session没有controlling terminal又恰好打开的对象是一个可以作为ontrolling terminal的TTY等特定条件下，内核就可能记录session X 的 controlling tty = ttyUSB0，于是这个 TTY 上发生的一些终端语义，就可能作用于这个 session。</p>
<h2 id="o_noctty控制谁">O_NOCTTY控制谁</h2>
<p>O_NOCTTY 控制的是：调用 open() 的这个进程 / 它所属的 session，是否把被打开的 TTY 当作 controlling terminal。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;fcntl.h&gt;</span><span class="cp">
</span></span></span><span class="line"><span class="cl"><span class="cp"></span>
</span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">fd</span> <span class="o">=</span> <span class="nf">open</span><span class="p">(</span><span class="s">&#34;/dev/ttyUSB0&#34;</span><span class="p">,</span> <span class="n">O_RDWR</span> <span class="o">|</span> <span class="n">O_NOCTTY</span><span class="p">);</span>
</span></span></code></pre></div><h2 id="什么场景下更应该关注">什么场景下更应该关注</h2>
<p>普通场景下程序继承Terminal Emulator的controlling terminal,一个session通常不会因为后来随便open()一个/dev/ttyUSB0,就直接把controlling terminal换过去，所以很多时候表面上也不会出问题。 但如果程序进行了daemon化，条件满足的话串口设备就有可能莫名其妙变成这个session的控制终端。 O_NOCTTY作为open()的调用选项，它阻止的是“正在执行open的进程所在session”因为这次打开TTY，而获得“被打开TTY”作为 controlling terminal。</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
