self_cmd 0.1.8

Self-executing command builder for Rust programs / Rust 程序自执行命令构建器
Documentation
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
[English]#en | [中文]#zh

---

<a id="en"></a>

# self_cmd: Self-Executing Command Builder

- [Overview]#overview
- [Features]#features
- [Usage]#usage
- [Linux Socket Activation]#linux-socket-activation
- [Design Philosophy]#design-philosophy
- [Technical Stack]#technical-stack
- [Project Structure]#project-structure
- [API Reference]#api-reference
- [Error Handling]#error-handling

## Overview

`self_cmd` is a Rust library that creates Command instances for re-executing the current program with identical arguments and stdio inheritance. On Linux, it provides additional support for systemd socket activation by preserving file descriptor mappings through the `LISTEN_FDS` protocol.

## Features

- **Self-Replication**: Generate Command objects that execute the current program
- **Argument Preservation**: Automatically captures and forwards command-line arguments
- **Stdio Inheritance**: Maintains stdin, stdout, and stderr connections
- **Socket Activation Support**: Linux-specific file descriptor mapping for systemd integration
- **Robust Error Handling**: Custom error types with proper error propagation
- **Logging Integration**: Built-in logging support for debugging and monitoring

## Usage

Add to your `Cargo.toml`:

```toml
[dependencies]
self_cmd = "0.1.7"
```

Basic usage:

```rust
use self_cmd;

fn main() -> self_cmd::Result<()> {
    // Create a command that will re-execute this program
    let mut cmd = self_cmd::get()?;
    
    // Execute the command
    let status = cmd.status()?;
    println!("Child process exited with: {status}");
    
    Ok(())
}
```

Advanced usage with custom handling:

```rust
use self_cmd;

fn restart_self() -> self_cmd::Result<()> {
    let mut cmd = self_cmd::get()?;
    
    // The command inherits stdio by default and preserves FD mappings on Linux
    // You can modify it if needed
    cmd.spawn()?;
    
    Ok(())
}
```

## Linux Socket Activation

On Linux systems, `self_cmd` automatically handles systemd socket activation by preserving file descriptor mappings:

```rust
use self_cmd;

fn main() -> self_cmd::Result<()> {
    // On Linux, this will automatically:
    // 1. Check for LISTEN_FDS environment variable
    // 2. Duplicate and map file descriptors starting from FD 3
    // 3. Set LISTEN_FDS for the child process
    // 4. Remove LISTEN_PID to indicate new process ownership
    let mut cmd = self_cmd::get()?;
    
    cmd.spawn()?;
    Ok(())
}
```

The library handles the complete systemd socket activation protocol, making it seamless for services that need to restart while maintaining their listening sockets.

## Design Philosophy

The library follows a minimalist approach with a single public function that encapsulates the complexity of self-execution:

```mermaid
graph TD
    A[Program Start] --> B["self_cmd::get()"]
    B --> C["env::current_exe()"]
    C --> D["env::args().skip(1)"]
    D --> E["Command::new(program)"]
    E --> F["cmd.args(args)"]
    F --> G[Configure Stdio Inheritance]
    G --> H[Return Command]
    H --> I[Execute Command]
```

The design ensures:
- **Simplicity**: Single function interface
- **Reliability**: Proper error handling without panics
- **Flexibility**: Returns Command for further customization
- **Performance**: Minimal overhead with lazy evaluation

## Technical Stack

- **Language**: Rust 2024 Edition
- **Core Dependencies**: 
  - `log` for logging functionality
  - `thiserror` for structured error handling
- **Linux Dependencies**:
  - `command-fds` for file descriptor mapping
  - `libc` for low-level system calls
- **Error Handling**: Custom `Error` type with `thiserror` integration
- **Process Management**: `std::process::Command` with FD mapping extensions
- **Environment Access**: `std::env` for executable path and arguments

## Project Structure

```
self_cmd/
├── src/
│   ├── lib.rs          # Core implementation and public API
│   ├── error.rs        # Error types and handling
│   └── fd_mapping.rs   # Linux-specific FD mapping (conditional)
├── tests/
│   └── main.rs         # Integration tests
├── readme/
│   ├── en.md          # English documentation
│   └── zh.md          # Chinese documentation
├── Cargo.toml         # Project configuration
└── test.sh           # Test runner script
```

## API Reference

### `get() -> Result<Command>`

Creates a Command instance configured to re-execute the current program with full context preservation.

**Returns:**
- `Ok(Command)`: Configured command ready for execution
- `Err(Error)`: If unable to determine executable path or configure FD mappings

**Behavior:**
- Captures current executable path via `env::current_exe()`
- Preserves all command-line arguments except program name
- Configures stdio inheritance (stdin, stdout, stderr)
- **Linux only**: Handles systemd socket activation FD mapping
- Returns Command for further customization before execution

**Example:**
```rust
match self_cmd::get() {
    Ok(mut cmd) => {
        // Command is ready to use with full context preservation
        cmd.status()?;
    }
    Err(e) => {
        eprintln!("Failed to create self command: {e}");
    }
}
```

### `fd_mapping() -> Result<Vec<FdMapping>>` (Linux only)

**Available on Linux only** - Creates file descriptor mappings for systemd socket activation.

**Returns:**
- `Ok(Vec<FdMapping>)`: List of FD mappings for socket activation
- `Err(Error)`: If FD duplication or validation fails

This function is automatically called by `get()` on Linux systems and typically doesn't need to be used directly.

## Error Handling

The library uses a custom `Error` type built with `thiserror` for comprehensive error handling:

```rust
use self_cmd::{Error, Result};

#[derive(Error, Debug)]
pub enum Error {
    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),
    
    #[error("FD mapping collision: {0}")]
    FdMappingCollision(#[from] command_fds::FdMappingCollision),
}
```

All public functions return `Result<T>` which is an alias for `std::result::Result<T, Error>`. This provides:

- **Structured Errors**: Clear error types for different failure modes
- **Error Chaining**: Automatic conversion from underlying error types
- **Debugging Support**: Rich error messages with context
- **Integration**: Seamless integration with `?` operator and error handling patterns

---

## About

This project is an open-source component of [js0.site ⋅ Refactoring the Internet Plan](https://js0.site).

We are redefining the development paradigm of the Internet in a componentized way. Welcome to follow us:

* [Google Group]https://groups.google.com/g/js0-site
* [js0site.bsky.social]https://bsky.app/profile/js0site.bsky.social

---

<a id="zh"></a>

# self_cmd: 自执行命令构建器

- [概述]#概述
- [功能特性]#功能特性
- [使用方法]#使用方法
- [Linux 套接字激活]#linux-套接字激活
- [设计理念]#设计理念
- [技术栈]#技术栈
- [项目结构]#项目结构
- [API 参考]#api-参考
- [错误处理]#错误处理

## 概述

`self_cmd` 是 Rust 库,用于创建重新执行当前程序的 Command 实例,保持相同参数和标准输入输出继承。在 Linux 系统上,通过 `LISTEN_FDS` 协议保持文件描述符映射,提供对 systemd 套接字激活的额外支持。

## 功能特性

- **自我复制**: 生成执行当前程序的 Command 对象
- **参数保持**: 自动捕获并转发命令行参数
- **标准输入输出继承**: 维持 stdin、stdout、stderr 连接
- **套接字激活支持**: Linux 特定的文件描述符映射,用于 systemd 集成
- **健壮的错误处理**: 自定义错误类型与正确的错误传播
- **日志集成**: 内置日志支持,用于调试和监控

## 使用方法

添加到 `Cargo.toml`:

```toml
[dependencies]
self_cmd = "0.1.7"
```

基本用法:

```rust
use self_cmd;

fn main() -> self_cmd::Result<()> {
    // 创建重新执行此程序的命令
    let mut cmd = self_cmd::get()?;
    
    // 执行命令
    let status = cmd.status()?;
    println!("子进程退出状态: {status}");
    
    Ok(())
}
```

高级用法与自定义处理:

```rust
use self_cmd;

fn restart_self() -> self_cmd::Result<()> {
    let mut cmd = self_cmd::get()?;
    
    // 命令默认继承标准输入输出,在 Linux 上保持 FD 映射
    // 可根据需要进行修改
    cmd.spawn()?;
    
    Ok(())
}
```

## Linux 套接字激活

在 Linux 系统上,`self_cmd` 自动处理 systemd 套接字激活,保持文件描述符映射:

```rust
use self_cmd;

fn main() -> self_cmd::Result<()> {
    // 在 Linux 上,这将自动:
    // 1. 检查 LISTEN_FDS 环境变量
    // 2. 从 FD 3 开始复制和映射文件描述符
    // 3. 为子进程设置 LISTEN_FDS
    // 4. 移除 LISTEN_PID 以表示新进程所有权
    let mut cmd = self_cmd::get()?;
    
    cmd.spawn()?;
    Ok(())
}
```

库处理完整的 systemd 套接字激活协议,使需要重启但保持监听套接字的服务变得无缝。

## 设计理念

库采用极简主义方法,通过单个公共函数封装自执行的复杂性:

```mermaid
graph TD
    A[程序启动] --> B["self_cmd::get()"]
    B --> C["env::current_exe()"]
    C --> D["env::args().skip(1)"]
    D --> E["Command::new(program)"]
    E --> F["cmd.args(args)"]
    F --> G[配置标准输入输出继承]
    G --> H[返回 Command]
    H --> I[执行命令]
```

设计确保:
- **简洁性**: 单函数接口
- **可靠性**: 无恐慌的错误处理
- **灵活性**: 返回 Command 供进一步定制
- **性能**: 惰性求值的最小开销

## 技术栈

- **语言**: Rust 2024 版本
- **核心依赖**: 
  - `log` 用于日志功能
  - `thiserror` 用于结构化错误处理
- **Linux 依赖**:
  - `command-fds` 用于文件描述符映射
  - `libc` 用于底层系统调用
- **错误处理**: 自定义 `Error` 类型与 `thiserror` 集成
- **进程管理**: `std::process::Command` 与 FD 映射扩展
- **环境访问**: `std::env` 获取可执行文件路径和参数

## 项目结构

```
self_cmd/
├── src/
│   ├── lib.rs          # 核心实现和公共 API
│   ├── error.rs        # 错误类型和处理
│   └── fd_mapping.rs   # Linux 特定的 FD 映射(条件编译)
├── tests/
│   └── main.rs         # 集成测试
├── readme/
│   ├── en.md          # 英文文档
│   └── zh.md          # 中文文档
├── Cargo.toml         # 项目配置
└── test.sh           # 测试运行脚本
```

## API 参考

### `get() -> Result<Command>`

创建配置为重新执行当前程序的 Command 实例,完整保持上下文。

**返回值:**
- `Ok(Command)`: 配置好的命令,可直接执行
- `Err(Error)`: 无法确定可执行文件路径或配置 FD 映射时

**行为:**
- 通过 `env::current_exe()` 捕获当前可执行文件路径
- 保留除程序名外的所有命令行参数
- 配置标准输入输出继承 (stdin, stdout, stderr)
- **仅 Linux**: 处理 systemd 套接字激活 FD 映射
- 返回 Command 供执行前进一步定制

**示例:**
```rust
match self_cmd::get() {
    Ok(mut cmd) => {
        // 命令已准备就绪,完整保持上下文
        cmd.status()?;
    }
    Err(e) => {
        eprintln!("创建自执行命令失败: {e}");
    }
}
```

### `fd_mapping() -> Result<Vec<FdMapping>>` (仅 Linux)

**仅在 Linux 上可用** - 为 systemd 套接字激活创建文件描述符映射。

**返回值:**
- `Ok(Vec<FdMapping>)`: 套接字激活的 FD 映射列表
- `Err(Error)`: FD 复制或验证失败时

此函数在 Linux 系统上由 `get()` 自动调用,通常不需要直接使用。

## 错误处理

库使用基于 `thiserror` 构建的自定义 `Error` 类型进行全面的错误处理:

```rust
use self_cmd::{Error, Result};

#[derive(Error, Debug)]
pub enum Error {
    #[error("IO error: {0} / IO 错误: {0}")]
    Io(#[from] std::io::Error),
    
    #[error("FD mapping collision: {0} / FD 映射冲突: {0}")]
    FdMappingCollision(#[from] command_fds::FdMappingCollision),
}
```

所有公共函数返回 `Result<T>`,这是 `std::result::Result<T, Error>` 的别名。这提供了:

- **结构化错误**: 不同失败模式的清晰错误类型
- **错误链**: 从底层错误类型的自动转换
- **调试支持**: 带有上下文的丰富错误消息
- **集成**: 与 `?` 操作符和错误处理模式的无缝集成

---

## 关于

本项目为 [js0.site ⋅ 重构互联网计划](https://js0.site) 的开源组件。

我们正在以组件化的方式重新定义互联网的开发范式,欢迎关注:

* [谷歌邮件列表]https://groups.google.com/g/js0-site
* [js0site.bsky.social]https://bsky.app/profile/js0site.bsky.social