-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
511 lines (267 loc) · 294 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Ssk-wh's Blog</title>
<link href="https://ssk-wh.github.io/atom.xml" rel="self"/>
<link href="https://ssk-wh.github.io/"/>
<updated>2024-07-12T03:05:34.000Z</updated>
<id>https://ssk-wh.github.io/</id>
<author>
<name>ssk-wh</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>ostree中GPG签名的使用方式</title>
<link href="https://ssk-wh.github.io/2024/0754520fd3.html"/>
<id>https://ssk-wh.github.io/2024/0754520fd3.html</id>
<published>2024-07-11T00:00:00.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<p>OSTree 是一个用于版本化文件系统树的工具,可以将其视为 Git 的文件系统版本。OSTree 不仅支持文件系统的版本管理,还支持使用 GPG 对其提交进行签名,以确保数据的完整性和来源的可信性。下面介绍 GPG 签名的原理和如何在 OSTree 中使用它。</p><span id="more"></span><h2 id="GPG签名简介"><a href="#GPG签名简介" class="headerlink" title="GPG签名简介"></a>GPG签名简介</h2><p>GPG(GNU Privacy Guard)签名是一种用于验证数字内容完整性和真实性的方法。GPG是一个开源的加密软件,广泛用于数据加密和数字签名。</p><h3 id="GPG签名的工作原理"><a href="#GPG签名的工作原理" class="headerlink" title="GPG签名的工作原理"></a>GPG签名的工作原理</h3><h4 id="生成密钥对"><a href="#生成密钥对" class="headerlink" title="生成密钥对"></a>生成密钥对</h4><ul><li>用户生成一对密钥:一个私钥(private key)和一个公钥(public key)。</li><li>私钥用于创建签名,公钥用于验证签名。</li></ul><h4 id="签名过程"><a href="#签名过程" class="headerlink" title="签名过程"></a>签名过程</h4><ul><li>当用户想要对一段数据(如文件、电子邮件等)进行签名时,GPG使用用户的私钥对数据进行哈希运算,生成一个摘要(hash)。</li><li>这个摘要通过私钥加密后,形成签名附加在原始数据上。</li></ul><h4 id="验证签名"><a href="#验证签名" class="headerlink" title="验证签名"></a>验证签名</h4><ul><li>接收者使用签名者的公钥对签名进行解密,得到哈希值。</li><li>接收者对接收到的数据重新计算哈希值,并与解密得到的哈希值进行比较。</li><li>如果两个哈希值一致,说明数据没有被篡改,并且签名确实是由持有私钥的人生成的。</li></ul><h3 id="GPG签名的应用"><a href="#GPG签名的应用" class="headerlink" title="GPG签名的应用"></a>GPG签名的应用</h3><ul><li><strong>软件分发</strong>:开发者使用GPG签名他们发布的软件,用户可以通过验证签名确保下载的软件是原版且未被篡改。</li><li><strong>电子邮件</strong>:使用GPG对电子邮件进行签名,接收者可以确认邮件内容的完整性和发送者的身份。</li><li><strong>文档和合同</strong>:对重要的文件和合同进行数字签名,确保文件在传输过程中的完整性。</li></ul><h3 id="使用GPG签名的步骤"><a href="#使用GPG签名的步骤" class="headerlink" title="使用GPG签名的步骤"></a>使用GPG签名的步骤</h3><h4 id="安装-GPG"><a href="#安装-GPG" class="headerlink" title="安装 GPG"></a>安装 GPG</h4><p> 如果尚未安装 GPG,可以通过以下命令安装:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt install gnupg</span><br></pre></td></tr></table></figure><h4 id="生成密钥对-1"><a href="#生成密钥对-1" class="headerlink" title="生成密钥对"></a>生成密钥对</h4><p>如果尚未生成 GPG 密钥对,可以使用以下命令生成:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --full-generate-key</span><br></pre></td></tr></table></figure><p>选择合适的选项并按照提示生成密钥对。</p><h4 id="签名文件"><a href="#签名文件" class="headerlink" title="签名文件"></a>签名文件</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --sign <file></span><br></pre></td></tr></table></figure><h4 id="验证签名-1"><a href="#验证签名-1" class="headerlink" title="验证签名"></a>验证签名</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --verify <file>.gpg</span><br></pre></td></tr></table></figure><p>通过GPG签名,可以有效地保护数字内容的完整性和真实性,广泛应用于软件开发、安全通信和数据保护等领域。</p><h2 id="OSTree-GPG-签名的原理"><a href="#OSTree-GPG-签名的原理" class="headerlink" title="OSTree GPG 签名的原理"></a>OSTree GPG 签名的原理</h2><p>GPG 签名用于验证数据的完整性和来源。通过对 OSTree 提交进行 GPG 签名,可以确保文件系统树在传输和部署过程中没有被篡改,并且确实来自预期的签名者。</p><h2 id="配置和使用-OSTree-GPG-签名"><a href="#配置和使用-OSTree-GPG-签名" class="headerlink" title="配置和使用 OSTree GPG 签名"></a>配置和使用 OSTree GPG 签名</h2><h3 id="准备工作"><a href="#准备工作" class="headerlink" title="准备工作"></a>准备工作</h3><h4 id="列出所有-GPG-密钥"><a href="#列出所有-GPG-密钥" class="headerlink" title="列出所有 GPG 密钥"></a>列出所有 GPG 密钥</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --list-keys</span><br></pre></td></tr></table></figure><p>这将显示你密钥环中的所有公钥。输出类似于以下格式:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">pub rsa2048 2021-01-01 [SC] [expires: 2023-01-01]</span><br><span class="line"> 3AA5C34371567BD2</span><br><span class="line">uid [ultimate] Your Name <[email protected]></span><br><span class="line">sub rsa2048 2021-01-01 [E] [expires: 2023-01-01]</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="识别密钥-ID"><a href="#识别密钥-ID" class="headerlink" title="识别密钥 ID"></a>识别密钥 ID</h4><p>在输出中,pub 行包含公钥信息。下面是如何识别密钥 ID:</p><ul><li>公钥行的第二行显示密钥 ID。例如,上面的输出中,3AA5C34371567BD2 是密钥 ID。</li><li>uid 行显示用户名和电子邮件地址。你可以通过用户名或电子邮件地址识别你感兴趣的密钥。</li></ul><h4 id="导出-GPG-公钥"><a href="#导出-GPG-公钥" class="headerlink" title="导出 GPG 公钥"></a>导出 GPG 公钥</h4><p> 通过<strong>密钥</strong> ID 导出公钥以供其他人验证签名:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --armor --export <your-key-id> > pubkey.asc</span><br></pre></td></tr></table></figure><h3 id="签名和验证-OSTree-提交"><a href="#签名和验证-OSTree-提交" class="headerlink" title="签名和验证 OSTree 提交"></a>签名和验证 OSTree 提交</h3><h4 id="初始化-OSTree-仓库"><a href="#初始化-OSTree-仓库" class="headerlink" title="初始化 OSTree 仓库"></a>初始化 OSTree 仓库</h4><p> 如果尚未初始化 OSTree 仓库,可以使用以下命令:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ostree init --repo=repo --mode=archive-z2</span><br></pre></td></tr></table></figure><blockquote><p>注:在使用 OSTree 时,可以通过环境变量 OSTREE_REPO 指定仓库的地址。这个环境变量允许你在命令行中不必每次都指定 –repo 参数,而是通过设置环境变量来定义仓库的位置。<br>export OSTREE_REPO=/path/to/your/repo</p></blockquote><h4 id="签名-OSTree-提交"><a href="#签名-OSTree-提交" class="headerlink" title="签名 OSTree 提交"></a>签名 OSTree 提交</h4><p>创建一个提交并进行签名:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ostree commit --repo=repo --branch=example-branch --gpg-sign=<your-key-id> --subject="Example Commit" --body="This is an example commit"</span><br></pre></td></tr></table></figure><p>其中 <code><your-key-id></code> 是你的 GPG 密钥 ID。</p><h4 id="验证-OSTree-提交"><a href="#验证-OSTree-提交" class="headerlink" title="验证 OSTree 提交"></a>验证 OSTree 提交</h4><p>在另一个系统上验证签名,需要首先导入公钥:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --import pubkey.asc</span><br></pre></td></tr></table></figure><p>然后验证签名:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ostree pull --repo=repo --gpg-verify=true <remote-repo> <branch></span><br></pre></td></tr></table></figure><h3 id="发布和部署"><a href="#发布和部署" class="headerlink" title="发布和部署"></a>发布和部署</h3><ol><li><strong>发布签名的 OSTree 提交</strong></li></ol><p>将签名的提交推送到远程仓库:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ostree --repo=repo remote add --gpg-import=pubkey.asc origin <remote-url></span><br><span class="line">ostree --repo=repo push --remote=origin <branch></span><br></pre></td></tr></table></figure><ol start="2"><li><strong>部署签名的 OSTree 提交</strong></li></ol><p>在客户端系统上,拉取并部署签名的提交:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ostree remote add --gpg-import=pubkey.asc origin <remote-url></span><br><span class="line">ostree pull origin <branch></span><br><span class="line">ostree admin deploy <branch></span><br></pre></td></tr></table></figure><h3 id="实践示例"><a href="#实践示例" class="headerlink" title="实践示例"></a>实践示例</h3><p>以下是一个完整的示例,从签名到验证和部署:</p><h4 id="服务器端(签名和发布)"><a href="#服务器端(签名和发布)" class="headerlink" title="服务器端(签名和发布)"></a>服务器端(签名和发布)</h4><h5 id="初始化仓库"><a href="#初始化仓库" class="headerlink" title="初始化仓库"></a>初始化仓库</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ostree init --repo=repo --mode=archive-z2</span><br></pre></td></tr></table></figure><h5 id="创建并签名提交"><a href="#创建并签名提交" class="headerlink" title="创建并签名提交"></a>创建并签名提交</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ostree commit --repo=repo --branch=example-branch --gpg-sign=<your-key-id> --subject="Initial Commit" --body="Initial commit with GPG signature"</span><br></pre></td></tr></table></figure><h5 id="推送提交"><a href="#推送提交" class="headerlink" title="推送提交"></a>推送提交</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ostree remote add --repo=repo --gpg-import=pubkey.asc origin <remote-url></span><br><span class="line">ostree --repo=repo push --remote=origin example-branch</span><br></pre></td></tr></table></figure><h4 id="客户端(验证和部署)"><a href="#客户端(验证和部署)" class="headerlink" title="客户端(验证和部署)"></a>客户端(验证和部署)</h4><h5 id="导入公钥"><a href="#导入公钥" class="headerlink" title="导入公钥"></a>导入公钥</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpg --import pubkey.asc</span><br></pre></td></tr></table></figure><h5 id="添加远程仓库并拉取提交"><a href="#添加远程仓库并拉取提交" class="headerlink" title="添加远程仓库并拉取提交"></a>添加远程仓库并拉取提交</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ostree remote add --gpg-import=pubkey.asc origin <remote-url></span><br><span class="line">ostree pull origin example-branch</span><br></pre></td></tr></table></figure><h5 id="部署提交"><a href="#部署提交" class="headerlink" title="部署提交"></a>部署提交</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ostree admin deploy example-branch</span><br></pre></td></tr></table></figure><p>通过以上步骤,你可以实现 OSTree 提交的 GPG 签名和验证,从而确保文件系统树的安全性和完整性。</p>]]></content>
<summary type="html"><p>OSTree 是一个用于版本化文件系统树的工具,可以将其视为 Git 的文件系统版本。OSTree 不仅支持文件系统的版本管理,还支持使用 GPG 对其提交进行签名,以确保数据的完整性和来源的可信性。下面介绍 GPG 签名的原理和如何在 OSTree 中使用它。</p></summary>
<category term="ostree" scheme="https://ssk-wh.github.io/categories/ostree/"/>
<category term="ostree" scheme="https://ssk-wh.github.io/tags/ostree/"/>
<category term="GPG" scheme="https://ssk-wh.github.io/tags/GPG/"/>
<category term="签名" scheme="https://ssk-wh.github.io/tags/%E7%AD%BE%E5%90%8D/"/>
</entry>
<entry>
<title>理解CPU的主频、倍频和外频</title>
<link href="https://ssk-wh.github.io/2024/07e7dec690.html"/>
<id>https://ssk-wh.github.io/2024/07e7dec690.html</id>
<published>2024-07-04T00:00:00.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<p>在计算机的世界里,CPU(中央处理器)作为计算机的大脑,其性能决定了整机的速度和效率。而CPU的主频、倍频和外频则是衡量其性能的重要参数。本文将为您深入浅出地介绍这三个概念,帮助您更好地理解它们之间的关系及其对CPU性能的影响。</p><span id="more"></span><h2 id="CPU的主频"><a href="#CPU的主频" class="headerlink" title="CPU的主频"></a>CPU的主频</h2><p>主频(Clock Speed)是指CPU的工作频率,通常以GHz(千兆赫兹)为单位。它表示CPU每秒钟能够执行的指令周期数。例如,一个主频为3.5GHz的CPU,每秒钟可以进行35亿个指令周期。</p><h3 id="为什么主频重要?"><a href="#为什么主频重要?" class="headerlink" title="为什么主频重要?"></a>为什么主频重要?</h3><ol><li><strong>执行速度</strong>:主频越高,CPU在单位时间内能够执行的指令就越多,处理速度也就越快。</li><li><strong>响应时间</strong>:高主频的CPU可以更快速地响应系统和应用程序的需求,提高计算机的整体性能。</li></ol><h2 id="CPU的外频"><a href="#CPU的外频" class="headerlink" title="CPU的外频"></a>CPU的外频</h2><p>外频(External Clock)是指主板与CPU之间的基准时钟频率。它通常由主板上的时钟发生器提供。外频的单位同样是Hz(赫兹)。</p><h3 id="外频的作用"><a href="#外频的作用" class="headerlink" title="外频的作用"></a>外频的作用</h3><p>外频是决定CPU最终工作频率(即主频)的基础参数。外频与倍频相结合,确定了CPU的主频。例如,如果外频为100MHz,而倍频为35,那么CPU的主频就是100MHz × 35 = 3500MHz(即3.5GHz)。</p><h2 id="CPU的倍频"><a href="#CPU的倍频" class="headerlink" title="CPU的倍频"></a>CPU的倍频</h2><p>倍频(Multiplier)是一个无量纲的系数,它将外频放大,从而得到CPU的主频。倍频由CPU内部的倍频器决定,一般由CPU的设计厂商设定。</p><h3 id="倍频的特点"><a href="#倍频的特点" class="headerlink" title="倍频的特点"></a>倍频的特点</h3><ol><li><strong>可调节性</strong>:许多高端CPU支持倍频调节,允许用户在一定范围内调整倍频,从而超频或降频,以满足不同的性能需求和节能要求。</li><li><strong>灵活性</strong>:通过调整倍频,用户可以在不改变外频的情况下,灵活调整CPU的工作频率,提供更好的系统稳定性和性能优化。</li></ol><h2 id="主频、倍频与外频的关系"><a href="#主频、倍频与外频的关系" class="headerlink" title="主频、倍频与外频的关系"></a>主频、倍频与外频的关系</h2><p>简单来说,CPU的主频由外频和倍频共同决定,公式为: 主频=外频×倍频\text{主频} = \text{外频} \times \text{倍频}</p><h3 id="举例说明"><a href="#举例说明" class="headerlink" title="举例说明"></a>举例说明</h3><p>假设一款CPU的外频为100MHz,倍频为35,那么它的主频就是:<br><code>主频=100MHz×35=3500MHz=3.5GHz</code></p><p>通过调整外频和倍频的组合,可以实现对CPU主频的精确控制。例如,通过将外频提升到105MHz,倍频保持35不变,新的主频就是:<br><code>主频=105MHz×35=3675MHz=3.675GHz</code></p><h2 id="如何调节外频和倍频"><a href="#如何调节外频和倍频" class="headerlink" title="如何调节外频和倍频"></a>如何调节外频和倍频</h2><p>现代计算机主板和CPU通常允许用户在BIOS/UEFI设置中调整外频和倍频。这一过程称为“超频”(Overclocking)或“降频”(Underclocking)。不过,超频可能会带来系统不稳定和过热的问题,需要谨慎操作并确保良好的散热条件。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>理解CPU的主频、倍频和外频是提升计算机性能的重要一步。主频是CPU性能的直接表现,而外频和倍频则共同决定了这一表现。通过合理调整这两个参数,用户可以在一定范围内优化CPU的工作频率,从而满足不同的计算需求。<br>希望通过本文,您对CPU的主频、倍频和外频有了更清晰的认识。如果有任何疑问或需要进一步的探讨,欢迎在评论区留言,我会尽力解答您的问题。</p>]]></content>
<summary type="html"><p>在计算机的世界里,CPU(中央处理器)作为计算机的大脑,其性能决定了整机的速度和效率。而CPU的主频、倍频和外频则是衡量其性能的重要参数。本文将为您深入浅出地介绍这三个概念,帮助您更好地理解它们之间的关系及其对CPU性能的影响。</p></summary>
<category term="计算机" scheme="https://ssk-wh.github.io/categories/%E8%AE%A1%E7%AE%97%E6%9C%BA/"/>
<category term="CPU" scheme="https://ssk-wh.github.io/tags/CPU/"/>
</entry>
<entry>
<title>makeself 的使用</title>
<link href="https://ssk-wh.github.io/2024/0717fd6bfe.html"/>
<id>https://ssk-wh.github.io/2024/0717fd6bfe.html</id>
<published>2024-07-02T00:00:00.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<p>在 Linux 中,创建自解压安装脚本是一种常见的方法,可以将多个文件打包成一个可执行文件,以便于分发和安装。这种方法通常使用 <code>shar</code>(Shell Archive)或者 <code>makeself</code> 工具来实现。</p><span id="more"></span><p>以下是使用 <code>makeself</code> 创建自解压安装脚本的步骤。</p><h3 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h3><p>在大多数 Linux 发行版中,<code>makeself</code> 工具可以通过包管理器安装。以下是一些常见的安装方法:</p><ul><li><p><strong>Ubuntu/Debian:</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get install makeself</span><br></pre></td></tr></table></figure></li><li><p><strong>Fedora:</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo dnf install makeself</span><br></pre></td></tr></table></figure></li><li><p><strong>Arch Linux:</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo pacman -S makeself</span><br></pre></td></tr></table></figure></li></ul><h3 id="准备文件"><a href="#准备文件" class="headerlink" title="准备文件"></a>准备文件</h3><p>假设你有一组文件或一个目录需要打包。在这个例子中,我们将使用一个目录 <code>my_app</code>。</p><h3 id="编写安装脚本"><a href="#编写安装脚本" class="headerlink" title="编写安装脚本"></a>编写安装脚本</h3><p>编写一个名为 <code>install.sh</code> 的脚本,定义如何安装和配置你的应用程序。以下是一个简单的例子:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#!/bin/bash</span><br><span class="line">echo "正在安装 My App..."</span><br><span class="line"># 执行安装步骤,例如复制文件、设置权限等</span><br><span class="line">cp -r * /opt/my_app/</span><br><span class="line">echo "安装完成!"</span><br></pre></td></tr></table></figure><p>确保你的安装脚本是可执行的:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">chmod +x install.sh</span><br></pre></td></tr></table></figure><h3 id="使用makeself创建自解压安装包"><a href="#使用makeself创建自解压安装包" class="headerlink" title="使用makeself创建自解压安装包"></a>使用makeself创建自解压安装包</h3><p>使用 <code>makeself</code> 工具创建自解压安装包。以下是一个示例命令:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">makeself my_app my_app_installer.run "My App Installer" ./install.sh</span><br></pre></td></tr></table></figure><ul><li><code>my_app</code> 是包含你所有文件的目录。</li><li><code>my_app_installer.run</code> 是生成的自解压安装包的名称。</li><li><code>"My App Installer"</code> 是安装包的描述。</li><li><code>./install.sh</code> 是安装脚本的路径。</li></ul><h3 id="完整示例"><a href="#完整示例" class="headerlink" title="完整示例"></a>完整示例</h3><p>假设你有以下目录结构:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">my_app/</span><br><span class="line">├── install.sh</span><br><span class="line">├── bin/</span><br><span class="line">│ └── my_app_executable</span><br><span class="line">└── lib/</span><br><span class="line"> └── my_app_library.so</span><br></pre></td></tr></table></figure><ol><li><p>创建 <code>install.sh</code>:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">#!/bin/bash</span><br><span class="line">echo "正在安装 My App..."</span><br><span class="line"># 创建目标目录</span><br><span class="line">mkdir -p /opt/my_app</span><br><span class="line"># 复制文件</span><br><span class="line">cp -r * /opt/my_app/</span><br><span class="line">echo "安装完成!"</span><br></pre></td></tr></table></figure></li><li><p>确保 <code>install.sh</code> 是可执行的:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">chmod +x my_app/install.sh</span><br></pre></td></tr></table></figure></li><li><p>使用 <code>makeself</code> 创建自解压安装包:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">makeself my_app my_app_installer.run "My App Installer" ./install.sh</span><br></pre></td></tr></table></figure></li></ol><h3 id="运行自解压安装包"><a href="#运行自解压安装包" class="headerlink" title="运行自解压安装包"></a>运行自解压安装包</h3><p>用户可以通过执行生成的 <code>.run</code> 文件来安装应用程序:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./my_app_installer.run</span><br></pre></td></tr></table></figure><p>这会解压文件并运行 <code>install.sh</code> 脚本,完成应用程序的安装。<br />通过这些步骤,你可以轻松创建一个自解压安装脚本,方便分发和安装你的 Linux 应用程序。</p><h3 id="解压为原始文件"><a href="#解压为原始文件" class="headerlink" title="解压为原始文件"></a>解压为原始文件</h3><p>通过 makeself 制作的自解压安装包同样支持解压为原始文件,您可以在修改后重新打包为 .run 格式的自解压安装包。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./my_app_installer.run --noexec --targegt my_app_dir</span><br></pre></td></tr></table></figure><h3 id="查看压缩包内容"><a href="#查看压缩包内容" class="headerlink" title="查看压缩包内容"></a>查看压缩包内容</h3><p>压缩后的可执行文件可以通过 –list 参数查看文件内容</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./my_app_installer.run --list</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><p>在 Linux 中,创建自解压安装脚本是一种常见的方法,可以将多个文件打包成一个可执行文件,以便于分发和安装。这种方法通常使用 <code>shar</code>(Shell Archive)或者 <code>makeself</code> 工具来实现。</p></summary>
<category term="Linux" scheme="https://ssk-wh.github.io/categories/Linux/"/>
<category term="Linux" scheme="https://ssk-wh.github.io/tags/Linux/"/>
<category term="makeself" scheme="https://ssk-wh.github.io/tags/makeself/"/>
</entry>
<entry>
<title>宏内核与微内核:深入理解计算机操作系统的核心</title>
<link href="https://ssk-wh.github.io/2024/072650bdc9.html"/>
<id>https://ssk-wh.github.io/2024/072650bdc9.html</id>
<published>2024-07-02T00:00:00.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<p>在计算机操作系统的设计中,内核(Kernel)是一个至关重要的组成部分。内核作为系统软件的核心,负责管理系统资源,协调硬件和软件之间的交互。根据设计思想的不同,内核可以分为两种主要类型:宏内核(Monolithic Kernel)和微内核(Microkernel)。本文将深入探讨这两种内核的区别、各自的优缺点以及一些实际的例子。</p><span id="more"></span><h4 id="什么是宏内核?"><a href="#什么是宏内核?" class="headerlink" title="什么是宏内核?"></a>什么是宏内核?</h4><p>宏内核是一种传统的操作系统内核设计,其特点是将操作系统的大部分功能都集成在一个大内核中。这个大内核直接运行在硬件之上,并且具有完整的系统功能,包括进程管理、内存管理、文件系统、设备驱动等。<br /><strong>优点:</strong></p><ol><li><strong>性能高:</strong> 由于大部分服务都在内核空间内运行,系统调用和进程间通信的开销较低。</li><li><strong>实现简单:</strong> 开发者可以直接在内核空间内实现大部分功能,减少了用户空间与内核空间之间的切换。</li></ol><p><strong>缺点:</strong></p><ol><li><strong>稳定性差:</strong> 由于所有功能都在内核空间运行,一旦某个部分出现错误,可能导致整个系统崩溃。</li><li><strong>维护复杂:</strong> 宏内核代码量大,任何修改都需要对整个内核进行重新编译,测试和调试难度较大。</li></ol><p><strong>实际例子:</strong></p><ul><li><strong>Linux内核:</strong> Linux是最典型的宏内核操作系统,它将大部分功能集成在内核中。</li><li><strong>Windows NT内核:</strong> 尽管微软声称Windows NT内核是微内核架构,但实际上它更接近于宏内核设计,因为许多服务都在内核模式下运行。</li></ul><h4 id="什么是微内核?"><a href="#什么是微内核?" class="headerlink" title="什么是微内核?"></a>什么是微内核?</h4><p>微内核则采用了截然不同的设计思路。它将操作系统的核心功能精简到最小,仅保留最基础的部分,如进程间通信、基本的内存管理和简单的硬件驱动。其他系统服务则运行在用户空间,以减少内核的复杂度。<br /><strong>优点:</strong></p><ol><li><strong>稳定性高:</strong> 由于内核中只包含最基本的功能,即使某个用户空间服务崩溃,系统整体仍能保持稳定。</li><li><strong>安全性好:</strong> 用户空间服务与内核之间的隔离,减少了内核受到攻击的可能性。</li></ol><p><strong>缺点:</strong></p><ol><li><strong>性能低:</strong> 由于系统服务运行在用户空间,频繁的系统调用和进程间通信会带来较大的性能开销。</li><li><strong>实现复杂:</strong> 需要设计高效的通信机制,以保证用户空间服务之间的交互顺畅。</li></ol><p><strong>实际例子:</strong></p><ul><li><strong>MINIX:</strong> MINIX是一个典型的微内核操作系统,因其简洁的设计而被广泛用于教学。</li><li><strong>QNX:</strong> QNX是一种商用实时操作系统,采用微内核设计,广泛应用于嵌入式系统中。</li></ul><h4 id="宏内核与微内核的比较"><a href="#宏内核与微内核的比较" class="headerlink" title="宏内核与微内核的比较"></a>宏内核与微内核的比较</h4><table><thead><tr><th>特点</th><th>宏内核</th><th>微内核</th></tr></thead><tbody><tr><td>结构</td><td>所有功能集成在内核中</td><td>只保留核心功能,其他服务运行在用户空间</td></tr><tr><td>性能</td><td>高</td><td>较低</td></tr><tr><td>稳定性</td><td>稳定性差</td><td>稳定性高</td></tr><tr><td>安全性</td><td>安全性一般</td><td>安全性好</td></tr><tr><td>维护和扩展</td><td>维护复杂,扩展困难</td><td>维护较简单,扩展性好</td></tr></tbody></table><h4 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h4><p>宏内核和微内核各有优缺点,选择哪种内核架构取决于具体的应用场景和需求。对于需要高性能和快速响应的系统,如桌面操作系统和服务器操作系统,宏内核通常是首选。而对于需要高稳定性和安全性的系统,如嵌入式系统和实时操作系统,微内核则更具优势。通过理解这两种内核架构的特点和差异,开发者可以更好地设计和优化操作系统,以满足不同的应用需求。<br />希望这篇文章能帮助你更好地理解宏内核和微内核。如果你有任何疑问或需要进一步探讨,欢迎在评论区留言。</p>]]></content>
<summary type="html"><p>在计算机操作系统的设计中,内核(Kernel)是一个至关重要的组成部分。内核作为系统软件的核心,负责管理系统资源,协调硬件和软件之间的交互。根据设计思想的不同,内核可以分为两种主要类型:宏内核(Monolithic Kernel)和微内核(Microkernel)。本文将深入探讨这两种内核的区别、各自的优缺点以及一些实际的例子。</p></summary>
<category term="Linux" scheme="https://ssk-wh.github.io/categories/Linux/"/>
<category term="Linux" scheme="https://ssk-wh.github.io/tags/Linux/"/>
<category term="内核" scheme="https://ssk-wh.github.io/tags/%E5%86%85%E6%A0%B8/"/>
</entry>
<entry>
<title>段页式内存管理</title>
<link href="https://ssk-wh.github.io/2024/07eadf9fd1.html"/>
<id>https://ssk-wh.github.io/2024/07eadf9fd1.html</id>
<published>2024-07-02T00:00:00.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<p>段页式内存管理是一种结合了分段和分页两种内存管理技术的机制,它旨在充分利用这两者的优点,减少它们各自的缺点。这种混合策略广泛应用于现代操作系统中,以实现灵活高效的内存管理。</p><span id="more"></span><h2 id="段页式内存管理的基本概念"><a href="#段页式内存管理的基本概念" class="headerlink" title="段页式内存管理的基本概念"></a>段页式内存管理的基本概念</h2><h3 id="段(Segment)"><a href="#段(Segment)" class="headerlink" title="段(Segment)"></a>段(Segment)</h3><ul><li><strong>分段</strong>:内存被划分为不同的段,每个段代表一个逻辑单位,比如代码段、数据段、堆栈段等。每个段有一个段基址和段长度。</li><li><strong>段表(Segment Table)</strong>:操作系统为每个进程维护一个段表,段表条目包含段基址和段长度,用于将逻辑地址转换为段内的偏移地址。</li></ul><h3 id="页(Page)"><a href="#页(Page)" class="headerlink" title="页(Page)"></a>页(Page)</h3><ul><li><strong>分页</strong>:每个段进一步划分为固定大小的页,内存被划分成大小相等的页框(Page Frame)。</li><li><strong>页表(Page Table)</strong>:每个段对应一个页表,页表条目包含页框号,用于将段内的偏移地址转换为物理地址。</li></ul><h2 id="地址转换过程"><a href="#地址转换过程" class="headerlink" title="地址转换过程"></a>地址转换过程</h2><p>段页式内存管理将逻辑地址转换为物理地址的过程涉及两个步骤:</p><ol><li><strong>段选择</strong>:首先根据段号查找段表,获取段基址和段长度。如果逻辑地址中的偏移量超过了段长度,触发段错误(Segment Fault)。</li><li><strong>页选择</strong>:其次在段内进行分页,根据段内的页号查找页表,获取对应的页框号,将页内偏移量加到页框基址上,形成最终的物理地址。</li></ol><p>具体步骤如下:</p><ul><li><strong>逻辑地址(段号:段内偏移)</strong>:逻辑地址由段号(Segment Number)和段内偏移(Offset within Segment)组成。</li><li><strong>段表查找</strong>:使用段号在段表中查找,获取段基址和段长度。</li><li><strong>页表查找</strong>:将段内偏移分为页号(Page Number)和页内偏移(Offset within Page),使用页号在页表中查找,获取页框号。</li><li><strong>物理地址计算</strong>:将页框号和页内偏移组合,形成最终的物理地址。</li></ul><h2 id="优点"><a href="#优点" class="headerlink" title="优点"></a>优点</h2><ul><li><strong>灵活性</strong>:结合了分段和分页的优点,既支持逻辑分段,又能够有效利用内存碎片。</li><li><strong>保护和共享</strong>:通过段表和页表的多级映射,可以实现内存保护和进程间的内存共享。</li><li><strong>减少外部碎片</strong>:分页的引入减少了分段带来的外部碎片问题。</li></ul><h2 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h2><p>假设一个逻辑地址由段号、页号和页内偏移组成,如下所示:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">逻辑地址格式: 段号(S) 页号(P) 页内偏移(D)</span><br></pre></td></tr></table></figure><p>具体转换过程如下:</p><ol><li>使用段号S在段表中查找,得到段基址和段长度。</li><li>将逻辑地址中的页号P和页内偏移D分离,计算段内偏移。</li><li>使用页号P在对应段的页表中查找,得到页框号。</li><li>将页框号和页内偏移D组合,形成物理地址。</li></ol><h3 id="示例数据"><a href="#示例数据" class="headerlink" title="示例数据"></a>示例数据</h3><p>假设段表和页表如下:<br />段表:</p><table><thead><tr><th>段号</th><th>段基址</th><th>段长度</th></tr></thead><tbody><tr><td>0</td><td>1000</td><td>400</td></tr><tr><td>1</td><td>2000</td><td>800</td></tr></tbody></table><p>页表(段0):</p><table><thead><tr><th>页号</th><th>页框号</th></tr></thead><tbody><tr><td>0</td><td>5</td></tr><tr><td>1</td><td>8</td></tr></tbody></table><p>页表(段1):</p><table><thead><tr><th>页号</th><th>页框号</th></tr></thead><tbody><tr><td>0</td><td>7</td></tr><tr><td>1</td><td>10</td></tr><tr><td>2</td><td>3</td></tr></tbody></table><p>假设逻辑地址为:(1, 1, 50) ,表示段1,页1,页内偏移50:</p><ol><li>在段表中查找段1,得到段基址2000。</li><li>使用页号1在段1的页表中查找,得到页框号10。</li><li>将页框号10转换为物理地址,假设每页大小为100:<ul><li>物理地址 = 页框号 * 页大小 + 页内偏移</li><li>物理地址 = 10 * 100 + 50 = 1050</li></ul></li></ol><p>最终物理地址为1050。</p><h2 id="段页式内存管理的应用"><a href="#段页式内存管理的应用" class="headerlink" title="段页式内存管理的应用"></a>段页式内存管理的应用</h2><p>段页式内存管理广泛应用于现代操作系统,如Windows和Unix/Linux,这些系统通过段页式内存管理实现内存保护、多任务处理和虚拟内存管理。通过段页式管理,操作系统可以灵活地分配和管理内存,提高系统的可靠性和效率。</p>]]></content>
<summary type="html"><p>段页式内存管理是一种结合了分段和分页两种内存管理技术的机制,它旨在充分利用这两者的优点,减少它们各自的缺点。这种混合策略广泛应用于现代操作系统中,以实现灵活高效的内存管理。</p></summary>
<category term="Linux" scheme="https://ssk-wh.github.io/categories/Linux/"/>
<category term="Linux" scheme="https://ssk-wh.github.io/tags/Linux/"/>
<category term="内存管理" scheme="https://ssk-wh.github.io/tags/%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/"/>
</entry>
<entry>
<title>Greenboot服务介绍</title>
<link href="https://ssk-wh.github.io/2024/06697cec4e.html"/>
<id>https://ssk-wh.github.io/2024/06697cec4e.html</id>
<published>2024-06-18T20:19:08.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<h2 id="概况"><a href="#概况" class="headerlink" title="概况"></a>概况</h2><p>Fedora 中提供了 <a class="link" href="https://github.com/fedora-iot/greenboot/tree/main" >greenboot<i class="fas fa-external-link-alt"></i></a> 服务,这是一款基于 rpm-ostree 的系统上 systemd 的通用运行状况检查框架。</p><span id="more"></span><p>Greenboot 由两部分组成:</p><ul><li>greenboot :检查提供的脚本,如果这些检查未通过则重新启动,如果重新启动未能解决问题则回滚到之前的部署。</li><li>greenboot-default-health-checks ,由 Greenboot 维护者提供的一系列可选和策划的健康检查。</li></ul><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><p>为了在 Fedora Silverblue、Fedora IoT 或 Fedora CoreOS 上获得完整的 Greenboot ,请使用如下命令安装</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">rpm-ostree install greenboot greenboot-default-health-checks</span><br><span class="line">systemctl reboot</span><br></pre></td></tr></table></figure><h2 id="名词介绍"><a href="#名词介绍" class="headerlink" title="名词介绍"></a>名词介绍</h2><ul><li>MOTD:指/run/motd.d/boot-status,存放 greenboot 运行阶段的一些日志信息。</li></ul><h2 id="脚本目录"><a href="#脚本目录" class="headerlink" title="脚本目录"></a>脚本目录</h2><p>目录结构</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">/etc</span><br><span class="line">└── greenboot</span><br><span class="line"> ├── check</span><br><span class="line"> │ ├── required.d</span><br><span class="line"> │ └── wanted.d</span><br><span class="line"> ├── green.d</span><br><span class="line"> └── red.d</span><br></pre></td></tr></table></figure><ul><li>/etc/greenboot/check/required.d:此目录中的运行状态检查脚本不得失败。如果此文件夹中的任何脚本退出时出现错误代码,则启动将被声明为失败。错误消息将出现在 MOTD 和 journalctl -u greenboot-healthcheck.service 中。</li><li>/etc/greenboot/check/wanted.d:此目录中的运行状态检查脚本可能失败,。此文件夹中的脚本可以退出并显示错误代码,并且启动不会被声明为失败。错误消息将出现在 MOTD 和 journalctl -u greenboot-healthcheck.service -b 中。</li><li>/etc/greenboot/green.d:此目录中的交叉脚本将在启动成功(绿色)后运行。</li><li>/etc/greenboot/red.d:此目录中的交叉脚本将在启动失败(红色)后运行。</li></ul><p>除非您的发行版中默认启用 greenboot,否则请通过运行 <code>systemctl enable greenboot-task-runner greenboot-healthcheck greenboot-status greenboot-loading-message greenboot-grub2-set-counter greenboot-grub2-set-success greenboot-rpm-ostree-grub2-check-fallback redboot-auto-reboot redboot-task-runner</code> 来启用它。它将在下次启动过程中自动启动并运行检查。</p><p>之后当您 ssh 进入计算机时,将显示启动状态消息:<br><code>Boot Status is GREEN - Health Check SUCCESS</code><br><code>Boot Status is RED - Health Check FAILURE!</code></p><h2 id="greenboot-default-health-checks"><a href="#greenboot-default-health-checks" class="headerlink" title="greenboot-default-health-checks"></a>greenboot-default-health-checks</h2><p>这些运行状况检查可在 rpm-ostree 系统中的只读目录 /usr/lib/greenboot/check 中找到。</p><ul><li>检查存储库 URL 是否仍可通过 DNS 解析:此脚本位于 /usr/lib/greenboot/check/required.d/01_repository_dns_check.sh 下,并确保对存储库 URL 的 DNS 查询仍然可用。</li><li>检查更新平台是否仍然可访问:此脚本位于 /usr/lib/greenboot/check/wanted.d/01_update_platform_check.sh 下,并尝试连接并从 /etc/ostree/remotes.d 中定义的更新平台获取 2XX 或 3XX HTTP 代码。</li><li>检查当前启动是否由硬件看门狗触发:此脚本位于 /usr/lib/greenboot/check/required.d/02_watchdog.sh 下,用于检查当前启动是否由看门狗触发。如果是,但在一定的宽限期(默认为 24 小时,可通过 /etc/greenboot/greenboot.conf 中的 GREENBOOT_WATCHDOG_GRACE_PERIOD=number_of_hours 配置)后重新启动,Greenboot 不会将当前启动标记为红色,并且不会回滚到之前的部署。如果在宽限期内发生,此时当前启动将被标记为红色,但 Greenboot 不会回滚到之前的部署。默认情况下启用,但可以通过将 /etc/greenboot/greenboot.conf 中的 GREENBOOT_WATCHDOG_CHECK_ENABLED 修改为 false 来禁用它。</li></ul><h2 id="使用-systemd-服务进行健康检查"><a href="#使用-systemd-服务进行健康检查" class="headerlink" title="使用 systemd 服务进行健康检查"></a>使用 systemd 服务进行健康检查</h2><p>总体启动成功是根据 boot-complete.target 来衡量的。</p><h3 id="Required-Checks"><a href="#Required-Checks" class="headerlink" title="Required Checks"></a>Required Checks</h3><p>创建一个不能失败的一次性健康检查服务单元,例如 /etc/systemd/system/required-check.service 。确保它在失败时调用 redboot.target ( OnFailure=redboot.target )。运行 <code>systemctl enable required-check </code>来启用它。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">[Unit]</span><br><span class="line">Description=Custom Required Health Check</span><br><span class="line">Before=boot-complete.target</span><br><span class="line">OnFailure=redboot.target</span><br><span class="line">OnFailureJobMode=fail</span><br><span class="line"></span><br><span class="line">[Service]</span><br><span class="line">Type=oneshot</span><br><span class="line">ExecStart=/usr/libexec/mytestsuite/required-check</span><br><span class="line"></span><br><span class="line">[Install]</span><br><span class="line">RequiredBy=boot-complete.target</span><br><span class="line">WantedBy=multi-user.target</span><br></pre></td></tr></table></figure><h3 id="Wanted-Checks"><a href="#Wanted-Checks" class="headerlink" title="Wanted Checks"></a>Wanted Checks</h3><p>创建一个可能会失败的一次性健康检查服务单元,例如 /etc/systemd/system/wanted-check.service 。运行 <code>systemctl enable wanted-check</code> 来启用它。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">[Unit]</span><br><span class="line">Description=Custom Wanted Health Check</span><br><span class="line">Before=boot-complete.target</span><br><span class="line"></span><br><span class="line">[Service]</span><br><span class="line">Type=oneshot</span><br><span class="line">ExecStart=/usr/libexec/mytestsuite/wanted-check</span><br><span class="line"></span><br><span class="line">[Install]</span><br><span class="line">WantedBy=boot-complete.target</span><br><span class="line">WantedBy=multi-user.target</span><br></pre></td></tr></table></figure><h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h2><p>目前,可以通过环境变量自定义以下参数。这些环境变量也可以在配置文件 /etc/greenboot/greenboot.conf 中描述:</p><ul><li>GREENBOOT_MAX_BOOT_ATTEMPTS:在声明部署有问题并回滚到上一个部署之前尝试启动的最大次数,默认为3。</li><li>GREENBOOT_WATCHDOG_CHECK_ENABLED:启用/禁用检查当前启动是否已由硬件看门狗健康检查触发。有关健康检查的更多信息包含在子包 greenboot-default-health-checks 部分中。</li><li>GREENBOOT_WATCHDOG_GRACE_PERIOD:升级后我们认为新部署导致重新启动的小时数。</li></ul><h2 id="流程"><a href="#流程" class="headerlink" title="流程"></a>流程</h2><ul><li>greenboot-rpm-ostree-grub2-check-fallback.service 在 greenboot-healthcheck.service 之前运行,并检查 GRUB2 环境变量 boot_counter 是否为 -1。<ul><li>如果为 -1,则意味着系统处于回退部署中,并将执行 <code>rpm-ostree rollback </code>返回到之前的工作部署。</li><li>如果 boot_counter 不为-1,则此步骤不执行任何操作。</li></ul></li><li>greenboot-healthcheck.service 在 systemd 的 boot-complete.target 之前运行。它启动 /usr/libexec/greenboot/greenboot check ,它运行 required.d 和 wanted.d 脚本。<ul><li>如果 required.d 文件夹中的任何脚本失败,则调用 redboot.target 。<ul><li>它触发 redboot-task-runner.service ,从而启动 /usr/libexec/greenboot/greenboot red 。这将运行 red.d 文件夹中的脚本。</li><li>经过上述操作后:<ul><li>greenboot-status.service 运行,创建 MOTD 指定哪些脚本失败。</li><li>redboot-auto-reboot.service 已运行。它执行一系列检查以确定是否需要手动干预。如果没有,它将重新启动系统。</li></ul></li></ul></li><li>如果 required.d 文件夹中的所有脚本都成功:<ul><li>已达到 boot-complete.target </li><li>greenboot-grub2-set-success.service 已运行。它取消设置 boot_counter GRUB 环境变量并将 boot_success GRUB 环境变量设置为 1。</li><li>greenboot-task-runner.service 启动<code> /usr/libexec/greenboot/greenboot green</code> ,它运行 green.d 文件夹中的脚本,这些脚本将在成功更新后运行。</li><li>greenboot-status.service 运行,创建 MOTD 并显示成功消息。</li></ul></li></ul></li></ul><h2 id="Services-一览"><a href="#Services-一览" class="headerlink" title="Services 一览"></a>Services 一览</h2><table><thead><tr><th><strong>服务</strong></th><th><strong>作用</strong></th><th><strong>其他</strong></th></tr></thead><tbody><tr><td>greenboot-grub2-set-counter.service</td><td>greenboot-grub2-set-counter:<br>grub2-editenv - set boot_counter=”$max_boot_attempts” <br>grub2-editenv - set boot_success=0<br>通过命令参数或配置文件中获取最大重启次数,未指定则默认为3次</td><td>配置文件:<br>/etc/greenboot/greenboot.conf<br>配置项:<br>GREENBOOT_MAX_BOOT_ATTEMPTS<br>配置文件中允许通过DISABLED_HEALTHCHECKS禁用某些检查项</td></tr><tr><td>greenboot-grub2-set-success.service</td><td>grub2-editenv - set boot_success=1<br>grub2-editenv - unset boot_counter<br></td><td>After=boot-complete.target<br>在系统启动完成后运行</td></tr><tr><td>greenboot-healthcheck.service</td><td>/usr/libexec/greenboot/greenboot check<br>执行/usr/lib/greenboot/check和/etc/greenboot/check目录中required.d和wanted.d的检查脚本,如果required.d中的脚本运行失败,将导致greenboot进程退出值为1(异常退出)。</td><td>wanted.d中脚本失败无影响OnFailure=redboot.target<br>失败后到达redboot.target,从而启动redboot-task-runner.service</td></tr><tr><td>greenboot-loading-message.service</td><td>/usr/libexec/greenboot/greenboot-loading-message<br>只是向/run/motd.d/boot-status中输出一些信息</td><td>-</td></tr><tr><td>greenboot-rpm-ostree-grub2-check-fallback.service</td><td>/usr/libexec/greenboot/greenboot-rpm-ostree-grub2-check-fallback</td><td>rpm-ostree rollback<br>修改grub引导,第一项变为上一版本</td></tr><tr><td>greenboot-status.service</td><td>/usr/libexec/greenboot/greenboot-status<br>综合其他的日志信息,统一导入到/run/motd.d/boot-status</td><td>服务包括:<br>greenboot-healthcheck.service<br>greenboot-task-runner.service<br>redboot-task-runner.service <br>redboot-auto-reboot.service<br>greenboot-rpm-ostree-grub2-check-fallback.service</td></tr><tr><td>greenboot-task-runner.service</td><td>/usr/libexec/greenboot/greenboot green<br>执行/usr/lib/greenboot/green.d和/etc/greenboot/green.d中的脚本</td><td>After=boot-complete.target在系统启动完成后运行</td></tr><tr><td>redboot-auto-reboot.service</td><td>/usr/libexec/greenboot/redboot-auto-reboot<br>检查是否需要重启</td><td>根据grub2-editenv list中的信息以及/boot/loader/entries/中文件数量决定当前是否重启</td></tr><tr><td>redboot-task-runner.service</td><td>/usr/libexec/greenboot/greenboot red<br>执行/usr/lib/greenboot/red.d和/etc/greenboot/red.d中的脚本</td><td>RequiredBy=redboot.target<br>此服务在系统启动失败后运行</td></tr><tr><td>redboot.target</td><td>-</td><td>-</td></tr></tbody></table><h2 id="grub2-editenv"><a href="#grub2-editenv" class="headerlink" title="grub2-editenv"></a>grub2-editenv</h2><p>在设置 GRUB 环境的时候,用到了 grub2-editenv 命令,由 grub2-tools-minimal 提供。<br>查阅其 <a class="link" href="https://git.savannah.gnu.org/git/grub.git" >源码<i class="fas fa-external-link-alt"></i></a> 可以得知,这里只是把 set 的内容写入 /boot/grub2/grubenv 文件中进行保存。</p>]]></content>
<summary type="html"><h2 id="概况"><a href="#概况" class="headerlink" title="概况"></a>概况</h2><p>Fedora 中提供了 <a class="link" href="https://github.com/fedora-iot/greenboot/tree/main" >greenboot<i class="fas fa-external-link-alt"></i></a> 服务,这是一款基于 rpm-ostree 的系统上 systemd 的通用运行状况检查框架。</p></summary>
<category term="Linux" scheme="https://ssk-wh.github.io/categories/Linux/"/>
<category term="grub" scheme="https://ssk-wh.github.io/tags/grub/"/>
<category term="fedora" scheme="https://ssk-wh.github.io/tags/fedora/"/>
<category term="greenboot" scheme="https://ssk-wh.github.io/tags/greenboot/"/>
</entry>
<entry>
<title>systemd 目录重定向</title>
<link href="https://ssk-wh.github.io/2024/0650acf1b8.html"/>
<id>https://ssk-wh.github.io/2024/0650acf1b8.html</id>
<published>2024-06-17T17:13:08.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<p>在 <code>systemd</code> 中,可以使用 <code>BindPaths</code> 或 <code>BindReadOnlyPaths</code> 来重定向应用访问的目录。这些选项可以在 <code>.service</code> 单元文件中设置,用于将特定的目录绑定到不同的位置,从而实现目录的重定向。<code>systemd</code> 的这种机制,可以让我们更好的控制应用的行为,增强系统的安全性。</p><span id="more"></span><p><code>BindPaths</code> 是通过使用 Linux 内核的挂载命名空间(mount namespaces)和绑定挂载(bind mounts)来实现的。这些功能允许在特定进程的命名空间中修改文件系统的视图,而不会影响到其他进程或系统的全局视图。</p><p>挂载命名空间(mount namespaces)允许在特定进程的视图中隔离和重新配置挂载点。创建一个新的挂载命名空间后,进程可以在不影响其他进程的情况下修改其挂载点。<br>绑定挂载(bind mounts)是 Linux 文件系统功能的一部分,允许将一个目录或文件挂载到另一个目录。这使得同一目录或文件可以在多个位置同时出现。</p><p>以下是一个示例,展示如何配置一个 <code>systemd</code> 服务单元文件以重定向目录访问:</p><h2 id="服务单元"><a href="#服务单元" class="headerlink" title="服务单元"></a>服务单元</h2><p>假设你有一个名为 <code>example.service</code> 的服务单元文件,路径可能在 <code>/etc/systemd/system/example.service</code> 或 <code>/lib/systemd/system/example.service</code>。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">[Unit]</span><br><span class="line">Description=Example Service</span><br><span class="line"></span><br><span class="line">[Service]</span><br><span class="line">ExecStart=/usr/bin/example-binary</span><br><span class="line">BindPaths=/path/to/redirected:/path/to/original</span><br><span class="line"><span class="comment"># 或者使用只读绑定</span></span><br><span class="line"><span class="comment"># BindReadOnlyPaths=/path/to/redirected:/path/to/original</span></span><br><span class="line"></span><br><span class="line">[Install]</span><br><span class="line">WantedBy=multi-user.target</span><br></pre></td></tr></table></figure><p>在这个示例中,<code>/path/to/original</code> 是应用程序预期访问的目录,<code>/path/to/redirected</code> 是你希望应用程序实际访问的目录。</p><p>修改单元文件后,重新加载 <code>systemd</code> 配置以使更改生效,在 <code>example-binary</code> 中访问 <code>/path/to/original</code> 目录的内容时,此时均会重定向至 <code>/path/to/redirected</code> 目录。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"># 重新加载 systemd 配置</span><br><span class="line">sudo systemctl daemon-reload</span><br><span class="line"></span><br><span class="line"># 启动或重启服务</span><br><span class="line">sudo systemctl restart example.service</span><br></pre></td></tr></table></figure><h2 id="其他配置"><a href="#其他配置" class="headerlink" title="其他配置"></a>其他配置</h2><p>除了 BindPaths ,systemd还提供了其他的选项,使用者可以根据自己的需求选择合适的配置。</p><h3 id="BindPaths"><a href="#BindPaths" class="headerlink" title="BindPaths"></a>BindPaths</h3><ul><li><code>BindPaths=/target:/source</code></li><li>将 <code>/source</code> 目录绑定到 <code>/target</code> 目录。服务访问 <code>/source</code> 目录时实际上会访问 <code>/target</code> 目录。</li></ul><h3 id="BindReadOnlyPaths"><a href="#BindReadOnlyPaths" class="headerlink" title="BindReadOnlyPaths"></a>BindReadOnlyPaths</h3><ul><li><code>BindReadOnlyPaths=/target:/source</code></li><li>与 <code>BindPaths</code> 类似,但绑定的目录为只读模式。服务只能读取 <code>/target</code> 目录,无法进行写操作。</li></ul><h3 id="ReadWritePaths"><a href="#ReadWritePaths" class="headerlink" title="ReadWritePaths"></a>ReadWritePaths</h3><ul><li><code>ReadWritePaths=/path/to/dir</code></li><li>指定服务可以读写访问的目录。这些目录将被临时挂载为读写,即使根文件系统是只读的。</li></ul><h3 id="ReadOnlyPaths"><a href="#ReadOnlyPaths" class="headerlink" title="ReadOnlyPaths"></a>ReadOnlyPaths</h3><ul><li><code>ReadOnlyPaths=/path/to/dir</code></li><li>指定服务可以只读访问的目录。这些目录将被临时挂载为只读。</li></ul><h3 id="InaccessiblePaths"><a href="#InaccessiblePaths" class="headerlink" title="InaccessiblePaths"></a>InaccessiblePaths</h3><ul><li><code>InaccessiblePaths=/path/to/dir</code></li><li>指定服务无法访问的目录。访问这些目录将导致权限错误。</li></ul><h3 id="TemporaryFileSystem"><a href="#TemporaryFileSystem" class="headerlink" title="TemporaryFileSystem"></a>TemporaryFileSystem</h3><ul><li><code>TemporaryFileSystem=/path/to/dir:mode=755,size=10M</code></li><li>将指定目录挂载为临时文件系统(tmpfs),类似于 mount -t tmpfs。可以用来提供服务的临时存储空间。</li></ul><h3 id="PrivateTmp"><a href="#PrivateTmp" class="headerlink" title="PrivateTmp"></a>PrivateTmp</h3><ul><li><code>PrivateTmp=yes</code></li><li>启用服务的私有 /tmp 和 /var/tmp 目录,防止不同服务之间的临时文件相互影响。</li></ul><h3 id="ProtectSystem"><a href="#ProtectSystem" class="headerlink" title="ProtectSystem"></a>ProtectSystem</h3><ul><li><code>ProtectSystem=full</code></li><li>限制服务对系统文件和目录的写入访问。<ul><li>ProtectSystem=yes:将 /usr 和其他系统目录设置为只读。</li><li>ProtectSystem=full:将 /etc 也设置为只读。</li><li>ProtectSystem=strict:将整个系统设置为只读,除了通过 ReadWritePaths 显式允许的目录。</li></ul></li></ul><h3 id="ProtectHome"><a href="#ProtectHome" class="headerlink" title="ProtectHome"></a>ProtectHome</h3><ul><li><code>ProtectHome=yes</code></li><li>限制服务对用户主目录的访问。<ul><li>ProtectHome=yes:将用户主目录挂载为不可访问。</li><li>ProtectHome=read-only:将用户主目录挂载为只读。</li><li>ProtectHome=no:不限制用户主目录的访问。</li></ul></li></ul><h3 id="MountFlags"><a href="#MountFlags" class="headerlink" title="MountFlags"></a>MountFlags</h3><ul><li><code>MountFlags=slave</code></li><li>设置挂载点的标志。通常用来隔离服务的挂载命名空间。</li></ul><h2 id="备注"><a href="#备注" class="headerlink" title="备注"></a>备注</h2><p>部分环境中设置后并不能生效,报错内容如下:<br><img lazyload alt="image" data-src="/2024/0650acf1b8/1.png" ><br>你需要升级systemd和内核。</p><p>systemd在 233 版本之后对这一特性添加了支持。见<a class="link" href="https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#BindPaths=" >systemd-man-BindPaths<i class="fas fa-external-link-alt"></i></a>。<br>内核版本不确定,笔者在4.19的内核上测试失败但在6.1.32的内核验证成功。</p>]]></content>
<summary type="html"><p>在 <code>systemd</code> 中,可以使用 <code>BindPaths</code> 或 <code>BindReadOnlyPaths</code> 来重定向应用访问的目录。这些选项可以在 <code>.service</code> 单元文件中设置,用于将特定的目录绑定到不同的位置,从而实现目录的重定向。<code>systemd</code> 的这种机制,可以让我们更好的控制应用的行为,增强系统的安全性。</p></summary>
<category term="Linux" scheme="https://ssk-wh.github.io/categories/Linux/"/>
<category term="systemd" scheme="https://ssk-wh.github.io/tags/systemd/"/>
</entry>
<entry>
<title>Fedora 中 ostree 更新 grub 引导的流程</title>
<link href="https://ssk-wh.github.io/2024/0699dea904.html"/>
<id>https://ssk-wh.github.io/2024/0699dea904.html</id>
<published>2024-06-12T17:17:17.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<h2 id="grub-d-下的脚本"><a href="#grub-d-下的脚本" class="headerlink" title="grub.d 下的脚本"></a>grub.d 下的脚本</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">root@fedora:/etc/grub.d<span class="comment"># ls -al</span></span><br><span class="line">总计 108</span><br><span class="line">drwx------. 1 root root 392 6月11日 13:16 .</span><br><span class="line">drwxr-xr-x. 1 root root 4048 6月11日 13:22 ..</span><br><span class="line">-rwxr-xr-x. 1 root root 9346 6月11日 13:16 00_header</span><br><span class="line">-rwxr-xr-x. 1 root root 236 6月11日 13:16 01_users</span><br><span class="line">-rwxr-xr-x. 1 root root 835 6月11日 13:16 08_fallback_counting</span><br><span class="line">-rwxr-xr-x. 1 root root 19332 6月11日 13:16 10_linux</span><br><span class="line">-rwxr-xr-x. 1 root root 833 6月11日 13:16 10_reset_boot_success</span><br><span class="line">-rwxr-xr-x. 1 root root 892 6月11日 13:16 12_menu_auto_hide</span><br><span class="line">-rwxr-xr-x. 1 root root 410 6月11日 13:16 14_menu_show_once</span><br><span class="line">lrwxrwxrwx. 1 root root 38 6月11日 13:16 15_ostree -> /usr/libexec/libostree/grub2-15_ostree</span><br><span class="line">-rwxr-xr-x. 1 root root 13613 6月11日 13:16 20_linux_xen</span><br><span class="line">-rwxr-xr-x. 1 root root 2562 6月11日 13:16 20_ppc_terminfo</span><br><span class="line">-rwxr-xr-x. 1 root root 10869 6月11日 13:16 30_os-prober</span><br><span class="line">-rwxr-xr-x. 1 root root 1122 6月11日 13:16 30_uefi-firmware</span><br><span class="line">-rwxr-xr-x. 1 root root 725 6月11日 13:16 35_fwupd</span><br><span class="line">-rwxr-xr-x. 1 root root 218 6月11日 13:16 40_custom</span><br><span class="line">-rwxr-xr-x. 1 root root 219 6月11日 13:16 41_custom</span><br><span class="line">-rw-r--r--. 1 root root 483 6月11日 13:16 README</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="ostree-修改-grub-引导项"><a href="#ostree-修改-grub-引导项" class="headerlink" title="ostree 修改 grub 引导项"></a>ostree 修改 grub 引导项</h2><p>核心逻辑见最后一行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/usr/bin/sh</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># Copyright (C) 2014 Colin Walters <[email protected]></span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># This program is free software: you can redistribute it and/or modify</span></span><br><span class="line"><span class="comment"># it under the terms of the GNU Lesser General Public License as published</span></span><br><span class="line"><span class="comment"># by the Free Software Foundation; either version 2 of the licence or (at</span></span><br><span class="line"><span class="comment"># your option) any later version.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># This library is distributed in the hope that it will be useful,</span></span><br><span class="line"><span class="comment"># but WITHOUT ANY WARRANTY; without even the implied warranty of</span></span><br><span class="line"><span class="comment"># MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU</span></span><br><span class="line"><span class="comment"># Lesser General Public License for more details.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># You should have received a copy of the GNU Lesser General</span></span><br><span class="line"><span class="comment"># Public License along with this library. If not, see <https://www.gnu.org/licenses/>.</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Gracefully exit if ostree is not installed, or there's</span></span><br><span class="line"><span class="comment"># no system repository initialized.</span></span><br><span class="line"><span class="keyword">if</span> ! <span class="built_in">which</span> ostree >/dev/null 2>/dev/null; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">exit</span> 0</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"><span class="keyword">if</span> ! <span class="built_in">test</span> -d /ostree/repo; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">exit</span> 0</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Gracefully exit if we can not find the grub2 'default' configuration as it is</span></span><br><span class="line"><span class="comment"># the case on new installations with bootupd where it is not needed.</span></span><br><span class="line"><span class="keyword">if</span> ! <span class="built_in">test</span> -f /etc/default/grub; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">exit</span> 0</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Gracefully exit if the grub2 configuration has BLS enabled,</span></span><br><span class="line"><span class="comment"># and the installed version has support for the blscfg module.</span></span><br><span class="line"><span class="comment"># Since there is no need to create menu entries for that case.</span></span><br><span class="line"><span class="comment"># See: https://src.fedoraproject.org/rpms/grub2/c/7c2bab5e98d</span></span><br><span class="line">. /etc/default/grub</span><br><span class="line"><span class="keyword">if</span> <span class="built_in">test</span> -f /boot/grub2/.grub2-blscfg-supported && \</span><br><span class="line"> <span class="built_in">test</span> <span class="string">"<span class="variable">${GRUB_ENABLE_BLSCFG}</span>"</span> = <span class="string">"true"</span>; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">exit</span> 0</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Make sure we're in the right environment</span></span><br><span class="line"><span class="keyword">if</span> ! <span class="built_in">test</span> -n <span class="string">"<span class="variable">${GRUB_DEVICE}</span>"</span>; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"This script must be run as a child of grub2-mkconfig"</span> 1>&2</span><br><span class="line"> <span class="built_in">exit</span> 1</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">set</span> -e</span><br><span class="line"></span><br><span class="line"><span class="comment"># Pick up stuff from grub's helper that we want to inject into our</span></span><br><span class="line"><span class="comment"># generated bootloader configuration. Yes, this is pretty awful, but</span></span><br><span class="line"><span class="comment"># it's a lot better than reimplementing the config-generating bits of</span></span><br><span class="line"><span class="comment"># OSTree in shell script.</span></span><br><span class="line"></span><br><span class="line">. /usr/share/grub/grub-mkconfig_lib</span><br><span class="line"></span><br><span class="line">DEVICE=<span class="variable">${GRUB_DEVICE_BOOT:-<span class="variable">${GRUB_DEVICE}</span>}</span></span><br><span class="line"></span><br><span class="line">GRUB2_BOOT_DEVICE_ID=<span class="string">"<span class="subst">$(grub_get_device_id ${DEVICE})</span>"</span></span><br><span class="line"><span class="built_in">export</span> GRUB2_BOOT_DEVICE_ID</span><br><span class="line">GRUB2_PREPARE_ROOT_CACHE=<span class="string">"<span class="subst">$(prepare_grub_to_access_device ${DEVICE})</span>"</span></span><br><span class="line"><span class="built_in">export</span> GRUB2_PREPARE_ROOT_CACHE</span><br><span class="line"></span><br><span class="line"><span class="built_in">exec</span> ostree admin instutil grub2-generate</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="具体实现"><a href="#具体实现" class="headerlink" title="具体实现"></a>具体实现</h2><p>阅读 <a class="link" href="https://github.com/ostreedev/ostree" >ostree 源码<i class="fas fa-external-link-alt"></i></a>,函数调用顺序如下:<br>ot_admin_instutil_builtin_grub2_generate<br>ostree_generate_grub2_config<br>impl_ostree_generate_grub2_config<br>_ostree_bootloader_grub2_generate_config // 向target_fd(实际是向标准输出)中写入引导数据</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* This implementation is quite complex; see this issue for</span></span><br><span class="line"><span class="comment"> * a starting point:</span></span><br><span class="line"><span class="comment"> * https://github.com/ostreedev/ostree/issues/717</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">gboolean</span><br><span class="line">_ostree_bootloader_grub2_generate_config (OstreeSysroot *sysroot,</span><br><span class="line"> <span class="type">int</span> bootversion,</span><br><span class="line"> <span class="type">int</span> target_fd,</span><br><span class="line"> GCancellable *cancellable,</span><br><span class="line"> GError **error)</span><br><span class="line">{</span><br><span class="line"> <span class="comment">/* So... yeah. Just going to hardcode these. */</span></span><br><span class="line"> <span class="type">static</span> <span class="type">const</span> <span class="type">char</span> hardcoded_video[] = <span class="string">"load_video\n"</span></span><br><span class="line"> <span class="string">"set gfxpayload=keep\n"</span>;</span><br><span class="line"> <span class="type">static</span> <span class="type">const</span> <span class="type">char</span> hardcoded_insmods[] = <span class="string">"insmod gzio\n"</span>;</span><br><span class="line"> <span class="type">const</span> <span class="type">char</span> *grub2_boot_device_id =</span><br><span class="line"> g_getenv (<span class="string">"GRUB2_BOOT_DEVICE_ID"</span>);</span><br><span class="line"> <span class="type">const</span> <span class="type">char</span> *grub2_prepare_root_cache =</span><br><span class="line"> g_getenv (<span class="string">"GRUB2_PREPARE_ROOT_CACHE"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* We must have been called via the wrapper script */</span></span><br><span class="line"> g_assert (grub2_boot_device_id != <span class="literal">NULL</span>);</span><br><span class="line"> g_assert (grub2_prepare_root_cache != <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* Passed from the parent */</span></span><br><span class="line"> gboolean is_efi = g_getenv (<span class="string">"_OSTREE_GRUB2_IS_EFI"</span>) != <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"> g_autoptr(GOutputStream) out_stream = g_unix_output_stream_new (target_fd, FALSE);</span><br><span class="line"></span><br><span class="line"> g_autoptr(GPtrArray) loader_configs = <span class="literal">NULL</span>;</span><br><span class="line"> <span class="keyword">if</span> (!_ostree_sysroot_read_boot_loader_configs (sysroot, bootversion,</span><br><span class="line"> &loader_configs,</span><br><span class="line"> cancellable, error))</span><br><span class="line"> <span class="keyword">return</span> FALSE;</span><br><span class="line"></span><br><span class="line"> g_autoptr(GString) output = g_string_new (<span class="string">""</span>);</span><br><span class="line"> <span class="keyword">for</span> (guint i = <span class="number">0</span>; i < loader_configs->len; i++)</span><br><span class="line"> {</span><br><span class="line"> OstreeBootconfigParser *config = loader_configs->pdata[i];</span><br><span class="line"> <span class="type">const</span> <span class="type">char</span> *title;</span><br><span class="line"> <span class="type">const</span> <span class="type">char</span> *options;</span><br><span class="line"> <span class="type">const</span> <span class="type">char</span> *kernel;</span><br><span class="line"> <span class="type">const</span> <span class="type">char</span> *initrd;</span><br><span class="line"> <span class="type">const</span> <span class="type">char</span> *devicetree;</span><br><span class="line"> <span class="type">char</span> *quoted_title = <span class="literal">NULL</span>;</span><br><span class="line"> <span class="type">char</span> *uuid = <span class="literal">NULL</span>;</span><br><span class="line"> <span class="type">char</span> *quoted_uuid = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"> title = ostree_bootconfig_parser_get (config, <span class="string">"title"</span>);</span><br><span class="line"> <span class="keyword">if</span> (!title)</span><br><span class="line"> title = <span class="string">"(Untitled)"</span>;</span><br><span class="line"></span><br><span class="line"> kernel = ostree_bootconfig_parser_get (config, <span class="string">"linux"</span>);</span><br><span class="line"></span><br><span class="line"> quoted_title = g_shell_quote (title);</span><br><span class="line"> uuid = g_strdup_printf (<span class="string">"ostree-%u-%s"</span>, (guint)i, grub2_boot_device_id);</span><br><span class="line"> quoted_uuid = g_shell_quote (uuid);</span><br><span class="line"> g_string_append_printf (output, <span class="string">"menuentry %s --class gnu-linux --class gnu --class os --unrestricted %s {\n"</span>, quoted_title, quoted_uuid);</span><br><span class="line"> g_free (uuid);</span><br><span class="line"> g_free (quoted_title);</span><br><span class="line"> g_free (quoted_uuid);</span><br><span class="line"></span><br><span class="line"> <span class="comment">/* Hardcoded sections */</span></span><br><span class="line"> g_string_append (output, hardcoded_video);</span><br><span class="line"> g_string_append (output, hardcoded_insmods);</span><br><span class="line"> g_string_append (output, grub2_prepare_root_cache);</span><br><span class="line"> g_string_append_c (output, <span class="string">'\n'</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!kernel)</span><br><span class="line"> <span class="keyword">return</span> glnx_throw (error, <span class="string">"No \"linux\" key in bootloader config"</span>);</span><br><span class="line"> g_string_append (output, <span class="string">"linux"</span>);</span><br><span class="line"> <span class="keyword">if</span> (is_efi)</span><br><span class="line"> g_string_append (output, GRUB2_EFI_SUFFIX);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> g_string_append (output, GRUB2_SUFFIX);</span><br><span class="line"> g_string_append_c (output, <span class="string">' '</span>);</span><br><span class="line"> g_string_append (output, kernel);</span><br><span class="line"></span><br><span class="line"> options = ostree_bootconfig_parser_get (config, <span class="string">"options"</span>);</span><br><span class="line"> <span class="keyword">if</span> (options)</span><br><span class="line"> {</span><br><span class="line"> g_string_append_c (output, <span class="string">' '</span>);</span><br><span class="line"> g_string_append (output, options);</span><br><span class="line"> }</span><br><span class="line"> g_string_append_c (output, <span class="string">'\n'</span>);</span><br><span class="line"></span><br><span class="line"> initrd = ostree_bootconfig_parser_get (config, <span class="string">"initrd"</span>);</span><br><span class="line"> <span class="keyword">if</span> (initrd)</span><br><span class="line"> {</span><br><span class="line"> g_string_append (output, <span class="string">"initrd"</span>);</span><br><span class="line"> <span class="keyword">if</span> (is_efi)</span><br><span class="line"> g_string_append (output, GRUB2_EFI_SUFFIX);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> g_string_append (output, GRUB2_SUFFIX);</span><br><span class="line"> g_string_append_c (output, <span class="string">' '</span>);</span><br><span class="line"> g_string_append (output, initrd);</span><br><span class="line"> g_string_append_c (output, <span class="string">'\n'</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> devicetree = ostree_bootconfig_parser_get (config, <span class="string">"devicetree"</span>);</span><br><span class="line"> <span class="keyword">if</span> (devicetree)</span><br><span class="line"> {</span><br><span class="line"> g_string_append (output, <span class="string">"devicetree"</span>);</span><br><span class="line"> g_string_append_c (output, <span class="string">' '</span>);</span><br><span class="line"> g_string_append (output, devicetree);</span><br><span class="line"> g_string_append_c (output, <span class="string">'\n'</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> g_string_append (output, <span class="string">"}\n"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> gsize bytes_written;</span><br><span class="line"> <span class="keyword">if</span> (!g_output_stream_write_all (out_stream, output->str, output->len,</span><br><span class="line"> &bytes_written, cancellable, error))</span><br><span class="line"> <span class="keyword">return</span> FALSE;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> TRUE;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="查看所属软件包"><a href="#查看所属软件包" class="headerlink" title="查看所属软件包"></a>查看所属软件包</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">root@fedora:/etc/grub.d<span class="comment"># rpm -qf /usr/libexec/libostree/grub2-15_ostree</span></span><br><span class="line">ostree-grub2-2024.5-1.fc40.x86_64</span><br></pre></td></tr></table></figure><h2 id="查询软件包提供者"><a href="#查询软件包提供者" class="headerlink" title="查询软件包提供者"></a>查询软件包提供者</h2><p>源码也是由 ostree 提供</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">root@fedora:/etc/grub.d<span class="comment"># rpm -qi ostree-grub2</span></span><br><span class="line">Name : ostree-grub2</span><br><span class="line">Version : 2024.5</span><br><span class="line">Release : 1.fc40</span><br><span class="line">Architecture: x86_64</span><br><span class="line">Install Date: 2024年04月15日 星期一 02时09分59秒</span><br><span class="line">Group : Unspecified</span><br><span class="line">Size : 2266</span><br><span class="line">License : LGPL-2.0-or-later</span><br><span class="line">Signature : RSA/SHA256, 2024年03月15日 星期五 07时19分33秒, Key ID 0727707ea15b79cc</span><br><span class="line">Source RPM : ostree-2024.5-1.fc40.src.rpm</span><br><span class="line">Build Date : 2024年03月15日 星期五 06时09分26秒</span><br><span class="line">Build Host : buildhw-x86-08.iad2.fedoraproject.org</span><br><span class="line">Packager : Fedora Project</span><br><span class="line">Vendor : Fedora Project</span><br><span class="line">URL : https://ostree.readthedocs.io/en/latest/</span><br><span class="line">Bug URL : https://bugz.fedoraproject.org/ostree</span><br><span class="line">Summary : GRUB2 integration <span class="keyword">for</span> OSTree</span><br><span class="line">Description :</span><br><span class="line">GRUB2 integration <span class="keyword">for</span> OSTree</span><br></pre></td></tr></table></figure><h2 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h2><p>ostree-grub2 安装时提供了 /usr/libexec/libostree/grub2-15_ostree , 并链接至 /etc/grub.d/15_ostree,在重启前,执行 grub-mkconfig 操作,更新 grub 引导数据。</p>]]></content>
<summary type="html"><h2 id="grub-d-下的脚本"><a href="#grub-d-下的脚本" class="headerlink" title="grub.d 下的脚本"></a>grub.d 下的脚本</h2><figure class="highlight bash"><table</summary>
<category term="Fedora" scheme="https://ssk-wh.github.io/categories/Fedora/"/>
<category term="ostree" scheme="https://ssk-wh.github.io/tags/ostree/"/>
<category term="grub" scheme="https://ssk-wh.github.io/tags/grub/"/>
<category term="fedora" scheme="https://ssk-wh.github.io/tags/fedora/"/>
</entry>
<entry>
<title>ostree命令的基础用法</title>
<link href="https://ssk-wh.github.io/2024/0633106365.html"/>
<id>https://ssk-wh.github.io/2024/0633106365.html</id>
<published>2024-06-02T10:15:29.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><p>sudo apt install ostree</p><h2 id="init"><a href="#init" class="headerlink" title="init"></a>init</h2><p>cd ostree/<br>ostree init –repo=. init<br><img lazyload alt="image" data-src="/2024/0633106365/1.png" ></p><p>Just make your own changes and continueostree…</p><h2 id="commit"><a href="#commit" class="headerlink" title="commit"></a>commit</h2><p>将 tree/ 目录下的内容导入,提交信息未填写默认为空<br>ostree –repo=. commit –branch=foo tree/<br><img lazyload alt="image" data-src="/2024/0633106365/2.png" ></p><p>指定提交内容<br><img lazyload alt="image" data-src="/2024/0633106365/3.png" ></p><h2 id="refs"><a href="#refs" class="headerlink" title="refs"></a>refs</h2><p>列出仓库分支<br><img lazyload alt="image" data-src="/2024/0633106365/4.png" ></p><h2 id="ls"><a href="#ls" class="headerlink" title="ls"></a>ls</h2><p>查看文件系统树的内容<br><img lazyload alt="image" data-src="/2024/0633106365/5.png" ></p><h2 id="cat"><a href="#cat" class="headerlink" title="cat"></a>cat</h2><p>查看文件内容<br><img lazyload alt="image" data-src="/2024/0633106365/6.png" ></p><h2 id="checkout"><a href="#checkout" class="headerlink" title="checkout"></a>checkout</h2><p>检出<br><img lazyload alt="image" data-src="/2024/0633106365/7.png" ></p><h2 id="reset"><a href="#reset" class="headerlink" title="reset"></a>reset</h2><p>重置到某个提交,在此之后的提交全部丢弃<br><img lazyload alt="image" data-src="/2024/0633106365/8.png" ></p><h2 id="log"><a href="#log" class="headerlink" title="log"></a>log</h2><p>查看分支提交信息<br><img lazyload alt="image" data-src="/2024/0633106365/9.png" ></p><h2 id="show"><a href="#show" class="headerlink" title="show"></a>show</h2><p>查看最新一笔提交<br><img lazyload alt="image" data-src="/2024/0633106365/10.png" ></p><h2 id="diff"><a href="#diff" class="headerlink" title="diff"></a>diff</h2><p>比较提交差异<br><img lazyload alt="image" data-src="/2024/0633106365/11.png" ></p><h2 id="OSTREE-REPO"><a href="#OSTREE-REPO" class="headerlink" title="OSTREE_REPO"></a>OSTREE_REPO</h2><p>指定仓库地址,从而无需在命令中指定–repo<br><img lazyload alt="image" data-src="/2024/0633106365/12.png" ></p><h2 id="Manual"><a href="#Manual" class="headerlink" title="Manual"></a>Manual</h2><p><a class="link" href="https://ostreedev.github.io/ostree/man/" >https://ostreedev.github.io/ostree/man/<i class="fas fa-external-link-alt"></i></a></p><h2 id="开发"><a href="#开发" class="headerlink" title="开发"></a>开发</h2><p><a class="link" href="https://github.com/qt/qtotaupdate" >https://github.com/qt/qtotaupdate<i class="fas fa-external-link-alt"></i></a></p>]]></content>
<summary type="html"><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><p>sudo apt install ostree</p>
<h2 id="init"><a href="#init" class="heade</summary>
<category term="ostree" scheme="https://ssk-wh.github.io/tags/ostree/"/>
</entry>
<entry>
<title>Linux的启动</title>
<link href="https://ssk-wh.github.io/2024/0530982cbe.html"/>
<id>https://ssk-wh.github.io/2024/0530982cbe.html</id>
<published>2024-05-31T13:48:54.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<p><img lazyload alt="image" data-src="/2024/0530982cbe/Linux%E7%9A%84%E5%90%AF%E5%8A%A8.jpg" ></p>]]></content>
<summary type="html"><p><img
lazyload
alt="image"
data-src="/2024/0530982cbe/Linux%E7%9A%8</summary>
<category term="grub" scheme="https://ssk-wh.github.io/tags/grub/"/>
<category term="Linux" scheme="https://ssk-wh.github.io/tags/Linux/"/>
<category term="boot" scheme="https://ssk-wh.github.io/tags/boot/"/>
<category term="initrd" scheme="https://ssk-wh.github.io/tags/initrd/"/>
<category term="initramfs" scheme="https://ssk-wh.github.io/tags/initramfs/"/>
<category term="内核" scheme="https://ssk-wh.github.io/tags/%E5%86%85%E6%A0%B8/"/>
</entry>
<entry>
<title>OverlayFS</title>
<link href="https://ssk-wh.github.io/2024/05c2403edf.html"/>
<id>https://ssk-wh.github.io/2024/05c2403edf.html</id>
<published>2024-05-31T13:19:27.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<p>OverlayFS(Overlay Filesystem)是一种联合文件系统,允许将一个或多个文件系统层叠合并为一个单一的文件系统视图。它最常用于容器技术(如Docker)和其他需要高效文件系统管理的场景。以下是OverlayFS的基本概念、工作原理、以及常见的使用场景。</p><span id="more"></span><h2 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h2><p>OverlayFS有三个主要的目录概念:</p><ul><li><p><strong>Lower Directory(下层目录)</strong>:这是底层的只读文件系统。</p></li><li><p><strong>Upper Directory(上层目录)</strong>:这是上层的可写文件系统。</p></li><li><p><strong>Work Directory(工作目录)</strong>:这是一个用于支持上层目录操作的工作目录。</p></li></ul><p>OverlayFS通过将上层目录和下层目录合并,提供一个统一的视图给用户。在这个视图中,上层目录的文件会覆盖下层目录中的文件。</p><h2 id="工作原理"><a href="#工作原理" class="headerlink" title="工作原理"></a>工作原理</h2><p>当你挂载OverlayFS时,你指定一个下层目录(lowerdir)、一个上层目录(upperdir)和一个工作目录(workdir)。合并后的结果会展示在一个挂载点(merged)上。<br>以下是一些操作如何在OverlayFS中处理:</p><ul><li><strong>读取文件</strong>:如果文件存在于上层目录,则读取上层目录的文件;如果不存在,则读取下层目录的文件。</li><li><strong>写入文件</strong>:写入操作始终发生在上层目录。如果文件在下层目录中存在,写入操作会在上层目录中创建一个文件副本并进行修改。</li><li><strong>删除文件</strong>:删除操作在上层目录中创建一个白化文件(whiteout file),从而在合并视图中隐藏下层目录的文件。</li></ul><h2 id="使用示例"><a href="#使用示例" class="headerlink" title="使用示例"></a>使用示例</h2><p>假设你有以下目录结构:</p><ul><li><strong>lowerdir</strong>:下层只读目录。</li><li><strong>upperdir</strong>:上层可写目录。</li><li><strong>workdir</strong>:工作目录。</li><li><strong>merged</strong>:合并后的挂载点。</li></ul><h2 id="挂载OverlayFS"><a href="#挂载OverlayFS" class="headerlink" title="挂载OverlayFS"></a>挂载OverlayFS</h2><p><strong>创建目录</strong>:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">mkdir</span> -p lowerdir upperdir workdir merged</span><br></pre></td></tr></table></figure><p><strong>挂载OverlayFS</strong>:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">sudo mount -t overlay overlay -o lowerdir=lowerdir,upperdir=upperdir,workdir=workdir merged</span><br></pre></td></tr></table></figure><p><strong>验证挂载</strong>:<br>你可以通过以下命令查看挂载的结果:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">ls</span> merged</span><br></pre></td></tr></table></figure><h2 id="操作示例"><a href="#操作示例" class="headerlink" title="操作示例"></a>操作示例</h2><h3 id="读取文件"><a href="#读取文件" class="headerlink" title="读取文件"></a>读取文件</h3><p>如果 <strong>lowerdir</strong> 包含 <strong>file1</strong>,但 <strong>upperdir</strong> 不包含,那么 <strong>file1</strong> 可以在 <strong>merged</strong> 中读取。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">"This is a file in lowerdir"</span> > lowerdir/file1</span><br><span class="line"><span class="built_in">cat</span> merged/file1</span><br><span class="line"><span class="comment"># 输出: This is a file in lowerdir</span></span><br></pre></td></tr></table></figure><h3 id="写入文件"><a href="#写入文件" class="headerlink" title="写入文件"></a>写入文件</h3><p>如果你在 <strong>merged</strong> 中写入文件,文件会出现在 <strong>upperdir</strong> 中。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">"This is a new file in merged"</span> > merged/file2</span><br><span class="line"><span class="built_in">cat</span> upperdir/file2</span><br><span class="line"><span class="comment"># 输出: This is a new file in merged</span></span><br></pre></td></tr></table></figure><h3 id="修改文件"><a href="#修改文件" class="headerlink" title="修改文件"></a>修改文件</h3><p>如果你修改 <strong>merged</strong> 中存在于 <strong>lowerdir</strong> 的文件,修改后的副本会保存在 <strong>upperdir</strong> 中。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">"This is a modified file in merged"</span> > merged/file1</span><br><span class="line"><span class="built_in">cat</span> upperdir/file1</span><br><span class="line"><span class="comment"># 输出: This is a modified file in merged</span></span><br><span class="line"><span class="built_in">cat</span> lowerdir/file1</span><br><span class="line"><span class="comment"># 输出: This is a file in lowerdir</span></span><br></pre></td></tr></table></figure><h3 id="删除文件"><a href="#删除文件" class="headerlink" title="删除文件"></a>删除文件</h3><p>删除操作在上层目录中创建一个白化文件,从而在合并视图中隐藏下层目录的文件。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">rm</span> merged/file1</span><br><span class="line"><span class="built_in">ls</span> merged</span><br><span class="line"><span class="comment"># `file1` 不再存在</span></span><br><span class="line"><span class="built_in">ls</span> upperdir</span><br><span class="line"><span class="comment"># 输出: file1 (白化文件)</span></span><br></pre></td></tr></table></figure><h3 id="取消挂载"><a href="#取消挂载" class="headerlink" title="取消挂载"></a>取消挂载</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看挂载信息(确认挂载点)</span></span><br><span class="line">sudo mount | grep merged</span><br><span class="line"></span><br><span class="line"><span class="comment"># 取消挂载</span></span><br><span class="line">sudo umount merged</span><br></pre></td></tr></table></figure><h2 id="常见使用场景"><a href="#常见使用场景" class="headerlink" title="常见使用场景"></a>常见使用场景</h2><ul><li><strong>容器技术</strong>:Docker等容器技术广泛使用OverlayFS来管理镜像层和容器层,使得镜像可以共享底层文件而不重复存储。</li><li><strong>开发和测试</strong>:开发人员可以使用OverlayFS创建临时的文件系统视图进行测试,而不影响原有文件系统。</li><li><strong>系统升级和恢复</strong>:系统管理员可以使用OverlayFS进行系统升级测试,确保系统稳定后再进行实际的升级操作。</li></ul><p>OverlayFS提供了一种高效且灵活的文件系统管理方式,适用于多种需要层叠文件系统视图的应用场景。</p>]]></content>
<summary type="html"><p>OverlayFS(Overlay Filesystem)是一种联合文件系统,允许将一个或多个文件系统层叠合并为一个单一的文件系统视图。它最常用于容器技术(如Docker)和其他需要高效文件系统管理的场景。以下是OverlayFS的基本概念、工作原理、以及常见的使用场景。</p></summary>
<category term="fs" scheme="https://ssk-wh.github.io/tags/fs/"/>
<category term="overlay" scheme="https://ssk-wh.github.io/tags/overlay/"/>
</entry>
<entry>
<title>Wayland Coding 速记-Staging</title>
<link href="https://ssk-wh.github.io/2024/05df3c7382.html"/>
<id>https://ssk-wh.github.io/2024/05df3c7382.html</id>
<published>2024-05-28T10:53:07.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<p>因工作需要加之个人比较感兴趣的原因,在实现 Wayland 合成器相关协议之途中,随笔记录记录一些相关的基础知识。</p><span id="more"></span><p><a name="Tmrp0"></a></p><h2 id="Wayland"><a href="#Wayland" class="headerlink" title="Wayland"></a>Wayland</h2><p>关于 wayland 的总结,个人觉得下面一段话挺好:</p><blockquote><p>WaylandWayland is a replacement for the X11 window system protocol and architecture with the aim to be easier to develop, extend, and maintain.<br /></p><p>WaylandWayland 是 X11 窗口系统协议和架构的替代品,旨在更易于开发、扩展和维护。<br /></p><p>Wayland is the language (protocol) that applications can use to talk to a display server in order to make themselves visible and get input from the user (a person). A Wayland server is called a “compositor”. Applications are Wayland clients.<br /></p><p>Wayland 是应用程序可用来与显示服务器对话的语言(协议),以便使自己可见并获取用户(人)的输入。 Wayland 服务器被称为“合成器”。应用程序是 Wayland 客户端。<br /></p><p>Wayland also refers to a system architecture. It is not just a server-client relationship between a compositor and applications. There is no single common Wayland server like Xorg is for X11, but every graphical environment brings with it one of many compositor implementations. Window management and the end user experience are often tied to the compositor rather than swappable components.<br /></p><p>Wayland 也指一种系统架构。它不仅仅是合成器和应用程序之间的服务器-客户端关系。没有像 Xorg 那样适用于 X11 的单一通用 Wayland 服务器,但每个图形环境都带来了许多合成器实现之一。窗口管理和最终用户体验通常与合成器而不是可交换组件相关。<br /></p><p>A core part of Wayland architecture is libwayland: an inter-process communication library that translates a protocol definition in XML to a C language API. This library does not implement Wayland, it merely encodes and decodes Wayland messages. The actual implementations are in the various compositor and application toolkit projects.<br /></p><p>Wayland 架构的核心部分是 libwayland:一个进程间通信库,它将 XML 中的协议定义转换为 C 语言 API。该库没有实现 Wayland,它只是对 Wayland 消息进行编码和解码。实际的实现是在各种合成器和应用程序工具包项目中。<br /></p><p>Wayland does not restrict where and how it is used. A Wayland compositor could be a standalone display server running on Linux kernel modesetting and evdev input devices or on many other operating systems, or a nested compositor that itself is an X11 or Wayland application (client). Wayland can even be used in application-internal communication as is done in some web browsers.<br /></p><p>Wayland 不限制其使用地点和方式。 Wayland 合成器可以是在 Linux 内核模式设置和 evdev 输入设备或许多其他操作系统上运行的独立显示服务器,也可以是本身就是 X11 或 Wayland 应用程序(客户端)的嵌套合成器。 Wayland 甚至可以用于应用程序内部通信,就像某些 Web 浏览器中所做的那样。<br /></p><p>Part of the Wayland project is also the Weston reference implementation of a Wayland compositor. Weston can run as an X client or under Linux KMS and ships with a few demo clients. The Weston compositor is a minimal and fast compositor and is suitable for many embedded and mobile use cases.</p><p>Wayland 项目的一部分也是 Wayland 合成器的 Weston 参考实现。 Weston 可以作为 X 客户端或在 Linux KMS 下运行,并附带一些演示客户端。 Weston 合成器是一个最小且快速的合成器,适用于许多嵌入式和移动用例。</p></blockquote><p><a name="LJoxs"></a></p><h2 id="开发库"><a href="#开发库" class="headerlink" title="开发库"></a>开发库</h2><p>后续开发内容均基于 libwayland-dev 进行。</p><p><a name="yTd8M"></a></p><h3 id="主要结构体"><a href="#主要结构体" class="headerlink" title="主要结构体"></a>主要结构体</h3><table><thead><tr><th><strong>Struct</strong></th><th><strong>Description</strong></th><th><strong>Example</strong></th></tr></thead><tbody><tr><td>wl_display</td><td>代表一个 Wayland 显示服务器的连接。它用于管理客户端和服务器之间的通信和事件处理</td><td>struct wl_display *wl_display_create(void);<br />void wl_display_run(struct wl_display *display);<br />struct wl_list *wl_display_get_client_list(struct wl_display *display);</td></tr><tr><td>wl_global</td><td>用于描述全局对象。这些全局对象在 Wayland 显示服务器中注册,可以被客户端发现和使用。<strong>wl_global</strong> 对象通常表示服务器中提供的某些功能或接口,例如 compositor、shell、seat 等</td><td>struct wl_global *wl_global_create(struct wl_display *display, const struct wl_interface *interface, int version, void *data, wl_global_bind_func_t bind);</td></tr><tr><td>wl_event_loop</td><td>用于管理事件循环。在 Wayland 服务器中,事件循环用于处理来自客户端的请求、内部超时事件以及文件描述符上的事件。</td><td>struct wl_event_loop *wl_event_loop_create(void);<br />void wl_event_loop_destroy(struct wl_event_loop *loop);</td></tr><tr><td>wl_event_source</td><td>用于描述一个事件源。在 Wayland 服务器的事件循环中,事件源可以是文件描述符事件、定时器事件或信号事件。</td><td>struct wl_event_source *wl_event_loop_add_fd(struct wl_event_loop *loop, int fd, uint32_t mask, wl_event_loop_fd_func_t func, void *data);</td></tr><tr><td>wl_interface</td><td>用于描述 Wayland 协议中的接口。接口是 Wayland 协议的基本构建块,定义了客户端和服务器之间可以进行的交互。每个接口包括一组方法(requests)和事件(events)。</td><td>struct wl_interface {<br /> const char *name;<br /> int version;<br /> int method_count;<br /> const struct wl_message *methods;<br /> int event_count;<br /> const struct wl_message *events;<br />};</td></tr><tr><td>wl_message</td><td>用于描述接口中的每个方法和事件。</td><td>static const struct wl_message my_interface_events[] = { { “something_done”, “s”, NULL } // “s” 表示事件发送一个字符串参数 };</td></tr><tr><td>wl_resource</td><td>用于表示 Wayland 客户端与服务器之间的一个协议对象。它在客户端和服务器之间传递方法调用和事件通知。每个 <strong>wl_resource</strong> 都与一个特定的 <strong>wl_interface</strong>(接口)相关联,表示该接口的一个实例。</td><td>struct wl_resource *wl_resource_create(struct wl_client *client, const struct wl_interface *interface, int version, uint32_t id);<br />void wl_resource_set_implementation(struct wl_resource *resource, const void *implementation, void *data, wl_resource_destroy_func_t destroy);</td></tr><tr><td>wl_surface</td><td>代表了一个可供客户端绘制的表面(Surface)。它是构建用户界面的基本单元,可以是窗口、按钮、文本框等可见的元素。<strong>wl_surface</strong> 通过 Wayland 协议与客户端和服务器进行通信,客户端可以向 <strong>wl_surface</strong> 发送绘图指令,服务器则负责将这些指令转换为屏幕上的图像。</td><td></td></tr><tr><td>wl_output</td><td>Wayland 中用于表示显示器(output)的接口。每个 <strong>wl_output</strong> 对象代表了系统中的一个物理显示设备,比如显示器或投影仪。通过 <strong>wl_output</strong> 接口,客户端程序可以获取有关显示器的信息,如分辨率、缩放因子、物理尺寸、制造商信息等,并接收显示器的事件,如模式更改、连接状态变化等。</td><td>wl_output_add_geometry_listener</td></tr><tr><td>wl_client</td><td>用于表示一个连接到 Wayland 服务器的客户端。它负责管理客户端连接、处理客户端的请求,并向客户端发送事件</td><td>struct wl_client *wl_resource_get_client(struct wl_resource *resource);<br />void wl_client_post_no_memory(struct wl_client *client);<br />void wl_client_post_implementation_error(struct wl_client *client, const char *msg);<br />void wl_client_post_event(struct wl_client *client, uint32_t opcode, …);</td></tr><tr><td>wl_signal</td><td>用于实现发布-订阅模式的信号机制。它允许对象在状态变化时通知感兴趣的侦听器(监听器)。<strong>wl_signal</strong> 是一个简单但功能强大的机制,可以在 Wayland 服务端内部或者在客户端与服务端之间传递事件通知。</td><td>struct wl_signal my_signal;<br />wl_signal_init(&my_signal);<br />void my_signal_handler(struct wl_listener *listener, void *data) {<br /> printf(“Signal received with data: %s\n”, (char *)data);<br />}<br />struct wl_listener my_listener;<br />my_listener.notify = my_signal_handler;<br />wl_signal_add(&my_signal, &my_listener);<br />// send signal to notify all listener<br />const char *signal_data = “Hello, World!”;<br />wl_signal_emit(&my_signal, (void *)signal_data);</td></tr><tr><td>wl_listener</td><td>用于监听 <strong>wl_signal</strong> 发出的信号。每个 <strong>wl_listener</strong> 都包含一个回调函数,当监听的信号发出时,该回调函数会被调用。这种机制使得对象之间的通信变得更加灵活和解耦。</td><td>struct wl_listener {<br /> struct wl_list link;<br /> wl_notify_func_t notify;<br />};<br />struct wl_listener my_listener;<br />my_listener.notify = my_signal_handler; // 设置回调函数<br />wl_signal_add(&my_signal, &my_listener); // 将监听器添加到信号中</td></tr><tr><td>wl_list</td><td>Wayland 核心库中的一个双向链表实现,用于在 Wayland 内部和相关组件中进行列表管理</td><td>struct wl_list {<br /> struct wl_list *prev;<br /> struct wl_list *next;<br />};<br />void wl_list_init(struct wl_list *list);<br />void wl_list_insert(struct wl_list *list, struct wl_list *elm);<br />void wl_list_remove(struct wl_list *elm);<br />wl_list_for_each & wl_list_for_each_safe</td></tr><tr><td>wl_shm_buffer</td><td>Wayland 的共享内存(Shared Memory)缓冲区,用于在客户端和服务器之间共享图像数据。它允许客户端将图像数据写入共享内存,然后将该内存区域作为缓冲区发送到服务器。服务器可以直接访问这个共享内存,从而避免了数据的拷贝,提高了效率</td><td></td></tr><tr><td>wl_shm_pool</td><td>Wayland 提供的一个共享内存池,用于在客户端和服务器之间共享图像数据。<strong>wl_shm_pool</strong> 是通过 Wayland 的 <strong>wl_shm</strong> 接口创建的,它允许客户端从共享内存中分配多个缓冲区。这些缓冲区可以被客户端用来绘制图像,并将其传递给服务器显示。</td><td></td></tr><tr><td>wl_protocol_logger</td><td>用于记录 Wayland 协议的消息。它允许开发者记录客户端和服务器之间交换的协议消息,方便调试和分析 Wayland 协议的使用情况。</td><td>struct wl_protocol_logger {<br /> void (*log)(void *user_data, struct wl_resource *resource,<br /> uint32_t opcode, const struct wl_message *message,<br /> union wl_argument *args);<br /> void *user_data;<br />};<br /><br />struct wl_protocol_logger logger = { <br />.log = protocol_log, <br />.user_data = “Wayland” // 这里可以传递任何用户数据<br /> }; <br />wl_display_add_protocol_logger(display, &logger);</td></tr><tr><td>wl_display_add_destroy_listener</td><td>绑定到一个 wl_listener 结构,通过指定 wl_listener 的.notify成员实现对 display 销毁时的监听<br />用于在 wl_display 对象销毁时注册一个回调函数。这个回调函数会在 wl_display 对象销毁时被调用,以便进行清理或其他必要的操作。</td><td>manager->display_destroy.notify = handle_display_destroy;<br /> wl_display_add_destroy_listener(display, &manager->display_destroy);</td></tr></tbody></table><p><a name="jKOh5"></a></p><h3 id="主要函数"><a href="#主要函数" class="headerlink" title="主要函数"></a>主要函数</h3><table><thead><tr><th><strong>Function</strong></th><th><strong>Description</strong></th><th><strong>Example</strong></th></tr></thead><tbody><tr><td>wl_display_add_destroy_listener</td><td>绑定到一个 wl_listener 结构,通过指定 wl_listener 的.notify成员实现对 display 销毁时的监听<br />用于在 wl_display 对象销毁时注册一个回调函数。这个回调函数会在 wl_display 对象销毁时被调用,以便进行清理或其他必要的操作。</td><td>manager->display_destroy.notify = handle_display_destroy;<br /> wl_display_add_destroy_listener(display, &manager->display_destroy);</td></tr><tr><td>wl_event_loop_add_destroy_listener</td><td>用于向事件循环添加一个监听器,以便在事件循环被销毁时触发回调函数。</td><td>struct wl_listener *wl_event_loop_add_destroy_listener(struct wl_event_loop *loop, wl_listener *listener);</td></tr><tr><td>wl_global_create</td><td>用于创建一个全局对象,并将其注册到 Wayland 显示服务器上。全局对象可以被客户端程序获取并使用,从而实现客户端和服务器之间的通信。</td><td>struct wl_global *wl_global_create(struct wl_display *display,<br /> const struct wl_interface *interface,<br /> int version,<br /> void *data,<br /> wl_global_bind_func_t bind);</td></tr><tr><td>wl_global_remove</td><td>类似wl_global_destroy,但并不销毁。通常使用 wl_global_destroy 即可</td><td></td></tr><tr><td>wl_global_destroy</td><td>销毁一个全局对象。</td><td></td></tr><tr><td>wl_resource_set_implementation</td><td>用于将一组回调函数(即接口实现)和用户数据关联到一个 <strong>wl_resource</strong> 对象。每当与该资源相关的客户端请求到达时,Wayland 会调用相应的回调函数,从而实现具体的行为。</td><td>void wl_resource_set_implementation(struct wl_resource *resource,<br /> const void *implementation,<br />void *data,<br /> wl_resource_destroy_func_t destroy);</td></tr><tr><td>wl_resource_set_user_data</td><td>用于将用户自定义的数据与特定的 <strong>wl_resource</strong> 资源关联起来。这使得在处理资源相关的回调时,可以访问和使用这些用户数据。</td><td>void wl_resource_set_user_data(struct wl_resource *resource, void *user_data);</td></tr><tr><td>wl_display_roundtrip</td><td>Wayland 客户端程序中常用的函数之一,用于同步地发送请求并等待服务器对请求的响应。它会阻塞当前线程,直到服务器返回响应或者发生错误。</td><td>int wl_display_roundtrip(struct wl_display *display);</td></tr><tr><td>wl_resource_get_user_data</td><td>用于获取与特定 <strong>wl_resource</strong> 资源关联的用户数据。这个函数通常与 <strong>wl_resource_set_user_data</strong> 一起使用,后者用于将用户数据与资源关联。</td><td>void *wl_resource_get_user_data(struct wl_resource *resource);</td></tr></tbody></table><p><a name="Vw3Mb"></a></p><h3 id="核心文件"><a href="#核心文件" class="headerlink" title="核心文件"></a>核心文件</h3><p>wayland-server-core.h</p><p><a name="ICOD6"></a></p><h2 id="协议分类"><a href="#协议分类" class="headerlink" title="协议分类"></a>协议分类</h2><p>详见: <a class="link" href="https://wayland.app/protocols/" >https://wayland.app/protocols/<i class="fas fa-external-link-alt"></i></a><br>:::success<br><em>实际上,wayland 合成器就是一组协议的实现者。</em><br>:::<br>wayland 协议大致分为 core(核心)、stable(稳定)、staging(考虑中,可能会变为稳定)、unstable(不稳定)等,表明其当前状态,出于兼容考虑,合成器的开发应且务必实现 core 和 stable 协议,视情况需要实现部分 unstable 或其它甚至是自定义协议。</p><p><a name="AgOPi"></a></p><h3 id="Core"><a href="#Core" class="headerlink" title="Core"></a>Core</h3><table><thead><tr><th><strong>Name</strong></th><th><strong>Description</strong></th></tr></thead><tbody><tr><td>Wayland</td><td>Wayland 核心协议,这个文件定义了客户端和服务器之间通信的标准接口,包括各种对象、请求和事件。是使用其他协议的前提。</td></tr></tbody></table><p><a name="mcV5i"></a></p><h3 id="Stable"><a href="#Stable" class="headerlink" title="Stable"></a>Stable</h3><table><thead><tr><th><strong>Name</strong></th><th><strong>Description</strong></th></tr></thead><tbody><tr><td>Presentation time</td><td>Presentation-Time 协议是为了解决音频与视频同步播放时出现的问题而设计的。它允许客户端在显示器上的特定时间点提交图像,以确保图像在预期时间显示,从而实现音频和视频的同步播放。</td></tr><tr><td>Viewporter</td><td>它旨在支持客户端动态调整输出显示区域(viewport)的大小和位置。这个协议特别适用于需要对输出进行缩放、平移或裁剪的应用场景,比如 VR(虚拟现实)和多显示器环境下的窗口管理器等。</td></tr><tr><td>XDG shell</td><td>定义了一种标准的方式来管理窗口和窗口管理器之间的通信,使得窗口的创建、调整和销毁等操作能够在 Wayland 环境下进行。</td></tr><tr><td>Linux DMA-BUF</td><td>Linux 内核中用于在设备之间共享内存的机制。DMA-BUF 全称是 Direct Memory Access Buffer,它允许不同的设备(如图形处理器、显示器、摄像头等)直接访问内核中的一块共享内存区域,而无需复制数据到每个设备的私有内存中。</td></tr><tr><td>Tablet</td><td>旨在提供对触摸板和手写板等输入设备的更丰富支持。它定义了一组标准接口,使得客户端能够更好地与这些特殊输入设备进行交互,并实现更丰富的用户体验。</td></tr></tbody></table><p><a name="sOLys"></a></p><h3 id="Staging"><a href="#Staging" class="headerlink" title="Staging"></a>Staging</h3><table><thead><tr><th><strong>Name</strong></th><th><strong>Description</strong></th></tr></thead><tbody><tr><td>XDG activation</td><td>旨在提供一种标准化的方式来启动和激活桌面应用程序。它定义了一组接口,允许应用程序和桌面环境之间进行通信,以便启动应用程序、切换窗口焦点、和处理用户交互。</td></tr><tr><td>DRM lease</td><td>允许应用程序临时租用图形硬件资源,例如显示器和显卡,从而绕过窗口系统,直接控制这些资源。这在虚拟现实(VR)和增强现实(AR)等需要低延迟和高性能图形渲染的应用中尤为重要。</td></tr><tr><td>DRM synchronization object</td><td>用于在图形渲染过程中协调和同步不同操作和资源的使用。它们在确保图形管线中的各个阶段按正确顺序执行、避免资源竞争和数据不一致方面发挥着关键作用。</td></tr><tr><td>Session lock</td><td>用于保护用户会话安全,防止未授权的访问。当用户暂时离开工作站时,可以锁定会话以确保其正在运行的应用程序和数据不会被其他人查看或篡改。</td></tr><tr><td>Single-pixel buffer</td><td>专门用于优化小图形元素的传输和渲染。它的主要目标是提供一种高效的方式来处理单个像素的图形操作,这对于某些类型的图形应用程序(如光标、点状图形、单色图形元素等)非常重要。</td></tr><tr><td>Content type hint</td><td>允许客户端向合成器(compositor)提供关于表面(surface)内容类型的提示。这些提示有助于合成器优化渲染和处理不同类型的内容,提高显示性能和视觉效果。</td></tr><tr><td>Idle notify</td><td>使客户端能够接收用户空闲状态的通知,从而在用户不活动时执行特定任务。这种机制有助于优化系统资源使用,提高用户体验,特别是在屏幕保护和节能模式等应用场景中。通过合理使用该协议,开发者可以显著提升应用程序的智能化和响应能力。</td></tr><tr><td>Tearing control</td><td>旨在解决屏幕撕裂问题。屏幕撕裂是在显示器刷新过程中,显示的图像部分来自于不同的帧,导致图像出现不连续的现象。这种现象在快速运动的场景中特别明显。Tearing Control 协议通过提供机制让客户端和合成器协作,来减少或消除屏幕撕裂,提高显示效果和用户体验。</td></tr><tr><td>Xwayland shell</td><td>Xwayland 是 Wayland 的一个兼容层,使得 X11 应用程序可以在 Wayland 合成器上运行。Xwayland Shell 协议是一个特定的 Wayland 扩展协议,旨在为运行在 Xwayland 上的 X11 客户端提供更好的窗口管理和集成支持。这个协议使得 Wayland 合成器能够更好地控制和管理这些 X11 窗口,从而提高整体用户体验。</td></tr><tr><td>Fractional scale</td><td>用于支持显示器的分数缩放(Fractional Scaling)。传统的显示器缩放通常只支持整数比例,例如 1x、2x、3x 等,这可能无法完全满足高分辨率显示器上的 UI 缩放需求。Fractional Scale 协议允许用户以分数形式(如 1.25x、1.5x、1.75x 等)调整 UI 的缩放级别,以更好地适应高分辨率显示器和不同的视觉需求。</td></tr><tr><td>Cursor shape</td><td>旨在允许客户端动态地改变鼠标指针的形状。这个协议使得应用程序可以根据需要更改鼠标指针的外观,以提供更好的用户体验和交互反馈。</td></tr><tr><td>Foreign toplevel list</td><td>旨在提供一种机制,让 Wayland 合成器(compositor)可以跟踪和管理来自外部系统的顶层窗口(例如 X11 窗口)。通过这个协议,Wayland 合成器可以更好地集成和管理来自不同窗口系统的窗口,提供更统一的用户体验。</td></tr><tr><td>Security context</td><td>Security Context 协议为 Wayland 提供了一种机制,允许客户端和服务端在通信中传递安全上下文信息,增强通信的安全性。尽管该协议需要客户端和服务端的正确实现,并可能带来一定的性能开销,但它能够有效地保护通信内容的机密性和完整性,并支持基于权限的访问控制,从而提高了 Wayland 通信的安全性。</td></tr><tr><td>Transient seat</td><td>它允许在同一系统上的不同输入设备之间建立父子关系。这种关系对于多屏幕系统或者具有多个输入设备的系统非常有用,它能够确保特定的输入设备(例如触摸板或者鼠标)仅控制特定的屏幕或应用程序。</td></tr><tr><td>XDG toplevel drag</td><td>用于实现在 Wayland 上对窗口进行拖动操作。这个协议允许用户在屏幕上拖动应用程序的顶层窗口,以便更改其位置或将其拖入其他工作区等。XDG Toplevel Drag 协议的实现使得用户能够通过简单的拖动操作来管理和组织窗口,提高了桌面环境的交互性和可用性。</td></tr><tr><td>XDG dialog windows</td><td>旨在为桌面环境提供一种标准化的方式来管理对话框窗口。该协议定义了一组接口和事件,用于创建、显示和管理对话框窗口,并规定了对话框窗口的行为和外观,以提供更一致的用户体验。</td></tr><tr><td>Alpha modifier protocol</td><td>它允许客户端与服务器协商窗口表面(surface)的 Alpha 值,以实现窗口的透明度调整。</td></tr></tbody></table><p>其他协议请查阅:<a class="link" href="https://wayland.app/protocols/" >https://wayland.app/protocols/<i class="fas fa-external-link-alt"></i></a></p><p><a name="Z39oa"></a></p><h2 id="自定义协议"><a href="#自定义协议" class="headerlink" title="自定义协议"></a>自定义协议</h2><p>使用 wayland-scanner 命令将协议文件(XML)生成胶水代码,如果是服务端,需设置新协议的实现,客户端直接调用胶水代码的接口即可。<br><a name="RzRTz"></a></p><h3 id="服务端实现"><a href="#服务端实现" class="headerlink" title="服务端实现"></a>服务端实现</h3><p>参考 <a class="link" href="https://gitlab.freedesktop.org/wlroots/wlroots/-/tree/0.17?ref_type=heads" >wlroots<i class="fas fa-external-link-alt"></i></a> 项目,不再赘述。<br />附一些之前手写的合成器对 <a class="link" href="https://wayland.app/protocols/ext-session-lock-v1" >ext_session_lock_v1<i class="fas fa-external-link-alt"></i></a> 协议支持的代码:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">pragma</span> once</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"ext-session-lock-server-protocol.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_manager_v1</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_event_loop</span> *<span class="title">event_loop</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_global</span> *<span class="title">global</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_list</span> <span class="title">contexts</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_resource</span> *<span class="title">client</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_listener</span> <span class="title">display_destroy</span>;</span></span><br><span class="line"></span><br><span class="line"> <span class="class"><span class="keyword">struct</span></span></span><br><span class="line"><span class="class"> {</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_signal</span> <span class="title">lock</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_signal</span> <span class="title">destroy</span>;</span></span><br><span class="line"> } events;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_v1</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_resource</span> *<span class="title">resource</span>;</span></span><br><span class="line"> <span class="type">uint32_t</span> id;</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_list</span> <span class="title">contexts</span>;</span></span><br><span class="line"></span><br><span class="line"> <span class="class"><span class="keyword">struct</span></span></span><br><span class="line"><span class="class"> {</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_signal</span> <span class="title">get_lock_surface</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_signal</span> <span class="title">unlock_and_destroy</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_signal</span> <span class="title">destroy</span>;</span></span><br><span class="line"> } events;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_surface_v1</span></span></span><br><span class="line"><span class="class">{</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_resource</span> *<span class="title">resource</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_resource</span> *<span class="title">surface</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_resource</span> *<span class="title">output</span>;</span></span><br><span class="line"> <span class="type">uint32_t</span> id;</span><br><span class="line"></span><br><span class="line"> <span class="class"><span class="keyword">struct</span></span></span><br><span class="line"><span class="class"> {</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_signal</span> <span class="title">ack_configure</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_signal</span> <span class="title">destroy</span>;</span></span><br><span class="line"> } events;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">ext_session_lock_v1_destroy</span><span class="params">(<span class="keyword">struct</span> ext_session_lock_v1 *context)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">ext_session_lock_surface_v1_destroy</span><span class="params">(<span class="keyword">struct</span> ext_session_lock_surface_v1 *context)</span>;</span><br><span class="line"><span class="keyword">struct</span> ext_session_lock_manager_v1 *<span class="title function_">ext_session_lock_manager_v1_create</span><span class="params">(<span class="keyword">struct</span> wl_display *display)</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"ext_session_lock_manager_impl.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">lock_surface_handle_destroy</span><span class="params">(<span class="keyword">struct</span> wl_client *client, <span class="keyword">struct</span> wl_resource *resource)</span></span><br><span class="line">{</span><br><span class="line"> wl_resource_destroy(resource);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">lock_surface_handle_ack_configure</span><span class="params">([[maybe_unused]] <span class="keyword">struct</span> wl_client *client,</span></span><br><span class="line"><span class="params"> <span class="keyword">struct</span> wl_resource *resource,</span></span><br><span class="line"><span class="params"> <span class="type">uint32_t</span> serial)</span></span><br><span class="line">{</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_surface_v1</span> *<span class="title">context</span> =</span></span><br><span class="line"> static_cast<ext_session_lock_surface_v1 *>(wl_resource_get_user_data(resource));</span><br><span class="line"> <span class="keyword">if</span> (!context) {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> wl_signal_emit_mutable(&context->events.ack_configure, context);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_surface_v1_interface</span> <span class="title">lock_surface_implementation</span> =</span> {</span><br><span class="line"> .destroy = lock_surface_handle_destroy,</span><br><span class="line"> .ack_configure = lock_surface_handle_ack_configure,</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">ext_session_lock_surface_v1_destroy</span><span class="params">(<span class="keyword">struct</span> ext_session_lock_surface_v1 *context)</span></span><br><span class="line">{</span><br><span class="line"> wl_signal_emit_mutable(&context->events.destroy, context);</span><br><span class="line"> <span class="built_in">free</span>(context);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">ext_session_lock_surface_v1_destroy_func</span><span class="params">(wl_resource *resource)</span></span><br><span class="line">{</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_surface_v1</span> *<span class="title">context</span> =</span></span><br><span class="line"> static_cast<ext_session_lock_surface_v1 *>(wl_resource_get_user_data(resource));</span><br><span class="line"> <span class="keyword">if</span> (!context) {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ext_session_lock_surface_v1_destroy(context);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">lock_handle_get_lock_surface</span><span class="params">(<span class="keyword">struct</span> wl_client *client,</span></span><br><span class="line"><span class="params"> <span class="keyword">struct</span> wl_resource *lock_resource,</span></span><br><span class="line"><span class="params"> <span class="type">uint32_t</span> id,</span></span><br><span class="line"><span class="params"> <span class="keyword">struct</span> wl_resource *surface,</span></span><br><span class="line"><span class="params"> <span class="keyword">struct</span> wl_resource *output)</span></span><br><span class="line">{</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_v1</span> *<span class="title">context</span> =</span></span><br><span class="line"> static_cast<ext_session_lock_v1 *>(wl_resource_get_user_data(lock_resource));</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_resource</span> *<span class="title">resource</span> =</span> wl_resource_create(client,</span><br><span class="line"> &ext_session_lock_surface_v1_interface,</span><br><span class="line"> EXT_SESSION_LOCK_V1_DESTROY_SINCE_VERSION,</span><br><span class="line"> id);</span><br><span class="line"> <span class="keyword">if</span> (resource == <span class="literal">NULL</span>) {</span><br><span class="line"> wl_resource_post_no_memory(lock_resource);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_surface_v1</span> *<span class="title">lock_surface</span> =</span></span><br><span class="line"> static_cast<ext_session_lock_surface_v1 *>(<span class="built_in">calloc</span>(<span class="number">1</span>, <span class="keyword">sizeof</span>(*lock_surface)));</span><br><span class="line"> <span class="keyword">if</span> (lock_surface == <span class="literal">NULL</span>) {</span><br><span class="line"> wl_resource_post_no_memory(lock_resource);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> wl_resource_set_implementation(resource,</span><br><span class="line"> &lock_surface_implementation,</span><br><span class="line"> lock_surface,</span><br><span class="line"> ext_session_lock_surface_v1_destroy_func);</span><br><span class="line"></span><br><span class="line"> wl_resource_set_user_data(resource, lock_surface);</span><br><span class="line"></span><br><span class="line"> wl_signal_init(&lock_surface->events.ack_configure);</span><br><span class="line"> wl_signal_init(&lock_surface->events.destroy);</span><br><span class="line"></span><br><span class="line"> lock_surface->resource = resource;</span><br><span class="line"> lock_surface->surface = surface;</span><br><span class="line"> lock_surface->output = output;</span><br><span class="line"> lock_surface->id = id;</span><br><span class="line"></span><br><span class="line"> wl_signal_emit_mutable(&context->events.get_lock_surface, lock_surface);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">lock_handle_destroy</span><span class="params">([[maybe_unused]] <span class="keyword">struct</span> wl_client *client,</span></span><br><span class="line"><span class="params"> <span class="keyword">struct</span> wl_resource *resource)</span></span><br><span class="line">{</span><br><span class="line"> wl_resource_destroy(resource);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">lock_handle_unlock_and_destroy</span><span class="params">(<span class="keyword">struct</span> wl_client *client, <span class="keyword">struct</span> wl_resource *resource)</span></span><br><span class="line">{</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_v1</span> *<span class="title">context</span> =</span></span><br><span class="line"> static_cast<ext_session_lock_v1 *>(wl_resource_get_user_data(resource));</span><br><span class="line"> wl_signal_emit_mutable(&context->events.unlock_and_destroy, context);</span><br><span class="line"> lock_handle_destroy(client, resource);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_v1_interface</span> <span class="title">lock_implementation</span> =</span> {</span><br><span class="line"> .destroy = lock_handle_destroy,</span><br><span class="line"> .get_lock_surface = lock_handle_get_lock_surface,</span><br><span class="line"> .unlock_and_destroy = lock_handle_unlock_and_destroy,</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">manager_handle_destroy</span><span class="params">(<span class="keyword">struct</span> wl_client *client, <span class="keyword">struct</span> wl_resource *resource)</span></span><br><span class="line">{</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_manager_v1</span> *<span class="title">context</span> =</span></span><br><span class="line"> static_cast<ext_session_lock_manager_v1 *>(wl_resource_get_user_data(resource));</span><br><span class="line"> <span class="keyword">if</span> (!context) {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> wl_signal_emit_mutable(&context->events.destroy, context);</span><br><span class="line"> wl_list_remove(wl_resource_get_link(resource));</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">ext_session_lock_v1_destroy</span><span class="params">(<span class="keyword">struct</span> ext_session_lock_v1 *context)</span></span><br><span class="line">{</span><br><span class="line"> wl_signal_emit_mutable(&context->events.destroy, context);</span><br><span class="line"> <span class="built_in">free</span>(context);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">ext_session_lock_v1_destroy_func</span><span class="params">(wl_resource *resource)</span></span><br><span class="line">{</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_v1</span> *<span class="title">context</span> =</span></span><br><span class="line"> static_cast<ext_session_lock_v1 *>(wl_resource_get_user_data(resource));</span><br><span class="line"> <span class="keyword">if</span> (!context) {</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> ext_session_lock_v1_destroy(context);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">manager_handle_lock</span><span class="params">(<span class="keyword">struct</span> wl_client *client,</span></span><br><span class="line"><span class="params"> <span class="keyword">struct</span> wl_resource *manager_resource,</span></span><br><span class="line"><span class="params"> <span class="type">uint32_t</span> id)</span></span><br><span class="line">{</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_manager_v1</span> *<span class="title">manager</span> =</span></span><br><span class="line"> static_cast<ext_session_lock_manager_v1 *>(wl_resource_get_user_data(manager_resource));</span><br><span class="line"></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_resource</span> *<span class="title">resource</span> =</span> wl_resource_create(client,</span><br><span class="line"> &ext_session_lock_v1_interface,</span><br><span class="line"> EXT_SESSION_LOCK_V1_DESTROY_SINCE_VERSION,</span><br><span class="line"> id);</span><br><span class="line"> <span class="keyword">if</span> (resource == <span class="literal">NULL</span>) {</span><br><span class="line"> wl_resource_post_no_memory(manager_resource);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_v1</span> *<span class="title">context</span> =</span></span><br><span class="line"> static_cast<ext_session_lock_v1 *>(<span class="built_in">calloc</span>(<span class="number">1</span>, <span class="keyword">sizeof</span>(*context)));</span><br><span class="line"> <span class="keyword">if</span> (context == <span class="literal">NULL</span>) {</span><br><span class="line"> wl_resource_post_no_memory(manager_resource);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> wl_resource_set_implementation(resource,</span><br><span class="line"> &lock_implementation,</span><br><span class="line"> context,</span><br><span class="line"> ext_session_lock_v1_destroy_func);</span><br><span class="line"> wl_resource_set_user_data(resource, context);</span><br><span class="line"></span><br><span class="line"> wl_signal_init(&context->events.get_lock_surface);</span><br><span class="line"> wl_signal_init(&context->events.unlock_and_destroy);</span><br><span class="line"> wl_signal_init(&context->events.destroy);</span><br><span class="line"></span><br><span class="line"> context->resource = resource;</span><br><span class="line"> context->id = id;</span><br><span class="line"> wl_list_init(&context->contexts);</span><br><span class="line"> wl_list_insert(&manager->contexts, wl_resource_get_link(resource));</span><br><span class="line"></span><br><span class="line"> wl_signal_emit_mutable(&manager->events.lock, context);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_manager_v1_interface</span> <span class="title">lock_manager_implementation</span> =</span> {</span><br><span class="line"> .destroy = manager_handle_destroy,</span><br><span class="line"> .lock = manager_handle_lock,</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">bind_ext_session_lock_manager_v1</span><span class="params">(<span class="keyword">struct</span> wl_client *client,</span></span><br><span class="line"><span class="params"> <span class="type">void</span> *data,</span></span><br><span class="line"><span class="params"> <span class="type">uint32_t</span> version,</span></span><br><span class="line"><span class="params"> <span class="type">uint32_t</span> id)</span></span><br><span class="line">{</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_manager_v1</span> *<span class="title">manager</span> =</span></span><br><span class="line"> static_cast<<span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_manager_v1</span> *></span>(data);</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_resource</span> *<span class="title">resource</span> =</span></span><br><span class="line"> wl_resource_create(client, &ext_session_lock_manager_v1_interface, version, id);</span><br><span class="line"> <span class="keyword">if</span> (!resource) {</span><br><span class="line"> wl_client_post_no_memory(client);</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> wl_resource_set_implementation(resource, &lock_manager_implementation, manager, <span class="literal">NULL</span>);</span><br><span class="line"></span><br><span class="line"> wl_list_insert(&manager->contexts, wl_resource_get_link(resource));</span><br><span class="line"></span><br><span class="line"> manager->client = resource;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">handle_display_destroy</span><span class="params">(<span class="keyword">struct</span> wl_listener *listener, [[maybe_unused]] <span class="type">void</span> *data)</span></span><br><span class="line">{</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_manager_v1</span> *<span class="title">manager</span> =</span></span><br><span class="line"> wl_container_of(listener, manager, display_destroy);</span><br><span class="line"> wl_signal_emit_mutable(&manager->events.destroy, manager);</span><br><span class="line"> wl_list_remove(&manager->display_destroy.link);</span><br><span class="line"> wl_global_destroy(manager->global);</span><br><span class="line"> <span class="built_in">free</span>(manager);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> SESSION_LOCK_MANAGEMENT_V1_VERSION 1</span></span><br><span class="line"></span><br><span class="line">ext_session_lock_manager_v1 *<span class="title function_">ext_session_lock_manager_v1_create</span><span class="params">(wl_display *display)</span></span><br><span class="line">{</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_manager_v1</span> *<span class="title">manager</span> =</span></span><br><span class="line"> static_cast<<span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_manager_v1</span> *></span>(<span class="built_in">calloc</span>(<span class="number">1</span>, <span class="keyword">sizeof</span>(*manager)));</span><br><span class="line"> <span class="keyword">if</span> (!manager) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> manager->event_loop = wl_display_get_event_loop(display);</span><br><span class="line"> manager->global = wl_global_create(display,</span><br><span class="line"> &ext_session_lock_manager_v1_interface,</span><br><span class="line"> SESSION_LOCK_MANAGEMENT_V1_VERSION,</span><br><span class="line"> manager,</span><br><span class="line"> bind_ext_session_lock_manager_v1);</span><br><span class="line"> <span class="keyword">if</span> (!manager->global) {</span><br><span class="line"> <span class="built_in">free</span>(manager);</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">NULL</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> wl_signal_init(&manager->events.lock);</span><br><span class="line"> wl_signal_init(&manager->events.destroy);</span><br><span class="line"> wl_list_init(&manager->contexts);</span><br><span class="line"></span><br><span class="line"> manager->display_destroy.notify = handle_display_destroy;</span><br><span class="line"> wl_display_add_destroy_listener(display, &manager->display_destroy);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> manager;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>协议的书写上面大同小异,其他协议均按照类似的代码方式进行了支持,如感兴趣,强烈建议参阅 <a class="link" href="https://gitlab.freedesktop.org/wlroots/wlroots/-/tree/0.17?ref_type=heads" >wlroots<i class="fas fa-external-link-alt"></i></a> 、weston、sway、mutter、kwin等项目的源码。<br><a name="Q6MUv"></a></p><h3 id="客户端调用"><a href="#客户端调用" class="headerlink" title="客户端调用"></a>客户端调用</h3><p>以 <a class="link" href="https://wayland.app/protocols/ext-session-lock-v1" >ext_session_lock_v1<i class="fas fa-external-link-alt"></i></a> 协议为例,客户端(例如锁屏程序)的实现如下:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 生成协议头文件</span></span><br><span class="line">wayland-scanner client-header ext-session-lock-v1.xml client.h</span><br><span class="line"><span class="comment"># 生成协议源文件(通过命令生成的代码,全是胶水代码)</span></span><br><span class="line">wayland-scanner code ext-session-lock-v1.xml client.c</span><br></pre></td></tr></table></figure><p>main文件内容如下:</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><wayland-client.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"client.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">example_data</span> {</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_display</span> *<span class="title">display</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_registry</span> *<span class="title">registry</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_compositor</span> *<span class="title">compositor</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_surface</span> *<span class="title">surface</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">wl_output</span> *<span class="title">output</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_manager_v1</span> *<span class="title">lock_manager</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_v1</span> *<span class="title">lock</span>;</span></span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_surface_v1</span> *<span class="title">lock_surface</span>;</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">on_locked</span><span class="params">(<span class="type">void</span> *data, <span class="keyword">struct</span> ext_session_lock_v1 *lock)</span> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Session successfully locked.\n"</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">on_configure</span><span class="params">(<span class="type">void</span> *data,</span></span><br><span class="line"><span class="params"> <span class="keyword">struct</span> ext_session_lock_surface_v1 *ext_session_lock_surface_v1,</span></span><br><span class="line"><span class="params"> <span class="type">uint32_t</span> serial,</span></span><br><span class="line"><span class="params"> <span class="type">uint32_t</span> width,</span></span><br><span class="line"><span class="params"> <span class="type">uint32_t</span> height)</span> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Received configure event, send ack_configure back\n"</span>);</span><br><span class="line"> ext_session_lock_surface_v1_ack_configure(ext_session_lock_surface_v1, serial);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_v1_listener</span> <span class="title">lock_listener</span> =</span> {</span><br><span class="line"> on_locked</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">ext_session_lock_surface_v1_listener</span> <span class="title">lock_surface_listener</span> =</span> {</span><br><span class="line"> on_configure</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">registry_handle_global</span><span class="params">(<span class="type">void</span> *data, <span class="keyword">struct</span> wl_registry *registry, <span class="type">uint32_t</span> id,</span></span><br><span class="line"><span class="params"> <span class="type">const</span> <span class="type">char</span> *interface, <span class="type">uint32_t</span> version)</span> {</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">example_data</span> *<span class="title">example_data</span> =</span> data;</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">strcmp</span>(interface, <span class="string">"ext_session_lock_manager_v1"</span>) == <span class="number">0</span>) {</span><br><span class="line"> example_data->lock_manager = wl_registry_bind(registry, id, &ext_session_lock_manager_v1_interface, <span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">strcmp</span>(interface, <span class="string">"wl_compositor"</span>) == <span class="number">0</span>) {</span><br><span class="line"> example_data->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, <span class="number">1</span>);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Got wl_compositor\n"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">strcmp</span>(interface, <span class="string">"wl_output"</span>) == <span class="number">0</span>) {</span><br><span class="line"> example_data->output = wl_registry_bind(registry, id, &wl_output_interface, version);</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Got wl_output\n"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">static</span> <span class="type">const</span> <span class="class"><span class="keyword">struct</span> <span class="title">wl_registry_listener</span> <span class="title">registry_listener</span> =</span> {</span><br><span class="line"> registry_handle_global,</span><br><span class="line"> <span class="literal">NULL</span></span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> **argv)</span> {</span><br><span class="line"> <span class="class"><span class="keyword">struct</span> <span class="title">example_data</span> <span class="title">data</span>;</span></span><br><span class="line"></span><br><span class="line"> data.lock = <span class="literal">NULL</span>;</span><br><span class="line"></span><br><span class="line"> data.display = wl_display_connect(<span class="literal">NULL</span>);</span><br><span class="line"> <span class="keyword">if</span> (!data.display) {</span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"Failed to connect to Wayland display.\n"</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Get registry</span></span><br><span class="line"> data.registry = wl_display_get_registry(data.display);</span><br><span class="line"> wl_registry_add_listener(data.registry, &registry_listener, &data);</span><br><span class="line"> wl_display_roundtrip(data.display);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (!data.lock_manager || !data.compositor || !data.output) {</span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"Required interfaces not available\n"</span>);</span><br><span class="line"> wl_registry_destroy(data.registry);</span><br><span class="line"> wl_display_disconnect(data.display);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Request lock</span></span><br><span class="line"> data.lock = ext_session_lock_manager_v1_lock(data.lock_manager);</span><br><span class="line"> ext_session_lock_v1_add_listener(data.lock, &lock_listener, &data);</span><br><span class="line"> wl_display_roundtrip(data.display);</span><br><span class="line"> <span class="keyword">if</span> (!data.lock) {</span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"Required interfaces: lock not available\n"</span>);</span><br><span class="line"> wl_registry_destroy(data.registry);</span><br><span class="line"> wl_display_disconnect(data.display);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Request destroy</span></span><br><span class="line"> <span class="comment">// ext_session_lock_manager_v1_destroy(data.lock);</span></span><br><span class="line"> <span class="comment">// wl_display_roundtrip(data.display);</span></span><br><span class="line"></span><br><span class="line"> <span class="comment">// // Wait for events</span></span><br><span class="line"> <span class="comment">// while (wl_display_dispatch(data.display) != -1) {</span></span><br><span class="line"> <span class="comment">// // Handle events</span></span><br><span class="line"> <span class="comment">// }</span></span><br><span class="line"> <span class="comment">// return 0;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">// Create surface</span></span><br><span class="line"> data.surface = wl_compositor_create_surface(data.compositor);</span><br><span class="line"> <span class="keyword">if</span> (!data.surface) {</span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"Failed to create wl_surface\n"</span>);</span><br><span class="line"> wl_registry_destroy(data.registry);</span><br><span class="line"> wl_display_disconnect(data.display);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Request get_lock_surface</span></span><br><span class="line"> data.lock_surface = ext_session_lock_v1_get_lock_surface(data.lock, data.surface, data.output);</span><br><span class="line"> ext_session_lock_surface_v1_add_listener(data.lock_surface, &lock_surface_listener, &data);</span><br><span class="line"> wl_display_roundtrip(data.display);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">// Request unlock_and_destroy</span></span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"Start Unlock\n"</span>);</span><br><span class="line"> ext_session_lock_v1_unlock_and_destroy(data.lock);</span><br><span class="line"> wl_display_roundtrip(data.display);</span><br><span class="line"> <span class="built_in">fprintf</span>(<span class="built_in">stderr</span>, <span class="string">"Unlock success\n"</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Wait for events</span></span><br><span class="line"> <span class="keyword">while</span> (wl_display_dispatch(data.display) != <span class="number">-1</span>) {</span><br><span class="line"> <span class="comment">// Handle events</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Cleanup</span></span><br><span class="line"> ext_session_lock_manager_v1_destroy(data.lock_manager);</span><br><span class="line"> wl_registry_destroy(data.registry);</span><br><span class="line"> wl_display_disconnect(data.display);</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>通过 <code>gcc -o client client.c main.c -lwayland-client</code>编译生成 client 二进制。<br />运行:注意在运行此二进制之前,需要指定其 WAYLAND_DISPLAY环境变量,这是由 Wayland 合成器决定的。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">export</span> WAYLAND_DISPLAY=wayland-0</span><br><span class="line">./client</span><br></pre></td></tr></table></figure><p>至此,我们已经完成了一个简单的客户端调用 Wayland 协议的 demo。在实际开发中,这些调用通常由各种开发库进行了封装。例如,libqtwayland 就是由 Qt 对部分 Wayland 协议的调用进行了封装,从而使得开发者在开发桌面应用时无需直接处理协议调用,只需使用 Qt 中已有的类和接口即可。</p><blockquote><p>// By A Way<br>A week 的合成器之旅达到 Ending,以后有时间再继续丰富.</p></blockquote><p><a name="Xir9t"></a></p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p><a class="link" href="https://wayland.freedesktop.org/" >https://wayland.freedesktop.org/<i class="fas fa-external-link-alt"></i></a><br /><a class="link" href="https://wayland.arktoria.org/index.html" >The Wayland Protocol 中文版<i class="fas fa-external-link-alt"></i></a></p>]]></content>
<summary type="html"><p>因工作需要加之个人比较感兴趣的原因,在实现 Wayland 合成器相关协议之途中,随笔记录记录一些相关的基础知识。</p></summary>
<category term="wayland" scheme="https://ssk-wh.github.io/tags/wayland/"/>
</entry>
<entry>
<title>Hexo博客本地部署</title>
<link href="https://ssk-wh.github.io/2024/05b59ef6f5.html"/>
<id>https://ssk-wh.github.io/2024/05b59ef6f5.html</id>
<published>2024-05-22T17:40:15.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<p>在本地快速预览博客部署效果,可按照此步骤操作。否则直接向源文件仓库中提交 md 文档即可。</p><span id="more"></span><h2 id="安装软件包"><a href="#安装软件包" class="headerlink" title="安装软件包"></a>安装软件包</h2><p><code>sudo apt install npm</code><br>uos系统中的默认版本有点问题,无法通过npm安装其他包(如果您的版本没问题,直接跳到下一下节),可按照 <a class="link" href="https://github.com/nodesource/distributions" >nodesource<i class="fas fa-external-link-alt"></i></a> 的 <a class="link" href="https://github.com/nodesource/distributions/blob/master/README.md" >README<i class="fas fa-external-link-alt"></i></a> 更新 nodejs.<br>或按照以下步骤(适合 Debian 系的 Linux 发行版):<br><code>sudo apt-get install -y curl</code><br><code>curl -fsSL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh</code><br><code>sudo -E bash nodesource_setup.sh</code><br><code>sudo apt-get install -y nodejs</code></p><p>安装成功后,通过 <code>node -v</code> 查看安装后的版本</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">> node -v</span><br><span class="line">v20.13.1</span><br></pre></td></tr></table></figure><h2 id="预览"><a href="#预览" class="headerlink" title="预览"></a>预览</h2><p><code>cd your_hexo_dir</code><br><code>npm install hexo</code><br>阿拉的电脑已经安装过了,所以安装结果如下:</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">> npm install hexo</span><br><span class="line">npm notice Beginning October 4, 2021, all connections to the npm registry - including <span class="keyword">for</span> package installation - must use TLS 1.2 or higher. You are currently using plaintext http to connect. Please visit the GitHub blog <span class="keyword">for</span> more information: https://github.blog/2021-08-23-npm-registry-deprecating-tls-1-0-tls-1-1/</span><br><span class="line">npm notice Beginning October 4, 2021, all connections to the npm registry - including <span class="keyword">for</span> package installation - must use TLS 1.2 or higher. You are currently using plaintext http to connect. Please visit the GitHub blog <span class="keyword">for</span> more information: https://github.blog/2021-08-23-npm-registry-deprecating-tls-1-0-tls-1-1/</span><br><span class="line"></span><br><span class="line">up to <span class="built_in">date</span> <span class="keyword">in</span> 2s</span><br><span class="line"></span><br><span class="line">22 packages are looking <span class="keyword">for</span> funding</span><br><span class="line"> run `npm fund` <span class="keyword">for</span> details</span><br></pre></td></tr></table></figure><p>此时正常情况下可以使用 <code>npm hexo server</code> 或 <code>npm run server</code> 查看预览效果</p><p>如果碰到 npm 不识别 hexo 命令的情况,请自行配置 npm 的环境变量,或者找到当前安装的 hexo 命令所在,一般在当前安装目录的 <code>node_modules/hexo/bin/</code> 下,之后执行即可,例如 <code>./node_modules/hexo/bin/hexo s</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line">uos@uos-PC ~ ./node_modules/hexo/bin/hexo s</span><br><span class="line">INFO Validating config</span><br><span class="line">INFO </span><br><span class="line">------------------------------------------</span><br><span class="line"> __ ___ _______ _______ .______</span><br><span class="line"> | |/ / | ____|| ____|| _ \</span><br><span class="line"> | <span class="string">' / | |__ | |__ | |_) |</span></span><br><span class="line"><span class="string"> | < | __| | __| | ___/</span></span><br><span class="line"><span class="string"> | . \ | |____ | |____ | |</span></span><br><span class="line"><span class="string"> |__|\__\ |_______||_______|| _|</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">------------------------------------------</span></span><br><span class="line"><span class="string">Keep version 4.1.2</span></span><br><span class="line"><span class="string">Documentation: https://keep-docs.xpoet.cn</span></span><br><span class="line"><span class="string">------------------------------------------</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">INFO Start processing</span></span><br><span class="line"><span class="string">INFO url_submission: Start generating url list...</span></span><br><span class="line"><span class="string">INFO url_submission: Page urls will generate into file named submit_url.txt</span></span><br><span class="line"><span class="string">INFO Hexo is running at http://localhost:4000/ . Press Ctrl+C to stop.</span></span><br></pre></td></tr></table></figure><p>之后在浏览器中访问 <code>[http://localhost:4000/]</code> 就可以看到预览效果了.</p><p>后期如果只是为了提交新文章,只需要 clone 对应的项目到本地,在 source/_posts 目录下新建文档即可。提交后由经由 github actions 自动部署并发布。</p><h2 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h2><p>npm 执行时提示不存在 package.json 文件,执行 <code>npm init</code> 进行初始化。再执行你要执行的操作,如 <code>npm install hexo</code><br>详情可参考<a class="link" href="https://blog.csdn.net/weixin_40161974/article/details/99441501" >https://blog.csdn.net/weixin_40161974/article/details/99441501<i class="fas fa-external-link-alt"></i></a></p><h2 id="附录"><a href="#附录" class="headerlink" title="附录"></a>附录</h2><p><a class="link" href="https://hexo.io/zh-cn/docs/" >hexo官方说明<i class="fas fa-external-link-alt"></i></a></p>]]></content>
<summary type="html"><p>在本地快速预览博客部署效果,可按照此步骤操作。否则直接向源文件仓库中提交 md 文档即可。</p></summary>
<category term="Writing" scheme="https://ssk-wh.github.io/categories/Writing/"/>
<category term="hexo" scheme="https://ssk-wh.github.io/tags/hexo/"/>
<category term="npm" scheme="https://ssk-wh.github.io/tags/npm/"/>
<category term="nodejs" scheme="https://ssk-wh.github.io/tags/nodejs/"/>
</entry>
<entry>
<title>僵尸进程</title>
<link href="https://ssk-wh.github.io/2024/022a2a7853.html"/>
<id>https://ssk-wh.github.io/2024/022a2a7853.html</id>
<published>2024-02-22T22:30:31.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<p>僵尸进程是指一个子进程已经终止但其父进程尚未读取其终止状态的进程,导致其进程表项仍然保留在系统中。</p><span id="more"></span><h1 id="产生"><a href="#产生" class="headerlink" title="产生"></a>产生</h1><p>如果子进程先退出了,父进程还未结束并且没有调用 wait 或者 waitpid 函数获取子进程的状态信息,则子进程残留的状态信息( task_struct 结构和少量资源信息)会变成僵尸进程。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// gcc -o zombie zombie.c</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><unistd.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/wait.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span> {</span><br><span class="line"> <span class="type">pid_t</span> pid;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 创建子进程</span></span><br><span class="line"> pid = fork();</span><br><span class="line"> <span class="keyword">if</span> (pid < <span class="number">0</span>) {</span><br><span class="line"> <span class="comment">// fork失败</span></span><br><span class="line"> perror(<span class="string">"fork"</span>);</span><br><span class="line"> <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (pid == <span class="number">0</span>) {</span><br><span class="line"> <span class="comment">// 子进程</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Child process with PID: %d\n"</span>, getpid());</span><br><span class="line"> <span class="comment">// 子进程立即退出</span></span><br><span class="line"> <span class="built_in">exit</span>(EXIT_SUCCESS);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// 父进程</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Parent process with PID: %d, Child PID: %d\n"</span>, getpid(), pid);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 父进程继续执行其他任务,例如睡眠一段时间</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Parent process continue do something\n"</span>);</span><br><span class="line"> sleep(<span class="number">10</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>在终端中输入 <code>gcc -o zombie zombie.c</code> 进行编译,之后运行 <code>./zombie</code> 进程。此时通过 <code>ps -ef | grep zombie</code> 可以看到 fork 后的子进程变为僵尸进程。</p><p><img lazyload alt="image" data-src="/2024/022a2a7853/1.png" ></p><h1 id="预防"><a href="#预防" class="headerlink" title="预防"></a>预防</h1><p>结合其产生的原因,在父进程中使用 wait 回收子进程残留的进程资源。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// gcc -o zombie zombie.c</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><unistd.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/wait.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span> {</span><br><span class="line"> <span class="type">pid_t</span> pid;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 创建子进程</span></span><br><span class="line"> pid = fork();</span><br><span class="line"> <span class="keyword">if</span> (pid < <span class="number">0</span>) {</span><br><span class="line"> <span class="comment">// fork失败</span></span><br><span class="line"> perror(<span class="string">"fork"</span>);</span><br><span class="line"> <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (pid == <span class="number">0</span>) {</span><br><span class="line"> <span class="comment">// 子进程</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Child process with PID: %d\n"</span>, getpid());</span><br><span class="line"> <span class="comment">// 子进程立即退出</span></span><br><span class="line"> <span class="built_in">exit</span>(EXIT_SUCCESS);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// 父进程</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Parent process with PID: %d, Child PID: %d\n"</span>, getpid(), pid);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 父进程等待子进程结束</span></span><br><span class="line"> <span class="type">int</span> status;</span><br><span class="line"> <span class="type">pid_t</span> wpid = wait(&status);</span><br><span class="line"> <span class="keyword">if</span> (wpid == <span class="number">-1</span>) {</span><br><span class="line"> perror(<span class="string">"wait"</span>);</span><br><span class="line"> <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 检查子进程的退出状态</span></span><br><span class="line"> <span class="keyword">if</span> (WIFEXITED(status)) {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Child process exited with status %d\n"</span>, WEXITSTATUS(status));</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Child process terminated by signal %d\n"</span>, WTERMSIG(status));</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 父进程继续执行其他任务,例如睡眠一段时间</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Parent process continue do something\n"</span>);</span><br><span class="line"> sleep(<span class="number">10</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><img lazyload alt="image" data-src="/2024/022a2a7853/2.png" ></p><p>当一个子进程结束时,内核会向其父进程发送SIGCHLD信号。父进程可以通过捕获这个信号并在信号处理函数中调用wait()或waitpid()来回收子进程的资源,从而避免僵尸进程的产生。<br>这种方式也优雅一些。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// gcc -o zombie zombie.c</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdio.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><stdlib.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><unistd.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/types.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><sys/wait.h></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><signal.h></span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 信号处理函数</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">sigchld_handler</span><span class="params">(<span class="type">int</span> signum)</span> {</span><br><span class="line"> <span class="comment">// 这里可以添加一些日志记录或其他处理</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"SIGCHLD signal received, cleaning up child processes.\n"</span>);</span><br><span class="line"> <span class="comment">// 等待所有子进程结束</span></span><br><span class="line"> <span class="keyword">while</span> (waitpid(<span class="number">-1</span>, <span class="literal">NULL</span>, WNOHANG) > <span class="number">0</span>); <span class="comment">// WNOHANG选项使得waitpid不会阻塞</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span> {</span><br><span class="line"> <span class="comment">// 设置信号处理函数</span></span><br><span class="line"> signal(SIGCHLD, sigchld_handler);</span><br><span class="line"></span><br><span class="line"> <span class="type">pid_t</span> pid;</span><br><span class="line"> <span class="comment">// 创建子进程</span></span><br><span class="line"> pid = fork();</span><br><span class="line"> <span class="keyword">if</span> (pid < <span class="number">0</span>) {</span><br><span class="line"> perror(<span class="string">"fork"</span>);</span><br><span class="line"> <span class="built_in">exit</span>(EXIT_FAILURE);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (pid == <span class="number">0</span>) {</span><br><span class="line"> <span class="comment">// 子进程</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Child process with PID: %d\n"</span>, getpid());</span><br><span class="line"> sleep(<span class="number">5</span>); <span class="comment">// 模拟子进程执行操作</span></span><br><span class="line"> <span class="built_in">exit</span>(EXIT_SUCCESS);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="comment">// 父进程</span></span><br><span class="line"> <span class="built_in">printf</span>(<span class="string">"Parent process with PID: %d, Child PID: %d\n"</span>, getpid(), pid);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 父进程继续执行其他任务</span></span><br><span class="line"> sleep(<span class="number">10</span>);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 父进程结束前,子进程可能已经结束,信号处理函数会处理SIGCHLD信号</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><p>僵尸进程是指一个子进程已经终止但其父进程尚未读取其终止状态的进程,导致其进程表项仍然保留在系统中。</p></summary>
<category term="Linux" scheme="https://ssk-wh.github.io/categories/Linux/"/>
<category term="C" scheme="https://ssk-wh.github.io/tags/C/"/>
</entry>
<entry>
<title>性能分析-火焰图</title>
<link href="https://ssk-wh.github.io/2024/029209f875.html"/>
<id>https://ssk-wh.github.io/2024/029209f875.html</id>
<published>2024-02-19T22:13:46.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<h1 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h1><p>火焰图是一种可视化工具,用于直观地展示程序的性能瓶颈和函数调用层次。它通过图形化展示函数调用栈,使得用户可以轻松地识别性能瓶颈和分析程序的性能特征。<br>在Linux系统中,使用火焰图通常需要使用工具如 FlameGraph 和 <strong>perf</strong> 来生成和分析火焰图。</p><blockquote><p>使用比较简单,按照下面的步骤固定操作即可</p></blockquote><h1 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h1><p>安装 perf 和 FlameGraph 工具</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get install linux-base</span><br><span class="line"><span class="comment"># 因为我的内核版本是4.19,所以安装的是linux-perf-4.19</span></span><br><span class="line">sudo apt-get install linux-perf-4.19</span><br><span class="line"></span><br><span class="line"><span class="comment"># 安装 FlameGraph,用于将 perf 采集的数据生成火焰图</span></span><br><span class="line">git <span class="built_in">clone</span> https://github.com/brendangregg/FlameGraph.git</span><br></pre></td></tr></table></figure><h1 id="采集"><a href="#采集" class="headerlink" title="采集"></a>采集</h1><p><code>perf record -F 99 -g -p <pid_or_command></code><br><code>perf record -F 99 -g <command></code></p><p><code>perf script | ./FlameGraph/stackcollapse-perf.pl > out.folded</code></p><p><code>./FlameGraph/flamegraph.pl out.folded > output.svg</code></p>]]></content>
<summary type="html"><h1 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h1><p>火焰图是一种可视化工具,用于直观地展示程序的性能瓶颈和函数调用层次。它通过图形化展示函数调用栈,使得用户可以轻松地识别性能瓶颈和分析程序的性</summary>
<category term="Linux" scheme="https://ssk-wh.github.io/categories/Linux/"/>
<category term="性能分析" scheme="https://ssk-wh.github.io/tags/%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90/"/>
<category term="火焰图" scheme="https://ssk-wh.github.io/tags/%E7%81%AB%E7%84%B0%E5%9B%BE/"/>
</entry>
<entry>
<title>软件包依赖关系分析工具</title>
<link href="https://ssk-wh.github.io/2024/01685f950a.html"/>
<id>https://ssk-wh.github.io/2024/01685f950a.html</id>
<published>2024-01-31T00:00:00.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><p>通过 apt 命令分析系统中安装的软件包的依赖关系,生成符合 mermaid 语法的配置文件,再通过 dot 命令生成 svg 图。</p><h2 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h2><p>确保电脑上安装了 dot 命令<br><code>sudo apt install graphviz</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#! /bin/bash</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Author: ssk-wh</span></span><br><span class="line"><span class="comment"># Date: 2024.01.29</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># @para: null</span></span><br><span class="line"><span class="comment"># 输出帮助信息</span></span><br><span class="line"><span class="keyword">function</span> <span class="function"><span class="title">print_usage</span></span>() {</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"Usage:</span></span><br><span class="line"><span class="string"> 用于分析软件包依赖的工具,最终在当前目录生成一张依赖关系图</span></span><br><span class="line"><span class="string"> </span></span><br><span class="line"><span class="string"> -h 输出帮助手册</span></span><br><span class="line"><span class="string"> -a 输出所有已安装软件包的依赖关系 (不要用 -a 参数,生成的 svg 图恐怕没有电脑能流畅地查看)</span></span><br><span class="line"><span class="string"> -m : 对指定软件包进行mark,生成的svg图中会进行特殊标记</span></span><br><span class="line"><span class="string"> -d : 指定查找深度,默认不限制,仅当指定分析特定应用时生效,配合 -p 参数生效</span></span><br><span class="line"><span class="string"> -p : 分析指定软件包的被依赖关系图</span></span><br><span class="line"><span class="string"> </span></span><br><span class="line"><span class="string"> 用例:</span></span><br><span class="line"><span class="string"> 分析dde-dock的被依赖关系图,递归查找深度为2,如果存在startdde,就加个颜色标记</span></span><br><span class="line"><span class="string"> generate_rdepends.sh -p dde-dock -d 2 -m startdde</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string"> 分析所有已安装软件包的依赖关系</span></span><br><span class="line"><span class="string"> generate_rdepends.sh -a"</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">rdepends_file=<span class="string">"/tmp/rdepends.tmp"</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># @para:file 目标文件</span></span><br><span class="line"><span class="comment"># @para: text 传入的内容</span></span><br><span class="line"><span class="comment"># 将内容以追加的方式写入文件中</span></span><br><span class="line"><span class="comment"># @example: write_to_file "/tmp/tmp.file" "write strings"</span></span><br><span class="line"><span class="keyword">function</span> <span class="function"><span class="title">write_to_file</span></span>() {</span><br><span class="line"> <span class="built_in">local</span> _dest_file=<span class="variable">$1</span></span><br><span class="line"> <span class="built_in">local</span> _write_string=<span class="variable">$2</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="variable">$_write_string</span> >> <span class="variable">$_dest_file</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment"># @para:null</span></span><br><span class="line"><span class="comment"># 获取已安装软件包列表,返回一个数组</span></span><br><span class="line"><span class="keyword">function</span> <span class="function"><span class="title">get_installed_packages</span></span>() {</span><br><span class="line"> <span class="built_in">local</span> _packages=() <span class="comment"># 定义空数组存储软件包名称</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 使用 dpkg -l 命令获取已安装软件包列表,提取软件包名称并添加到数组中(排除带dbgsym或者dev的包)</span></span><br><span class="line"> <span class="built_in">mapfile</span> -t _packages < <(dpkg -l | grep -vi <span class="string">"dbgsym"</span>| awk <span class="string">'/^ii/ {print $2}'</span>)</span><br><span class="line"></span><br><span class="line"> <span class="comment"># 返回软件包名称数组</span></span><br><span class="line"> <span class="built_in">printf</span> <span class="string">'%s\n'</span> <span class="string">"<span class="variable">${_packages[@]}</span>"</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># @para: package 软件包名</span></span><br><span class="line"><span class="comment"># 分析此软件包被哪些软件包所依赖,返回一组包名列表(仅统计系统中安装的应用)</span></span><br><span class="line"><span class="comment"># @example: get_package_rdepends "dde-dock" </span></span><br><span class="line"><span class="keyword">function</span> <span class="function"><span class="title">get_package_rdepends</span></span>() {</span><br><span class="line"> <span class="built_in">local</span> _package=<span class="variable">$1</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">local</span> _limit_packages=($(get_installed_packages))</span><br><span class="line"> <span class="comment"># echo "系统中安装的应用列表:"</span></span><br><span class="line"> <span class="comment"># printf '%s\n' "${_limit_packages[@]}"</span></span><br><span class="line"></span><br><span class="line"> command_output=$(apt rdepends <span class="variable">$_package</span>)</span><br><span class="line"></span><br><span class="line"> output_list=()</span><br><span class="line"> <span class="keyword">while</span> IFS= <span class="built_in">read</span> -r line; <span class="keyword">do</span></span><br><span class="line"> <span class="comment"># echo "line:" $line</span></span><br><span class="line"> <span class="comment"># 分析包含"依赖"的行</span></span><br><span class="line"> <span class="keyword">if</span> [[ <span class="string">"<span class="variable">$line</span>"</span> == *<span class="string">"依赖: "</span>* ]]; <span class="keyword">then</span></span><br><span class="line"> output_string=<span class="string">"<span class="variable">${line/依赖: /}</span>"</span></span><br><span class="line"> <span class="comment"># 去掉竖线</span></span><br><span class="line"> output_string=$(<span class="built_in">echo</span> <span class="string">"<span class="variable">$output_string</span>"</span> | <span class="built_in">tr</span> -d <span class="string">'|'</span>)</span><br><span class="line"> <span class="comment"># 去掉版本信息</span></span><br><span class="line"> <span class="keyword">while</span> [[ <span class="variable">$output_string</span> == *<span class="string">'('</span>* && <span class="variable">$output_string</span> == *<span class="string">')'</span>* ]]; <span class="keyword">do</span></span><br><span class="line"> output_string=<span class="string">"<span class="variable">${output_string%%(*}</span><span class="variable">${output_string#*)}</span>"</span></span><br><span class="line"> <span class="keyword">done</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 去除空格</span></span><br><span class="line"> output_string=$(<span class="built_in">echo</span> <span class="string">"<span class="variable">$output_string</span>"</span> | sed <span class="string">'s/ //g'</span>)</span><br><span class="line"> <span class="keyword">if</span> ! [[ <span class="string">" <span class="variable">${_limit_packages[*]}</span> "</span> == *<span class="string">"<span class="variable">$output_string</span>"</span>* ]]; <span class="keyword">then</span></span><br><span class="line"> <span class="comment"># "未安装的软件包,忽略"</span></span><br><span class="line"> <span class="comment"># echo "@@@"</span></span><br><span class="line"> <span class="built_in">continue</span>;</span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 将结果添加到列表中(如果列表中不存在相同的内容)</span></span><br><span class="line"> <span class="keyword">if</span> ! [[ <span class="string">" <span class="variable">${output_list[@]}</span> "</span> =~ <span class="string">" <span class="variable">$output_string</span> "</span> ]]; <span class="keyword">then</span></span><br><span class="line"> output_list+=(<span class="string">"<span class="variable">$output_string</span>"</span>)</span><br><span class="line"> <span class="comment"># echo "###" $output_string</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">done</span> <<< <span class="string">"<span class="variable">$command_output</span>"</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="variable">${output_list[@]}</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查过的软件包都记录下,避免重复查询</span></span><br><span class="line">used_package_list=()</span><br><span class="line"><span class="comment"># 记录当前查询深度</span></span><br><span class="line">depth=1</span><br><span class="line"></span><br><span class="line"><span class="comment"># @para: package 软件包名</span></span><br><span class="line"><span class="comment"># @para: package_rdepends_list 包名列表</span></span><br><span class="line"><span class="comment"># 递归函数:分析此软件包和package_rdepends_list中的包名间的被依赖关系,层层查找,将内容输出到配置文件中</span></span><br><span class="line"><span class="comment"># @example: generate_package_digraph "dde-dock" $package_list</span></span><br><span class="line"><span class="keyword">function</span> <span class="function"><span class="title">generate_package_digraph</span></span>() {</span><br><span class="line"> <span class="built_in">local</span> _package=<span class="variable">$1</span></span><br><span class="line"> <span class="built_in">local</span> _depth=<span class="variable">$2</span></span><br><span class="line"> <span class="built_in">local</span> _package_mark=<span class="variable">$3</span></span><br><span class="line"> <span class="built_in">shift</span></span><br><span class="line"> <span class="built_in">shift</span></span><br><span class="line"> <span class="built_in">shift</span> <span class="comment"># 将参数向左移动一个位置以获得数组</span></span><br><span class="line"> <span class="built_in">local</span> _package_rdepends_list=(<span class="string">"<span class="variable">$@</span>"</span>) <span class="comment"># 获取移动后的参数列表</span></span><br><span class="line"> </span><br><span class="line"> depth=$((depth + <span class="number">1</span>))</span><br><span class="line"> <span class="keyword">if</span> [ <span class="string">"<span class="variable">$_depth</span>"</span> -ne -1 ] && [ <span class="string">"<span class="variable">$depth</span>"</span> -gt <span class="variable">$_depth</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"^^^ 超出最大查询深度: <span class="variable">$_depth</span>"</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="comment"># 已经进行过rdenpeds操作的包记录一下,避免重复统计</span></span><br><span class="line"> <span class="keyword">if</span> ! [[ <span class="string">" <span class="variable">${used_package_list[@]}</span> "</span> =~ <span class="string">" <span class="variable">$_package</span> "</span> ]]; <span class="keyword">then</span></span><br><span class="line"> used_package_list+=(<span class="string">"<span class="variable">$_package</span>"</span>)</span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 获取数组的大小</span></span><br><span class="line"> array_size=<span class="string">"<span class="variable">${#_package_rdepends_list[@]}</span>"</span></span><br><span class="line"> <span class="comment"># 判断数组是否为空并进行相应操作</span></span><br><span class="line"> <span class="keyword">if</span> [[ <span class="variable">$array_size</span> -ne 0 ]]; <span class="keyword">then</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"== 正在生成软件包的依赖数据:"</span> <span class="variable">$_package</span> <span class="string">"被依赖软件包列表数量:"</span> <span class="variable">$array_size</span></span><br><span class="line"> <span class="comment"># echo " depth:" $depth</span></span><br><span class="line"> <span class="comment"># 遍历列表并输出每个字符串</span></span><br><span class="line"> <span class="keyword">for</span> rdepends_package <span class="keyword">in</span> <span class="string">"<span class="variable">${_package_rdepends_list[@]}</span>"</span>; <span class="keyword">do</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">" handle package:"</span> <span class="variable">$rdepends_package</span></span><br><span class="line"> <span class="keyword">if</span> [[ <span class="string">"<span class="variable">$rdepends_package</span>"</span> == <span class="string">"<span class="variable">$_package_mark</span>"</span> ]]; <span class="keyword">then</span></span><br><span class="line"> write_to_file <span class="variable">$rdepends_file</span> <span class="string">" node [shape=box,style=filled,color=\".7 .3 1.0\"];"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> write_to_file <span class="variable">$rdepends_file</span> <span class="string">" \"<span class="variable">$_package</span>\"->\"<span class="variable">$rdepends_package</span>\";"</span></span><br><span class="line"> <span class="keyword">if</span> [[ <span class="string">"<span class="variable">$rdepends_package</span>"</span> == <span class="string">"<span class="variable">$_package_mark</span>"</span> ]]; <span class="keyword">then</span></span><br><span class="line"> write_to_file <span class="variable">$rdepends_file</span> <span class="string">" node [shape=\"\", style=\"\", color=\"\"];"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> <span class="keyword">done</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 递归一遍</span></span><br><span class="line"> <span class="keyword">for</span> rdepends_package <span class="keyword">in</span> <span class="string">"<span class="variable">${_package_rdepends_list[@]}</span>"</span>; <span class="keyword">do</span></span><br><span class="line"> new_package_rdepends_list=($(get_package_rdepends <span class="string">"<span class="variable">$rdepends_package</span>"</span>))</span><br><span class="line"> generate_package_digraph <span class="string">"<span class="variable">$rdepends_package</span>"</span> <span class="string">"<span class="variable">$_depth</span>"</span> <span class="string">"<span class="variable">$_package_mark</span>"</span> <span class="variable">${new_package_rdepends_list[@]}</span></span><br><span class="line"> <span class="keyword">done</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"已查询过,忽略本次查询"</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"> depth=$((depth - <span class="number">1</span>))</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment"># 生成所有安装应用的的依赖关系图</span></span><br><span class="line"><span class="keyword">function</span> <span class="function"><span class="title">generate_all</span></span>() {</span><br><span class="line"> <span class="built_in">local</span> _package_mark=<span class="variable">$1</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment"># 1\清除旧的配置文件</span></span><br><span class="line"> <span class="built_in">rm</span> -f <span class="variable">$rdepends_file</span></span><br><span class="line"> <span class="built_in">touch</span> <span class="variable">$rdepends_file</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 2\生成head部分内容</span></span><br><span class="line"> write_to_file <span class="variable">$rdepends_file</span> <span class="string">"digraph basicGraph {"</span></span><br><span class="line"> write_to_file <span class="variable">$rdepends_file</span> <span class="string">"rankdir = LR "</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 3\逐个遍历已安装的应用</span></span><br><span class="line"> _installed_packages=($(get_installed_packages))</span><br><span class="line"> <span class="keyword">for</span> package <span class="keyword">in</span> <span class="string">"<span class="variable">${_installed_packages[@]}</span>"</span>; <span class="keyword">do</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"handle package:"</span> <span class="variable">$package</span></span><br><span class="line"> _rdepends_list=($(get_package_rdepends <span class="variable">$package</span>))</span><br><span class="line"> <span class="keyword">for</span> rdepends_package <span class="keyword">in</span> <span class="string">"<span class="variable">${_rdepends_list[@]}</span>"</span>; <span class="keyword">do</span></span><br><span class="line"> write_to_file <span class="variable">$rdepends_file</span> <span class="string">" \"<span class="variable">$package</span>\"->\"<span class="variable">$rdepends_package</span>\";"</span></span><br><span class="line"> <span class="keyword">done</span></span><br><span class="line"> <span class="keyword">done</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 4\生成foot部分内容</span></span><br><span class="line"> write_to_file <span class="variable">$rdepends_file</span> <span class="string">"}"</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 5\将配置文件转换为svg图片</span></span><br><span class="line"> dot -Tsvg <span class="variable">$rdepends_file</span> -o rdepends.svg</span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"done"</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment"># 生成指定包的关系图</span></span><br><span class="line"><span class="keyword">function</span> <span class="function"><span class="title">generate_by_package</span></span>() {</span><br><span class="line"> <span class="built_in">local</span> _package=<span class="variable">$1</span></span><br><span class="line"> <span class="built_in">local</span> _depth=<span class="variable">$2</span></span><br><span class="line"> <span class="built_in">local</span> _package_mark=<span class="variable">$3</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 1\清除旧的配置文件</span></span><br><span class="line"> <span class="built_in">rm</span> -f <span class="variable">$rdepends_file</span></span><br><span class="line"> <span class="built_in">touch</span> <span class="variable">$rdepends_file</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 2\生成head部分内容</span></span><br><span class="line"> write_to_file <span class="variable">$rdepends_file</span> <span class="string">"digraph basicGraph {"</span></span><br><span class="line"> write_to_file <span class="variable">$rdepends_file</span> <span class="string">"rankdir = LR "</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"开始查找软件包的被依赖关系:"</span> <span class="variable">$_package</span></span><br><span class="line"> <span class="comment"># package_rdepends_list=($(get_package_rdepends "$_package" "$_installed_packages"))</span></span><br><span class="line"> <span class="comment"># printf '%s\n' "${package_rdepends_list[@]}"</span></span><br><span class="line"> <span class="comment"># exit 0</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 3\开始查询</span></span><br><span class="line"> <span class="comment"># 查找被哪些包依赖,在递归这些被依赖的包又被哪些包依赖,递归一次层深加1,可以通过 -d 参数指定查询深度</span></span><br><span class="line"> <span class="comment"># bash的第一个小坑,取list要加括号 </span></span><br><span class="line"> package_rdepends_list=($(get_package_rdepends <span class="string">"<span class="variable">$_package</span>"</span>))</span><br><span class="line"> <span class="comment"># bash的第二个小坑,不要传入一个空的参数,会其他后面的参数受到影响</span></span><br><span class="line"> generate_package_digraph <span class="string">"<span class="variable">$_package</span>"</span> <span class="string">"<span class="variable">$_depth</span>"</span> <span class="string">"<span class="variable">$_package_mark</span>"</span> <span class="string">"<span class="variable">${package_rdepends_list[@]}</span>"</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 4\生成foot部分内容</span></span><br><span class="line"> write_to_file <span class="variable">$rdepends_file</span> <span class="string">"}"</span></span><br><span class="line"></span><br><span class="line"> <span class="comment"># 5\将配置文件转换为svg图片</span></span><br><span class="line"> dot -Tsvg <span class="variable">$rdepends_file</span> -o <span class="variable">$_package</span><span class="string">".svg"</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"done"</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">################################################ start ################################################</span></span><br><span class="line"></span><br><span class="line">option_mark=<span class="string">"dde"</span></span><br><span class="line">option_depth=-1</span><br><span class="line">option_package=<span class="string">""</span></span><br><span class="line"></span><br><span class="line">option_mark_set=<span class="literal">false</span></span><br><span class="line">option_all_set=<span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 解析命令行参数</span></span><br><span class="line"><span class="keyword">while</span> <span class="built_in">getopts</span> <span class="string">":am:d:p:h"</span> opt; <span class="keyword">do</span></span><br><span class="line"> <span class="keyword">case</span> <span class="variable">$opt</span> <span class="keyword">in</span></span><br><span class="line"> a)</span><br><span class="line"> option_all_set=<span class="literal">true</span></span><br><span class="line"> ;;</span><br><span class="line"> m)</span><br><span class="line"> option_mark=<span class="string">"<span class="variable">$OPTARG</span>"</span></span><br><span class="line"> option_mark_set=<span class="literal">true</span></span><br><span class="line"> ;;</span><br><span class="line"> d)</span><br><span class="line"> option_depth=<span class="string">"<span class="variable">$OPTARG</span>"</span></span><br><span class="line"> ;;</span><br><span class="line"> p)</span><br><span class="line"> option_package=<span class="string">"<span class="variable">$OPTARG</span>"</span></span><br><span class="line"> ;;</span><br><span class="line"> h)</span><br><span class="line"> print_usage</span><br><span class="line"> <span class="built_in">exit</span> 0</span><br><span class="line"> ;;</span><br><span class="line"> \?)</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"Invalid option: -<span class="variable">$OPTARG</span>"</span></span><br><span class="line"> <span class="built_in">exit</span> 1</span><br><span class="line"> ;;</span><br><span class="line"> :)</span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"Option -<span class="variable">$OPTARG</span> requires an argument."</span></span><br><span class="line"> <span class="built_in">exit</span> 1</span><br><span class="line"> ;;</span><br><span class="line"> <span class="keyword">esac</span></span><br><span class="line"><span class="keyword">done</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># -a 则分析所有已安装软件包的依赖关系</span></span><br><span class="line"><span class="keyword">if</span> <span class="variable">$option_all_set</span>; <span class="keyword">then</span></span><br><span class="line"> <span class="comment"># 默认mark dde项目</span></span><br><span class="line"> generate_all <span class="variable">$option_mark</span></span><br><span class="line"> <span class="built_in">exit</span> 0</span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 指定的软件包名不为空,分析此软件包的被依赖关系</span></span><br><span class="line"><span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$option_package</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> <span class="keyword">if</span> ! <span class="variable">$option_mark_set</span>; <span class="keyword">then</span></span><br><span class="line"> <span class="comment"># 指定 -p 但未指定 -m,直接标记 -p 指向的软件包</span></span><br><span class="line"> option_mark=<span class="variable">$option_package</span></span><br><span class="line"> <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"package:"</span> <span class="variable">$option_package</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"depth:"</span> <span class="variable">$option_depth</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"mark:"</span> <span class="variable">$option_mark</span></span><br><span class="line"> generate_by_package <span class="variable">$option_package</span> <span class="variable">$option_depth</span> <span class="variable">$option_mark</span></span><br><span class="line"> <span class="built_in">exit</span> 0</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line"> print_usage</span><br><span class="line"> <span class="built_in">exit</span> 0</span><br><span class="line"><span class="keyword">fi</span></span><br></pre></td></tr></table></figure><h2 id="用法"><a href="#用法" class="headerlink" title="用法"></a>用法</h2><p>可以给上述脚本添加可执行权限,运行时添加 -h 参数可输出帮助信息。<br><code>chmod +x generate_rdepends.sh</code><br><code>generate_rdepends.sh -h</code></p><h2 id="实战"><a href="#实战" class="headerlink" title="实战"></a>实战</h2><p>在 UOS 系统中运行以下命令<br><code>generate_rdepends.sh -p libdtkwidget5 -m dde-dock</code><br>得到的依赖图内容如下</p><p><img lazyload alt="image" data-src="/2024/01685f950a/1.svg" ></p><h2 id="备注"><a href="#备注" class="headerlink" title="备注"></a>备注</h2><p>通过上面的脚本可以分析某个软件包的被依赖项,如果是分析其依赖项,可以通过 <code>debtree -b [package_name]</code> 实现。</p>]]></content>
<summary type="html"><h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><p>通过 apt 命令分析系统中安装的软件包的依赖关系,生成符合 mermaid 语法的配置文件,再通过 dot 命令生成 svg 图。</p></summary>
<category term="Linux" scheme="https://ssk-wh.github.io/categories/Linux/"/>
<category term="apt" scheme="https://ssk-wh.github.io/tags/apt/"/>
</entry>
<entry>
<title>GammaRay代码导图</title>
<link href="https://ssk-wh.github.io/2023/104b4fafed.html"/>
<id>https://ssk-wh.github.io/2023/104b4fafed.html</id>
<published>2023-10-26T13:17:05.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<p>源码之下,了无秘密,见下图:</p><p><img lazyload alt="image" data-src="/1.jpg" ></p>]]></content>
<summary type="html"><p>源码之下,了无秘密,见下图:</p>
<p><img
lazyload
alt="image"
data-src="/1.jpg"
</summary>
<category term="C++" scheme="https://ssk-wh.github.io/categories/C/"/>
<category term="软件" scheme="https://ssk-wh.github.io/tags/%E8%BD%AF%E4%BB%B6/"/>
</entry>
<entry>
<title>QT中一些常用的宏和函数</title>
<link href="https://ssk-wh.github.io/2023/0989f4c455.html"/>
<id>https://ssk-wh.github.io/2023/0989f4c455.html</id>
<published>2023-09-21T22:40:35.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<p>QT中一些常用的宏和函数</p><table><thead><tr><th>宏</th><th>说明</th></tr></thead><tbody><tr><td>Q_ASSERT<br/>Q_ASSERT_X</td><td>常用于断言,Release模式下不起作用</td></tr><tr><td>Q_ASSUME</td><td>= Q_ASSERT_X + Q_UNREACHABLE</td></tr><tr><td>Q_COREAPP_STARTUP_FUNCTION</td><td>添加一个全局函数,在QCoreApplication构造时被执行。<br>要注意,这里的执行比QGuiApplication的初始化要早。</td></tr><tr><td>Q_DISABLE_COPY</td><td>禁用类的拷贝构造函数和赋值构造函数,常用于单例类的实现</td></tr><tr><td>Q_FOREACH</td><td>不在建议使用,等价于foreach关键字</td></tr><tr><td>Q_FOREVER</td><td>等价于forever关键字</td></tr><tr><td>Q_GLOBAL_STATIC<br>Q_GLOBAL_STATIC_WITH_ARGS</td><td>创建一个全局的,静态的对应类型,但相比于static Type t这种写法有一定优势</td></tr><tr><td>Q_LOGGING_CATEGORY</td><td>快速声明一个日志的category对象</td></tr><tr><td>Q_OS_*</td><td>区分不同的平台,常见的有Q_OS_ANDROID,Q_OS_LINUX,Q_OS_WIN64等</td></tr><tr><td>Q_PROCESSOR_*</td><td>区分不同的处理器环境,例如Q_PROCESSOR_ARM,Q_PROCESSOR_MIPS,Q_PROCESSOR_X86_64等</td></tr><tr><td>Q_LIKELY<br/>Q_UNLIKELY</td><td>缓存命中,提高执行效率。</td></tr><tr><td>Q_UNREACHABLE</td><td>执行到这里,程序会发生未定义的行为。常见的后果就是崩溃,用于标记永远不会执行到的语句</td></tr><tr><td>Q_UNUSED</td><td>没有用到部分参数或对象时,编译器会发出警告,使用此宏减少警告。</td></tr><tr><td>qAbs</td><td>返回参数的绝对值</td></tr><tr><td>qMax</td><td>返回两个参数中较大的一个</td></tr><tr><td>qMin</td><td>返回两个参数中较小的一个</td></tr><tr><td>qRound</td><td>返回较近的整数</td></tr><tr><td>qBound</td><td>返回最小值到最大值范围内的一个合理值</td></tr><tr><td>qAddPreRoutine</td><td>在QCoreApplication构造时执行操作</td></tr><tr><td>qAddPostRoutine</td><td>在QCoreApplication析构时执行操作</td></tr><tr><td>qDeleteAll</td><td>删除容器中的所有元素,元素必须是指针类型(注意:qDeleteAll只做元素的delete操作,并不会将元素从容器中remove,需要手动对容器进行clear)</td></tr></tbody></table><p>头文件</p><table><thead><tr><th>头文件</th><th>说明</th></tr></thead><tbody><tr><td>QtMath</td><td>如果你需要做一些数学计算,请包含这个头文件,包含了常用的绝对值,取整,三角计算等函数</td></tr><tr><td></td><td></td></tr><tr><td></td><td></td></tr><tr><td></td><td></td></tr></tbody></table><p>Qt关键点</p><p>Qt 5.11 Qt Widgets Model/View Programming</p>]]></content>
<summary type="html"><p>QT中一些常用的宏和函数</p>
<table>
<thead>
<tr>
<th>宏</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>Q_ASSERT<br/>Q_ASSERT_X</td>
<td>常用于断言,Releas</summary>
<category term="C++" scheme="https://ssk-wh.github.io/categories/C/"/>
<category term="Qt" scheme="https://ssk-wh.github.io/tags/Qt/"/>
</entry>
<entry>
<title>任务管控终端的代码实现</title>
<link href="https://ssk-wh.github.io/2023/0978b93c1c.html"/>
<id>https://ssk-wh.github.io/2023/0978b93c1c.html</id>
<published>2023-09-04T21:01:09.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<p>任务管控终端,允许从远程接收任务执行并反馈任务执行结果</p><span id="more"></span><h2 id="特性"><a href="#特性" class="headerlink" title="特性"></a>特性</h2><p>任务状态周期性上报机制,避免网络环境恶劣导致服务端无法获取任务执行情况<br>限制单个任务执行时长为2h<br>支持日志分类<br>支持导出历史任务执行状况,最多支持最近的1000个任务<br>支持通过DBus监听任务执行的实时状态</p><h3 id="任务类型-TaskType"><a href="#任务类型-TaskType" class="headerlink" title="任务类型-TaskType"></a>任务类型-TaskType</h3><table><thead><tr><th>类型</th><th>取值</th><th>说明</th></tr></thead><tbody><tr><td>Ping</td><td>1</td><td>检查客户端是否存活,收到后应直接以约定的方式响应服务端</td></tr><tr><td>Bash</td><td>2</td><td>命令的内容一般是bash语句</td></tr><tr><td>Settings</td><td>3</td><td>命令的内容和本地要执行的任务是提前有对应关系的</td></tr><tr><td>Strategy</td><td>4</td><td>策略型任务,一般是一系列任务的集合</td></tr></tbody></table><h3 id="任务结构-Task"><a href="#任务结构-Task" class="headerlink" title="任务结构-Task"></a>任务结构-Task</h3><table><thead><tr><th>字段</th><th>说明</th></tr></thead><tbody><tr><td>type</td><td>任务类型,决定了如何执行task_command命令</td></tr><tr><td>id</td><td>唯一的身份ID,用于标识身份</td></tr><tr><td>name</td><td>任务名称,仅做标记使用</td></tr><tr><td>command</td><td>任务的具体命令</td></tr></tbody></table><h2 id="程序模块"><a href="#程序模块" class="headerlink" title="程序模块"></a>程序模块</h2><table><thead><tr><th>模块</th><th>说明</th></tr></thead><tbody><tr><td>TaskCache</td><td>负责任务状态缓存</td></tr><tr><td>TaskHandler</td><td>执行任务</td></tr><tr><td>TaskDispatcher</td><td>任务的分发</td></tr><tr><td>TaskManager</td><td>整体的任务管理</td></tr><tr><td>TaskReporter</td><td>任务状态上传</td></tr></tbody></table><h2 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h2><p>暂时不考虑超大QPS任务请求执行的场景,目前已满足普通商用需求。</p><p>利用多线程,支持并发执行多条任务,任务的状态会实时同步到本地缓存,避免异常掉电、崩溃等情况导致的任务丢失问题。周期性的上传任务完成状态到服务端,针对网络环境不稳定情况也能很好的处理。且开了单独的线程(比执行任务的线程优先级要高)用于上传状态。</p><p>写这个的目的一是想把心中的任务管理写出来,二是以后万一用到了直接过来拷贝就好了。</p><h2 id="TODO"><a href="#TODO" class="headerlink" title="TODO"></a>TODO</h2><ul><li>大批量任务瞬间到达,引发内存峰值的情况还在考虑要不要处理</li><li>部分任务很可能需要root权限,考虑子母进程的方式分别实现root级别配置和用户级别的配置</li></ul><p>源码地址:<a class="link" href="https://github.com/ssk-wh/task_manager/tree/master" >https://github.com/ssk-wh/task_manager/tree/master<i class="fas fa-external-link-alt"></i></a></p>]]></content>
<summary type="html"><p>任务管控终端,允许从远程接收任务执行并反馈任务执行结果</p></summary>
<category term="C++" scheme="https://ssk-wh.github.io/categories/C/"/>
<category term="Qt" scheme="https://ssk-wh.github.io/tags/Qt/"/>
<category term="C++" scheme="https://ssk-wh.github.io/tags/C/"/>
<category term="任务管控" scheme="https://ssk-wh.github.io/tags/%E4%BB%BB%E5%8A%A1%E7%AE%A1%E6%8E%A7/"/>
</entry>
<entry>
<title>QT实现生产者-消费者模型</title>
<link href="https://ssk-wh.github.io/2023/086eb5fc91.html"/>
<id>https://ssk-wh.github.io/2023/086eb5fc91.html</id>
<published>2023-08-30T00:00:00.000Z</published>
<updated>2024-07-12T03:05:34.000Z</updated>
<content type="html"><![CDATA[<h1 id="生产者-消费者模型"><a href="#生产者-消费者模型" class="headerlink" title="生产者-消费者模型"></a>生产者-消费者模型</h1><p>基于 Qt 实现QT实现生产者-消费者模型的demo</p><span id="more"></span><h2 id="使用信号量实现-QSemaphore"><a href="#使用信号量实现-QSemaphore" class="headerlink" title="使用信号量实现-QSemaphore"></a>使用信号量实现-QSemaphore</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><QCoreApplication></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><QSemaphore></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><QThread></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><QDebug></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><QQueue></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><QRandomGenerator></span></span></span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> bufferSize = <span class="number">100</span>;</span><br><span class="line"><span class="function">QSemaphore <span class="title">writeSemaphore</span><span class="params">(bufferSize)</span></span>;</span><br><span class="line">QSemaphore readSemaphore;</span><br><span class="line">QQueue<<span class="type">int</span>> queue;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Producer</span> : <span class="keyword">public</span> QThread</span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">run</span><span class="params">()</span> <span class="keyword">override</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">while</span> (<span class="number">1</span>) {</span><br><span class="line"> <span class="type">static</span> <span class="type">int</span> resources_index = <span class="number">0</span>;</span><br><span class="line"> <span class="comment">// 0~100ms内随机产生一个资源</span></span><br><span class="line"> QThread::<span class="built_in">msleep</span>(QRandomGenerator::<span class="built_in">global</span>()-><span class="built_in">bounded</span>(<span class="number">100</span>));</span><br><span class="line"> writeSemaphore.<span class="built_in">acquire</span>();</span><br><span class="line"> queue.<span class="built_in">append</span>(resources_index++);</span><br><span class="line"> <span class="built_in">qDebug</span>() << <span class="string">"+++"</span> << resources_index << <span class="string">"produced"</span>;</span><br><span class="line"> readSemaphore.<span class="built_in">release</span>();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Consumer</span> : <span class="keyword">public</span> QThread</span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">run</span><span class="params">()</span> <span class="keyword">override</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">while</span> (<span class="number">1</span>) {</span><br><span class="line"> readSemaphore.<span class="built_in">acquire</span>();</span><br><span class="line"> <span class="type">int</span> resources_index = queue.<span class="built_in">takeFirst</span>();</span><br><span class="line"> writeSemaphore.<span class="built_in">release</span>();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 0~500ms内随机消费一个资源</span></span><br><span class="line"> QThread::<span class="built_in">msleep</span>(QRandomGenerator::<span class="built_in">global</span>()-><span class="built_in">bounded</span>(<span class="number">500</span>));</span><br><span class="line"> <span class="built_in">qDebug</span>() << <span class="string">"---"</span> << resources_index << <span class="string">"consumed"</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">};</span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="function">QCoreApplication <span class="title">a</span><span class="params">(argc, argv)</span></span>;</span><br><span class="line"></span><br><span class="line"> Producer producer;</span><br><span class="line"> Consumer consumer;</span><br><span class="line"> producer.<span class="built_in">start</span>();</span><br><span class="line"> consumer.<span class="built_in">start</span>();</span><br><span class="line"> producer.<span class="built_in">wait</span>();</span><br><span class="line"> consumer.<span class="built_in">wait</span>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> a.<span class="built_in">exec</span>();</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="使用条件变量实现-QWaitCondition"><a href="#使用条件变量实现-QWaitCondition" class="headerlink" title="使用条件变量实现-QWaitCondition"></a>使用条件变量实现-QWaitCondition</h2><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><QtCore></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><QRandomGenerator></span></span></span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">int</span> bufferSize = <span class="number">100</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Producer</span> : <span class="keyword">public</span> QThread</span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="built_in">Producer</span>(QWaitCondition *wc1, QWaitCondition *wc2, QMutex *mutex, QQueue<<span class="type">int</span>> &queue, QObject *parent = <span class="literal">nullptr</span>)</span><br><span class="line"> : <span class="built_in">QThread</span>(parent)</span><br><span class="line"> , <span class="built_in">m_consumeWaitCondition</span>(wc1)</span><br><span class="line"> , <span class="built_in">m_produceWaitCondition</span>(wc2)</span><br><span class="line"> , <span class="built_in">m_mutex</span>(mutex)</span><br><span class="line"> , <span class="built_in">m_queue</span>(queue)</span><br><span class="line"> {</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">run</span><span class="params">()</span> <span class="keyword">override</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">while</span>(<span class="number">1</span>) {</span><br><span class="line"> <span class="comment">// 0~100ms内随机产生一个资源</span></span><br><span class="line"> QThread::<span class="built_in">msleep</span>(QRandomGenerator::<span class="built_in">global</span>()-><span class="built_in">bounded</span>(<span class="number">100</span>));</span><br><span class="line"></span><br><span class="line"> m_mutex-><span class="built_in">lock</span>();</span><br><span class="line"> <span class="type">static</span> <span class="type">int</span> resource_index = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">if</span> (m_queue.<span class="built_in">size</span>() < bufferSize) {</span><br><span class="line"> m_queue.<span class="built_in">append</span>(resource_index++);</span><br><span class="line"> <span class="built_in">qDebug</span>() << <span class="string">"+++"</span> << resource_index << <span class="string">"produced"</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> m_produceWaitCondition-><span class="built_in">wait</span>(m_mutex);</span><br><span class="line"> }</span><br><span class="line"> m_mutex-><span class="built_in">unlock</span>();</span><br><span class="line"></span><br><span class="line"> m_mutex-><span class="built_in">lock</span>();</span><br><span class="line"> m_consumeWaitCondition-><span class="built_in">wakeOne</span>();</span><br><span class="line"> m_mutex-><span class="built_in">unlock</span>();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> QWaitCondition *m_consumeWaitCondition;</span><br><span class="line"> QWaitCondition *m_produceWaitCondition;</span><br><span class="line"> QMutex *m_mutex;</span><br><span class="line"> QQueue<<span class="type">int</span>> &m_queue;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Consumer</span> : <span class="keyword">public</span> QThread</span><br><span class="line">{</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line"> <span class="built_in">Consumer</span>(QWaitCondition *wc1, QWaitCondition *wc2, QMutex *mutex, QQueue<<span class="type">int</span>> &queue, QObject *parent = <span class="literal">nullptr</span>)</span><br><span class="line"> : <span class="built_in">QThread</span>(parent)</span><br><span class="line"> , <span class="built_in">m_consumeWaitCondition</span>(wc1)</span><br><span class="line"> , <span class="built_in">m_produceWaitCondition</span>(wc2)</span><br><span class="line"> , <span class="built_in">m_mutex</span>(mutex)</span><br><span class="line"> , <span class="built_in">m_queue</span>(queue)</span><br><span class="line"> {</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="type">void</span> <span class="title">run</span><span class="params">()</span> <span class="keyword">override</span></span></span><br><span class="line"><span class="function"> </span>{</span><br><span class="line"> <span class="keyword">while</span> (<span class="number">1</span>) {</span><br><span class="line"> <span class="type">int</span> resources_index = <span class="number">-1</span>;</span><br><span class="line"> m_mutex-><span class="built_in">lock</span>();</span><br><span class="line"> <span class="keyword">if</span> (m_queue.<span class="built_in">size</span>() > <span class="number">0</span>) {</span><br><span class="line"> resources_index = m_queue.<span class="built_in">takeFirst</span>();</span><br><span class="line"> m_mutex-><span class="built_in">unlock</span>();</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> m_consumeWaitCondition-><span class="built_in">wait</span>(m_mutex);</span><br><span class="line"> m_mutex-><span class="built_in">unlock</span>();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> m_mutex-><span class="built_in">lock</span>();</span><br><span class="line"> m_produceWaitCondition-><span class="built_in">wakeAll</span>();</span><br><span class="line"> m_mutex-><span class="built_in">unlock</span>();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 0~500ms内随机消费一个资源</span></span><br><span class="line"> QThread::<span class="built_in">msleep</span>(QRandomGenerator::<span class="built_in">global</span>()-><span class="built_in">bounded</span>(<span class="number">500</span>));</span><br><span class="line"> <span class="built_in">qDebug</span>() << <span class="string">"---"</span> << resources_index << <span class="string">"consumed"</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="keyword">private</span>:</span><br><span class="line"> QWaitCondition *m_consumeWaitCondition;</span><br><span class="line"> QWaitCondition *m_produceWaitCondition;</span><br><span class="line"> QMutex *m_mutex;</span><br><span class="line"> QQueue<<span class="type">int</span>> &m_queue;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">(<span class="type">int</span> argc, <span class="type">char</span> *argv[])</span></span></span><br><span class="line"><span class="function"></span>{</span><br><span class="line"> <span class="function">QCoreApplication <span class="title">app</span><span class="params">(argc, argv)</span></span>;</span><br><span class="line"></span><br><span class="line"> QWaitCondition queueNotEmpty;</span><br><span class="line"> QWaitCondition queueNotFull;</span><br><span class="line"> QMutex mutex;</span><br><span class="line"> QQueue<<span class="type">int</span>> taskQueue;</span><br><span class="line"></span><br><span class="line"> <span class="function">Producer <span class="title">producer</span><span class="params">(&queueNotEmpty, &queueNotFull, &mutex, taskQueue)</span></span>;</span><br><span class="line"> <span class="function">Consumer <span class="title">consumer</span><span class="params">(&queueNotEmpty, &queueNotFull, &mutex, taskQueue)</span></span>;</span><br><span class="line"> producer.<span class="built_in">start</span>();</span><br><span class="line"> consumer.<span class="built_in">start</span>();</span><br><span class="line"> producer.<span class="built_in">wait</span>();</span><br><span class="line"> consumer.<span class="built_in">wait</span>();</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><h1 id="生产者-消费者模型"><a href="#生产者-消费者模型" class="headerlink" title="生产者-消费者模型"></a>生产者-消费者模型</h1><p>基于 Qt 实现QT实现生产者-消费者模型的demo</p></summary>
<category term="C++" scheme="https://ssk-wh.github.io/categories/C/"/>
<category term="Qt" scheme="https://ssk-wh.github.io/tags/Qt/"/>
</entry>
</feed>