Compare commits
191 Commits
1.3.3.15-1
...
master
| Author | SHA1 | Date |
|---|---|---|
|
|
5a4eaff29f | |
|
|
e12e421143 | |
|
|
caf2cec0d2 | |
|
|
59ed24f214 | |
|
|
27c0ae9643 | |
|
|
8f1b042421 | |
|
|
613cc27af6 | |
|
|
56bb0d1e6b | |
|
|
72ca241a20 | |
|
|
11face2e94 | |
|
|
04aface617 | |
|
|
08b790480d | |
|
|
53f0e1e835 | |
|
|
881bcc93c0 | |
|
|
0e5def0fe2 | |
|
|
9204ffba0c | |
|
|
3b94fbcf43 | |
|
|
4ad30a7efb | |
|
|
24a6a99f98 | |
|
|
b1c7fa13d8 | |
|
|
08c47fff3c | |
|
|
e62d7d53e4 | |
|
|
2b51656a6e | |
|
|
2a8c21b681 | |
|
|
61d1b26eae | |
|
|
53883d5bf4 | |
|
|
55a147033b | |
|
|
308b80bacf | |
|
|
16f40a416a | |
|
|
3951cfc9b2 | |
|
|
0bb8d07bb2 | |
|
|
ee4e07a827 | |
|
|
e31f62f382 | |
|
|
000fa7ff73 | |
|
|
1fd78ccf1a | |
|
|
f30bf60148 | |
|
|
aa58f981ef | |
|
|
489cc336e4 | |
|
|
35ac00a66a | |
|
|
9d524a908c | |
|
|
46ff1b817f | |
|
|
e714f88ba3 | |
|
|
995231effc | |
|
|
123cfeb539 | |
|
|
9887a351c4 | |
|
|
37f8126145 | |
|
|
bcd7063161 | |
|
|
16ed42928d | |
|
|
2cb58b3a0f | |
|
|
cc49934702 | |
|
|
d2b7adbb1d | |
|
|
4f8ad981d5 | |
|
|
594bedcf1c | |
|
|
25fdeda582 | |
|
|
6b9422ff84 | |
|
|
4d3d0002f2 | |
|
|
f1378216b3 | |
|
|
22c8a34f3a | |
|
|
599b433142 | |
|
|
06f3a86652 | |
|
|
0bed97d189 | |
|
|
e83566c4b4 | |
|
|
cc3db26490 | |
|
|
0cb72a0b1a | |
|
|
2f74ccca81 | |
|
|
fda6b3954d | |
|
|
adcb988fa1 | |
|
|
26e24766d0 | |
|
|
a1aad2f284 | |
|
|
08305e83d0 | |
|
|
f6661b83bf | |
|
|
cf2e547d09 | |
|
|
23414a6aab | |
|
|
7d678a48ba | |
|
|
60b31b423e | |
|
|
c6725bd393 | |
|
|
e28caa9340 | |
|
|
c01c7bf36d | |
|
|
ed9fb921e8 | |
|
|
17c3827688 | |
|
|
7b60087a2e | |
|
|
301aced752 | |
|
|
2f0b801885 | |
|
|
c3590bc7b0 | |
|
|
1a07d78884 | |
|
|
88f8f97465 | |
|
|
1cb3bad58d | |
|
|
3a51dab444 | |
|
|
6c71a61249 | |
|
|
377ff9c4c1 | |
|
|
95ac068ed0 | |
|
|
2f70c75e51 | |
|
|
6f4ddaefe5 | |
|
|
1cf359e14d | |
|
|
813bc6b072 | |
|
|
f1856a5404 | |
|
|
7e74723197 | |
|
|
2586753235 | |
|
|
41c02f7c6f | |
|
|
c7de95af42 | |
|
|
197086419e | |
|
|
c02e41b180 | |
|
|
b983d5f513 | |
|
|
e2f473d44e | |
|
|
3c83d98431 | |
|
|
d2944e2ef5 | |
|
|
e86a05384b | |
|
|
7200a91460 | |
|
|
125037414d | |
|
|
49f19a7347 | |
|
|
77ad719204 | |
|
|
c5f966ead7 | |
|
|
c942000057 | |
|
|
d576be09ab | |
|
|
351a33f768 | |
|
|
910898b337 | |
|
|
d4c50ccc10 | |
|
|
65f24e63f3 | |
|
|
9f80f26da0 | |
|
|
411741b306 | |
|
|
2f76093cf1 | |
|
|
812b6770a5 | |
|
|
0e76506d5c | |
|
|
1f19c3df1c | |
|
|
bcebd8da68 | |
|
|
ff0cd07088 | |
|
|
b642bf942c | |
|
|
42b2907e63 | |
|
|
dc3f39b0f8 | |
|
|
9f7f969d92 | |
|
|
dbf51df551 | |
|
|
e3a58f2a6d | |
|
|
91f7f38e2c | |
|
|
b0b4798a95 | |
|
|
996f82e702 | |
|
|
ba28975e56 | |
|
|
930fce61ae | |
|
|
da89d5c824 | |
|
|
8708e52b43 | |
|
|
be356f816c | |
|
|
b61bac988b | |
|
|
16c15089c1 | |
|
|
15e53329c7 | |
|
|
bf9ab07f12 | |
|
|
d3397eefbb | |
|
|
03e772276a | |
|
|
67bf6e9d97 | |
|
|
ed4f87e317 | |
|
|
c98ca73207 | |
|
|
55968443bc | |
|
|
a5e55438d7 | |
|
|
04170fd370 | |
|
|
5596756555 | |
|
|
df1a816251 | |
|
|
0ac243071c | |
|
|
0c015a4e59 | |
|
|
ead51959f3 | |
|
|
90252e6d1d | |
|
|
56ae579d61 | |
|
|
3929bd38c9 | |
|
|
dcbbb53a8b | |
|
|
3a0446ed07 | |
|
|
5f1f57869f | |
|
|
e21aff13ca | |
|
|
f02eba5848 | |
|
|
953085409c | |
|
|
249b134ed3 | |
|
|
5f975ce066 | |
|
|
d223aea48c | |
|
|
8a36030481 | |
|
|
5b702272ae | |
|
|
e47975ddd4 | |
|
|
29c57ce9da | |
|
|
333b089f87 | |
|
|
3907448d51 | |
|
|
212a734812 | |
|
|
7f3de1c456 | |
|
|
e28427c595 | |
|
|
705692d3aa | |
|
|
c633517c6c | |
|
|
3058d4527e | |
|
|
5da2451f7f | |
|
|
0b1eea7b96 | |
|
|
a277365099 | |
|
|
839908d95d | |
|
|
7b0ce6f4a9 | |
|
|
17e22bdd85 | |
|
|
71311c7874 | |
|
|
f40c084f51 | |
|
|
c6d5294f71 | |
|
|
5001dec33e |
245
.clang-format
245
.clang-format
|
|
@ -1,139 +1,144 @@
|
|||
# This is the clang-format style used by qt releated deepin projects.
|
||||
#
|
||||
# This file is modified from https://github.com/qt/qt5/blob/5b22f8ec2e4fbb58e362b709ee82f2dbd8afdfd3/_clang-format
|
||||
# based on the rules from https://github.com/linuxdeepin/deepin-styleguide,
|
||||
# https://wiki.qt.io/Qt_Coding_Style and https://wiki.qt.io/Coding_Conventions
|
||||
#
|
||||
# This is for clang-format >= 14.0.0
|
||||
|
||||
---
|
||||
# Webkit style was loosely based on the Qt style
|
||||
BasedOnStyle: WebKit
|
||||
# 访问说明符的偏移(public private)
|
||||
AccessModifierOffset: -4
|
||||
# 括号之后,水平对齐参数: Align DontAlign AlwaysBreak。
|
||||
AlignAfterOpenBracket: Align
|
||||
#AlignConsecutiveBitFields: false
|
||||
# 连续的赋值时,对齐所有的等号
|
||||
AlignConsecutiveAssignments: false
|
||||
# 连续声明时,对齐所有声明的变量名
|
||||
AlignConsecutiveDeclarations: false
|
||||
#AlignConsecutiveMacros: false
|
||||
AlignEscapedNewlines: DontAlign
|
||||
# 水平对齐二元和三元表达式的操作数
|
||||
AlignOperands: true
|
||||
# 对齐连续的尾随的注释
|
||||
AlignTrailingComments: false
|
||||
#AllowAllArgumentsOnNextLine: false
|
||||
#AllowAllConstructorInitializersOnNextLine: false
|
||||
# 允许函数声明的所有参数在放在下一行
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
# 允许短的块放在同一行
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
# 允许短的case标签放在同一行
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
#AllowShortEnumsOnASingleLine: false
|
||||
# 允许短的函数放在同一行: None, InlineOnly(定义在类中), Empty(空函数), Inline(定义在类中,空函数), All
|
||||
AllowShortFunctionsOnASingleLine: InlineOnly
|
||||
# 是否允许短if单行 If true, if (a) return; 可以放到同一行
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
#AllowShortLambdasOnASingleLine: Inline
|
||||
# 允许短的循环保持在同一行
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
# 总是在定义返回类型后换行(deprecated)
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
|
||||
# deepin project might not use same standard.
|
||||
Standard: Auto
|
||||
|
||||
# Column width is limited to 100 in accordance with Qt Coding Style.
|
||||
# https://wiki.qt.io/Qt_Coding_Style
|
||||
# Note that this may be changed at some point in the future.
|
||||
ColumnLimit: 100
|
||||
# How much weight do extra characters after the line length limit have.
|
||||
# PenaltyExcessCharacter: 4
|
||||
|
||||
# Disable reflow of some specific comments
|
||||
# qdoc comments: indentation rules are different.
|
||||
# Translation comments and SPDX license identifiers are also excluded.
|
||||
CommentPragmas: "^!|^:|^ SPDX-License-Identifier:"
|
||||
|
||||
PointerAlignment: Right
|
||||
|
||||
# We use template< without space.
|
||||
SpaceAfterTemplateKeyword: false
|
||||
|
||||
# We want to break before the operators, but not before a '='.
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
|
||||
# Braces are usually attached, but not after functions or class declarations.
|
||||
BreakBeforeBraces: Custom
|
||||
BraceWrapping:
|
||||
# AfterCaseLabel: false
|
||||
AfterClass: true
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterStruct: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: true
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
# BeforeLambdaBody: false
|
||||
# BeforeWhile: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
IndentBraces: false
|
||||
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeTernaryOperators: true
|
||||
#在构造函数初始化时按逗号断行,并以冒号对齐
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakInheritanceList: BeforeComma
|
||||
BreakStringLiterals: false
|
||||
# 每行字符的限制,0表示没有限制
|
||||
ColumnLimit: 120
|
||||
# 描述具有特殊意义的注释的正则表达式,它不应该被分割为多行或以其它方式改变
|
||||
# CommentPragmas: '^ IWYU pragma:'
|
||||
# 语言: None Cpp Java Objc Protp
|
||||
CompactNamespaces: false
|
||||
Cpp11BracedListStyle: true
|
||||
#DeriveLineEnding: \n
|
||||
DerivePointerAlignment: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros: [ "foreach", "Q_FOREACH" ]
|
||||
# Indent initializers by 4 spaces
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
|
||||
# Indent width for line continuations.
|
||||
ContinuationIndentWidth: 8
|
||||
|
||||
# No indentation for namespaces.
|
||||
NamespaceIndentation: None
|
||||
|
||||
# Allow indentation for preprocessing directives (if/ifdef/endif). https://reviews.llvm.org/rL312125
|
||||
IndentPPDirectives: AfterHash
|
||||
# We do not indent preprocessor directives
|
||||
PPIndentWidth: 0
|
||||
|
||||
# Horizontally align arguments after an open bracket.
|
||||
# The coding style does not specify the following, but this is what gives
|
||||
# results closest to the existing code.
|
||||
AlignAfterOpenBracket: true
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
|
||||
# Ideally we should also allow less short function in a single line, but
|
||||
# clang-format does not handle that.
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
|
||||
# As clang-format 13 can regroup includes we enable this feature.
|
||||
# basically according to https://wiki.qt.io/Coding_Conventions#Including_headers
|
||||
# and https://github.com/linuxdeepin/deepin-styleguide
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^"'
|
||||
# gtest/gmock's h files
|
||||
- Regex: '^<g(test|mock)/'
|
||||
Priority: 1
|
||||
- Regex: '^["<]D'
|
||||
CaseSensitive: true
|
||||
# Your project's h files.
|
||||
- Regex: '^"'
|
||||
Priority: 2
|
||||
- Regex: '^<Q'
|
||||
Priority: 3
|
||||
- Regex: '^<'
|
||||
# DTK libraries' h files
|
||||
- Regex: '^<D[A-Z]'
|
||||
Priority: 4
|
||||
- Regex: '\.h>$'
|
||||
CaseSensitive: true
|
||||
# QT libraries' h files
|
||||
- Regex: '^<(Q[A-Z]|Qt)'
|
||||
Priority: 5
|
||||
- Regex: '^"moc_'
|
||||
Priority: 99
|
||||
- Regex: '\.moc"'
|
||||
Priority: 99
|
||||
CaseSensitive: true
|
||||
# C++ system headers (as of C++23).
|
||||
- Regex: '^<(algorithm|any|array|atomic|barrier|bit|bitset|cassert|ccomplex|cctype|cerrno|cfenv|cfloat|charconv|chrono|cinttypes|ciso646|climits|clocale|cmath|codecvt|compare|complex|concepts|condition_variable|coroutine|csetjmp|csignal|cstdalign|cstdarg|cstdbool|cstddef|cstdint|cstdio|cstdlib|cstring|ctgmath|ctime|cuchar|cwchar|cwctype|deque|exception|execution|expected|filesystem|flat_map|flat_set|format|forward_list|fstream|functional|future|generator|initializer_list|iomanip|ios|iosfwd|iostream|istream|iterator|latch|limits|list|locale|map|mdspan|memory|memory_resource|mutex|new|numbers|numeric|optional|ostream|print|queue|random|ranges|ratio|regex|scoped_allocator|semaphore|set|shared_mutex|source_location|span|spanstream|sstream|stack|stacktrace|stdexcept|stdfloat|stop_token|streambuf|string|string_view|strstream|syncstream|system_error|thread|tuple|type_traits|typeindex|typeinfo|unordered_map|unordered_set|utility|valarray|variant|vector|version)>$'
|
||||
Priority: 6
|
||||
CaseSensitive: true
|
||||
# C system headers.
|
||||
- Regex: '^<(aio|arpa/inet|assert|complex|cpio|ctype|curses|dirent|dlfcn|errno|fcntl|fenv|float|fmtmsg|fnmatch|ftw|glob|grp|iconv|inttypes|iso646|langinfo|libgen|limits|locale|math|monetary|mqueue|ndbm|netdb|net/if|netinet/in|netinet/tcp|nl_types|poll|pthread|pwd|regex|sched|search|semaphore|setjmp|signal|spawn|stdalign|stdarg|stdatomic|stdbool|stddef|stdint|stdio|stdlib|stdnoreturn|string|strings|stropts|sys/ipc|syslog|sys/mman|sys/msg|sys/resource|sys/select|sys/sem|sys/shm|sys/socket|sys/stat|sys/statvfs|sys/time|sys/times|sys/types|sys/uio|sys/un|sys/utsname|sys/wait|tar|term|termios|tgmath|threads|time|trace|uchar|ulimit|uncntrl|unistd|utime|utmpx|wchar|wctype|wordexp)\.h>$'
|
||||
Priority: 7
|
||||
CaseSensitive: true
|
||||
# other libraries' h files.
|
||||
- Regex: '^<'
|
||||
Priority: 3
|
||||
IncludeIsMainRegex: '((T|t)est)?$'
|
||||
SortIncludes: true
|
||||
|
||||
# 缩进case 标签
|
||||
IndentCaseLabels: false
|
||||
#IndentExternBlock: NoIndent
|
||||
#IndentCaseBlocks: false
|
||||
#IndentGotoLabels: false
|
||||
IndentPPDirectives: None
|
||||
#缩进宽度
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
#InsertTrailingCommas: None
|
||||
#在block从空行开始
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
Language: Cpp
|
||||
# 连续的空行保留几行
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
#指针的*的挨着哪边
|
||||
PointerAlignment: Right
|
||||
# 允许排序#include, 造成编译错误
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: false
|
||||
#括号后添加空格
|
||||
SpaceAfterCStyleCast: false
|
||||
#SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
#等号两边的空格
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: true
|
||||
SpaceBeforeCtorInitializerColon: false
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
#SpaceBeforeSquareBrackets: false
|
||||
#SpaceInEmptyBlock: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
#SpacesInConditionalStatement: false
|
||||
# 容器类的空格 例如 OC的字典
|
||||
SpacesInContainerLiterals: false
|
||||
# 小括号两边添加空格
|
||||
SpacesInParentheses: false
|
||||
# 中括号两边空格 []
|
||||
SpacesInSquareBrackets: false
|
||||
#StatementMacros: ["Q_UNUSED"]
|
||||
#tab键盘的宽度
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
# macros for which the opening brace stays attached.
|
||||
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH, forever, Q_FOREVER, QBENCHMARK, QBENCHMARK_ONCE ]
|
||||
|
||||
# Break constructor initializers before the colon and after the commas.
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
|
||||
# Add "// namespace <namespace>" comments on closing brace for a namespace
|
||||
# Ignored for namespaces that qualify as a short namespace,
|
||||
# see 'ShortNamespaceLines'
|
||||
FixNamespaceComments: true
|
||||
|
||||
# Definition of how short a short namespace is, default 1
|
||||
ShortNamespaceLines: 1
|
||||
|
||||
# When escaping newlines in a macro attach the '\' as far left as possible, e.g.
|
||||
##define a \
|
||||
# something; \
|
||||
# other; \
|
||||
# thelastlineislong;
|
||||
AlignEscapedNewlines: Left
|
||||
|
||||
# Avoids the addition of a space between an identifier and the
|
||||
# initializer list in list-initialization.
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowShortLambdasOnASingleLine: Empty
|
||||
AlignTrailingComments: true
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
PackConstructorInitializers: Never
|
||||
PenaltyReturnTypeOnItsOwnLine: 100
|
||||
SeparateDefinitionBlocks: Always
|
||||
WhitespaceSensitiveMacros:
|
||||
- Q_PROPERTY
|
||||
- Q_INTERFACES
|
||||
|
|
|
|||
|
|
@ -0,0 +1,107 @@
|
|||
# SPDX-FileCopyrightText: None
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
with section("parse"):
|
||||
additional_commands = {
|
||||
"cpmaddpackage": {
|
||||
"kwargs": {
|
||||
"DOWNLOAD_COMMAND": 1,
|
||||
"DOWNLOAD_NAME": 1,
|
||||
"DOWNLOAD_NO_EXTRACT": 1,
|
||||
"DOWNLOAD_ONLY": 1,
|
||||
"EXCLUDE_FROM_ALL": 1,
|
||||
"FIND_PACKAGE_ARGUMENTS": 1,
|
||||
"FORCE": 1,
|
||||
"GITHUB_REPOSITORY": 1,
|
||||
"GITLAB_REPOSITORY": 1,
|
||||
"GIT_REPOSITORY": 1,
|
||||
"GIT_SHALLOW": 1,
|
||||
"GIT_TAG": 1,
|
||||
"HTTP_PASSWORD": 1,
|
||||
"HTTP_USERNAME": 1,
|
||||
"NAME": 1,
|
||||
"NO_CACHE": 1,
|
||||
"OPTIONS": "+",
|
||||
"SOURCE_DIR": 1,
|
||||
"SOURCE_SUBDIR": 1,
|
||||
"SVN_REPOSITORY": 1,
|
||||
"SVN_REVISION": 1,
|
||||
"URL": 1,
|
||||
"URL_HASH": 1,
|
||||
"URL_MD5": 1,
|
||||
"VERSION": 1,
|
||||
},
|
||||
"pargs": {"flags": [], "nargs": "*"},
|
||||
"spelling": "CPMAddPackage",
|
||||
},
|
||||
"cpmdeclarepackage": {
|
||||
"kwargs": {
|
||||
"DOWNLOAD_COMMAND": 1,
|
||||
"DOWNLOAD_NAME": 1,
|
||||
"DOWNLOAD_NO_EXTRACT": 1,
|
||||
"DOWNLOAD_ONLY": 1,
|
||||
"EXCLUDE_FROM_ALL": 1,
|
||||
"FIND_PACKAGE_ARGUMENTS": 1,
|
||||
"FORCE": 1,
|
||||
"GITHUB_REPOSITORY": 1,
|
||||
"GITLAB_REPOSITORY": 1,
|
||||
"GIT_REPOSITORY": 1,
|
||||
"GIT_SHALLOW": 1,
|
||||
"GIT_TAG": 1,
|
||||
"HTTP_PASSWORD": 1,
|
||||
"HTTP_USERNAME": 1,
|
||||
"NAME": 1,
|
||||
"NO_CACHE": 1,
|
||||
"OPTIONS": "+",
|
||||
"SOURCE_DIR": 1,
|
||||
"SOURCE_SUBDIR": 1,
|
||||
"SVN_REPOSITORY": 1,
|
||||
"SVN_REVISION": 1,
|
||||
"URL": 1,
|
||||
"URL_HASH": 1,
|
||||
"URL_MD5": 1,
|
||||
"VERSION": 1,
|
||||
},
|
||||
"pargs": {"flags": [], "nargs": "*"},
|
||||
"spelling": "CPMDeclarePackage",
|
||||
},
|
||||
"cpmfindpackage": {
|
||||
"kwargs": {
|
||||
"DOWNLOAD_COMMAND": 1,
|
||||
"DOWNLOAD_NAME": 1,
|
||||
"DOWNLOAD_NO_EXTRACT": 1,
|
||||
"DOWNLOAD_ONLY": 1,
|
||||
"EXCLUDE_FROM_ALL": 1,
|
||||
"FIND_PACKAGE_ARGUMENTS": 1,
|
||||
"FORCE": 1,
|
||||
"GITHUB_REPOSITORY": 1,
|
||||
"GITLAB_REPOSITORY": 1,
|
||||
"GIT_REPOSITORY": 1,
|
||||
"GIT_SHALLOW": 1,
|
||||
"GIT_TAG": 1,
|
||||
"HTTP_PASSWORD": 1,
|
||||
"HTTP_USERNAME": 1,
|
||||
"NAME": 1,
|
||||
"NO_CACHE": 1,
|
||||
"OPTIONS": "+",
|
||||
"SOURCE_DIR": 1,
|
||||
"SOURCE_SUBDIR": 1,
|
||||
"SVN_REPOSITORY": 1,
|
||||
"SVN_REVISION": 1,
|
||||
"URL": 1,
|
||||
"URL_HASH": 1,
|
||||
"URL_MD5": 1,
|
||||
"VERSION": 1,
|
||||
},
|
||||
"pargs": {"flags": [], "nargs": "*"},
|
||||
"spelling": "CPMFindPackage",
|
||||
},
|
||||
"cpmgetpackageversion": {"pargs": 2, "spelling": "CPMGetPackageVersion"},
|
||||
"cpmregisterpackage": {"pargs": 1, "spelling": "CPMRegisterPackage"},
|
||||
"cpmusepackagelock": {"pargs": 1, "spelling": "CPMUsePackageLock"},
|
||||
}
|
||||
|
||||
with section("format"):
|
||||
# How wide to allow formatted cmake files
|
||||
line_width = 80
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
# SPDX-FileCopyrightText: None
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
version = 1
|
||||
|
||||
# 全局排除配置
|
||||
exclude_patterns = [
|
||||
"external/**",
|
||||
"build/**",
|
||||
"obj-*/**",
|
||||
".cache/**",
|
||||
".obs/**",
|
||||
".tx/**",
|
||||
"**/*.generated.*",
|
||||
"**/CMakeCache.txt",
|
||||
"**/compile_commands.json",
|
||||
"debian/patches/**",
|
||||
"po/*.po",
|
||||
"po/*.pot",
|
||||
"tools/openapi-c-libcurl-client/**",
|
||||
]
|
||||
|
||||
# C++ 分析器配置
|
||||
[[analyzers]]
|
||||
name = "cxx"
|
||||
enabled = true
|
||||
|
||||
[analyzers.meta]
|
||||
misra_compliance = true
|
||||
cyclomatic_complexity_threshold = "medium"
|
||||
|
||||
# Shell 脚本分析器配置
|
||||
[[analyzers]]
|
||||
name = "shell"
|
||||
enabled = true
|
||||
|
||||
[analyzers.meta]
|
||||
# 只保留官方支持的选项
|
||||
dialect = "bash"
|
||||
|
||||
# 密钥检测分析器配置
|
||||
[[analyzers]]
|
||||
name = "secrets"
|
||||
enabled = true
|
||||
# secrets 分析器不支持任何 meta 配置
|
||||
|
||||
# 测试覆盖率分析器配置
|
||||
[[analyzers]]
|
||||
name = "test-coverage"
|
||||
enabled = true
|
||||
|
||||
# 代码格式化器配置
|
||||
[[transformers]]
|
||||
name = "clang-format"
|
||||
enabled = true
|
||||
|
||||
[transformers.meta]
|
||||
exclude_patterns = ["external/**", "build/**", "obj-*/**", "**/*.generated.*"]
|
||||
|
||||
[[transformers]]
|
||||
name = "prettier"
|
||||
enabled = true
|
||||
|
||||
[transformers.meta]
|
||||
include_patterns = ["**/*.md", "**/*.json", "**/*.yaml", "**/*.yml"]
|
||||
exclude_patterns = [
|
||||
"external/**",
|
||||
"build/**",
|
||||
"obj-*/**",
|
||||
".cache/**",
|
||||
"po/**",
|
||||
"**/*.generated.*",
|
||||
"package-lock.json",
|
||||
"yarn.lock",
|
||||
]
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# SPDX-FileCopyrightText: None
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
[*.json]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
charset = utf-8
|
||||
|
|
@ -8,10 +8,8 @@ concurrency:
|
|||
jobs:
|
||||
backup-to-gitlabwh:
|
||||
uses: linuxdeepin/.github/.github/workflows/backup-to-gitlabwh.yml@master
|
||||
secrets:
|
||||
BRIDGETOKEN: ${{ secrets.BRIDGETOKEN }}
|
||||
secrets: inherit
|
||||
|
||||
backup-to-gitee:
|
||||
uses: linuxdeepin/.github/.github/workflows/backup-to-gitee.yml@master
|
||||
secrets:
|
||||
GITEE_SYNC_TOKEN: ${{ secrets.GITEE_SYNC_TOKEN }}
|
||||
secrets: inherit
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
name: auto tag
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, closed]
|
||||
paths:
|
||||
- "debian/changelog"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-pull/${{ github.event.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
auto_tag:
|
||||
uses: linuxdeepin/.github/.github/workflows/auto-tag.yml@master
|
||||
secrets: inherit
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
name: Call build-deb
|
||||
on:
|
||||
pull_request_target:
|
||||
paths-ignore:
|
||||
- ".github/workflows/**"
|
||||
types: [ opened, closed, synchronize ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-pull/${{ github.event.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
check_job:
|
||||
if: github.event.action != 'closed' || github.event.pull_request.merged
|
||||
uses: linuxdeepin/.github/.github/workflows/build-deb.yml@master
|
||||
secrets:
|
||||
BridgeToken: ${{ secrets.BridgeToken }}
|
||||
|
|
@ -10,8 +10,4 @@ on:
|
|||
jobs:
|
||||
check_job:
|
||||
uses: linuxdeepin/.github/.github/workflows/build-distribution.yml@master
|
||||
secrets:
|
||||
BUILD_GPG_PRIVATE_KEY: ${{ secrets.BUILD_GPG_PRIVATE_KEY }}
|
||||
BUILD_SSH_PRIVATE_KEY: ${{ secrets.BUILD_SSH_PRIVATE_KEY }}
|
||||
WEBDAV_PASSWD: ${{ secrets.WEBDAV_PASSWD }}
|
||||
WEBDAV_USER: ${{ secrets.WEBDAV_USER }}
|
||||
secrets: inherit
|
||||
|
|
|
|||
|
|
@ -6,5 +6,4 @@ on:
|
|||
jobs:
|
||||
chatopt:
|
||||
uses: linuxdeepin/.github/.github/workflows/chatOps.yml@master
|
||||
secrets:
|
||||
APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }}
|
||||
secrets: inherit
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
name: Call CLA check
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_target:
|
||||
types: [opened, closed, synchronize]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-pull/${{ github.event.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
clacheck:
|
||||
uses: linuxdeepin/.github/.github/workflows/cla-check.yml@master
|
||||
secrets:
|
||||
APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
name: tag build
|
||||
on:
|
||||
push:
|
||||
tags: "*"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
uses: linuxdeepin/.github/.github/workflows/tag-build.yml@master
|
||||
secrets: inherit
|
||||
|
|
@ -14,7 +14,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: export
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
|
|
|||
|
|
@ -1,2 +1,10 @@
|
|||
.idea/
|
||||
/build
|
||||
/build*
|
||||
/obj-x86_64-linux-gnu
|
||||
/debian/.debhelper
|
||||
/debian/linglong-box
|
||||
/debian/debhelper-build-stamp
|
||||
/debian/linglong-box.debhelper.log
|
||||
/debian/files
|
||||
/debian/linglong-box.substvars
|
||||
.vscode/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,42 @@
|
|||
test_build:
|
||||
steps:
|
||||
- link_package:
|
||||
source_project: deepin:Develop:dde
|
||||
source_package: %{SCM_REPOSITORY_NAME}
|
||||
target_project: deepin:CI
|
||||
|
||||
- configure_repositories:
|
||||
project: deepin:CI
|
||||
repositories:
|
||||
- name: deepin_develop
|
||||
paths:
|
||||
- target_project: deepin:CI
|
||||
target_repository: deepin_develop
|
||||
architectures:
|
||||
- x86_64
|
||||
- aarch64
|
||||
|
||||
- name: debian
|
||||
paths:
|
||||
- target_project: deepin:CI
|
||||
target_repository: debian_sid
|
||||
architectures:
|
||||
- x86_64
|
||||
filters:
|
||||
event: pull_request
|
||||
|
||||
tag_build:
|
||||
steps:
|
||||
- trigger_services:
|
||||
project: deepin:Unstable:dde
|
||||
package: %{SCM_REPOSITORY_NAME}
|
||||
filters:
|
||||
event: tag_push
|
||||
|
||||
commit_build:
|
||||
steps:
|
||||
- trigger_services:
|
||||
project: deepin:Develop:dde
|
||||
package: %{SCM_REPOSITORY_NAME}
|
||||
filters:
|
||||
event: push
|
||||
59
.reuse/dep5
59
.reuse/dep5
|
|
@ -1,59 +0,0 @@
|
|||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: linglong-box
|
||||
Upstream-Contact: UnionTech Software Technology Co., Ltd. <>
|
||||
Source: https://github.com/linuxdeepin/linglong-box
|
||||
|
||||
# ci
|
||||
Files: .github/* .gitlab-ci.yml test/data/demo/*.json test/data/demo/*.yaml test/data/demo/*.yml
|
||||
Copyright: None
|
||||
License: CC0-1.0
|
||||
|
||||
# Packaging configuration
|
||||
Files: rpm/* debian/* archlinux/*
|
||||
Copyright: None
|
||||
License: CC0-1.0
|
||||
|
||||
# README & DOC
|
||||
Files: README.md README.zh_CN.md INSTALL.md CHANGELOG.md doc/*.md src/*.md docs/*.md
|
||||
Copyright: UnionTech Software Technology Co., Ltd.
|
||||
License: CC-BY-4.0
|
||||
|
||||
# translation
|
||||
Files: translations/* plugins/*.ts
|
||||
Copyright: UnionTech Software Technology Co., Ltd.
|
||||
License: LGPL-3.0-or-later
|
||||
|
||||
# png svg
|
||||
Files: plugins/*.png plugins/*.svg frame/*.svg tests/*.png tests/*.svg
|
||||
Copyright: UnionTech Software Technology Co., Ltd.
|
||||
License: LGPL-3.0-or-later
|
||||
|
||||
# qrc
|
||||
Files: plugins/*.qrc frame/*.qrc tests/*.qrc
|
||||
Copyright: None
|
||||
License: CC0-1.0
|
||||
|
||||
# Project file
|
||||
Files: CMakeLists.txt .gitignore src/CMakeLists.txt test/CMakeLists.txt test/protype/CMakeLists.txt 3party/nlohmann/json.hpp 3party/optional/optional.hpp
|
||||
Copyright: None
|
||||
License: CC0-1.0
|
||||
|
||||
# xml toml json policy yaml
|
||||
Files: gschema/*.xml plugins/*.xml frame/*.xml .clog.toml plugins/*.json configs/*.json .packit.yaml .tx/config test/data/demo/*.json src/service/resource/*.json
|
||||
Copyright: None
|
||||
License: CC0-1.0
|
||||
|
||||
# in
|
||||
Files: .clang-format .cmake-format.py
|
||||
Copyright: None
|
||||
License: CC0-1.0
|
||||
|
||||
# sh
|
||||
Files: gen_report.sh lupdate.sh plugins/dcc-dock-plugin/translate_generation.sh tests/test-recoverage.sh translate_generation.sh scripts/*
|
||||
Copyright: None
|
||||
License: CC0-1.0
|
||||
|
||||
# xml2cpp
|
||||
Files: frame/dbus/* plugins/disk-mount/dbus/dbusdiskmount.* plugins/power/dbus/dbuspower.* plugins/shutdown/dbus/dbuspowermanager.* plugins/tray/dbus/dbustraymanager.* src/module/dbus_ipc/* src/module/dbus_ipc/*
|
||||
Copyright: The Qt Company Ltd.
|
||||
License: CC0-1.0
|
||||
File diff suppressed because it is too large
Load Diff
529
CMakeLists.txt
529
CMakeLists.txt
|
|
@ -1,31 +1,520 @@
|
|||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.11.4) # for RHEL 8
|
||||
|
||||
project(linglong-box)
|
||||
project(
|
||||
linyaps-box
|
||||
VERSION 2.1.3
|
||||
DESCRIPTION "A simple OCI runtime for desktop applications"
|
||||
HOMEPAGE_URL "https://github.com/OpenAtom-Linyaps/linyaps-box"
|
||||
LANGUAGES CXX)
|
||||
|
||||
# 保证项目兼容性
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
# ==============================================================================
|
||||
# Utilities
|
||||
# ==============================================================================
|
||||
|
||||
set(VERSION "1.0")
|
||||
# NOTE: Modified from https://www.scivision.dev/cmake-project-is-top-level/
|
||||
if(CMAKE_VERSION VERSION_LESS 3.21)
|
||||
get_property(
|
||||
not_top
|
||||
DIRECTORY
|
||||
PROPERTY PARENT_DIRECTORY)
|
||||
if(NOT not_top)
|
||||
set(linyaps-box_IS_TOP_LEVEL true)
|
||||
else()
|
||||
set(linyaps-box_IS_TOP_LEVEL false)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(BUILD_STATIC "Build the static binary" ON)
|
||||
# ==============================================================================
|
||||
# Build options
|
||||
# ==============================================================================
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
if (NOT CMAKE_DEBUG_ASAN)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -Wall -g -ggdb3")
|
||||
else ()
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -fsanitize=undefined,address -Wall -g -ggdb3")
|
||||
set(BUILD_STATIC OFF)
|
||||
endif ()
|
||||
endif ()
|
||||
option(linyaps-box_STATIC "Build linyaps-box as statically-linked binary." OFF)
|
||||
|
||||
option(linyaps-box_ENABLE_SECCOMP "Build linyaps-box with seccomp support." OFF)
|
||||
|
||||
option(linyaps-box_ENABLE_CAP "Build linyaps-box with capability support" ON)
|
||||
|
||||
option(linyaps-box_ENABLE_UNIT_TESTS "Enable unit tests."
|
||||
${linyaps-box_IS_TOP_LEVEL})
|
||||
|
||||
option(linyaps-box_ENABLE_SMOKE_TESTS "Enable smoke tests." OFF)
|
||||
|
||||
option(linyaps-box_MAKE_RELEASE "Make release build." OFF)
|
||||
|
||||
if(linyaps-box_ENABLE_SMOKE_TESTS OR linyaps-box_ENABLE_UNIT_TESTS)
|
||||
set(linyaps-box_ENABLE_TESTING ON)
|
||||
endif()
|
||||
|
||||
option(linyaps-box_ENABLE_COVERAGE "Enable coverage." OFF)
|
||||
|
||||
if(linyaps-box_ENABLE_COVERAGE AND NOT linyaps-box_ENABLE_TESTING)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"linyaps-box_ENABLE_COVERAGE requires linyaps-box_ENABLE_UNIT_TESTS or linyaps-box_ENABLE_SMOKE_TESTS."
|
||||
)
|
||||
endif()
|
||||
|
||||
option(linyaps-box_ENABLE_CPACK "Enable CPack." OFF)
|
||||
|
||||
if(linyaps-box_ENABLE_CPACK)
|
||||
set(linyaps-box_CPACK_PACKAGING_INSTALL_PREFIX
|
||||
"/opt/org.openatom.linyaps-box"
|
||||
CACHE STRING "Install prefix for package generated by CPack.")
|
||||
endif()
|
||||
|
||||
set(linyaps-box_CLONE_CHILD_STACK_SIZE
|
||||
"(1U << 20)"
|
||||
CACHE
|
||||
STRING
|
||||
"DO NOT MODIFY THIS SETTINGS UNLESS YOU KNOW WHAT YOU ARE DOING. Size of child stack in bytes when using clone(2) to create container."
|
||||
)
|
||||
|
||||
set(linyaps-box_STACK_GROWTH_DOWN
|
||||
true
|
||||
CACHE
|
||||
BOOL
|
||||
"DO NOT MODIFY THIS SETTINGS UNLESS YOU KNOW WHAT YOU ARE DOING. If stacks grow upward on your processor, set this to false."
|
||||
)
|
||||
|
||||
set(linyaps-box_DEFAULT_LOG_LEVEL
|
||||
LOG_WARNING
|
||||
CACHE
|
||||
STRING
|
||||
"The default syslog priority. This is used to filter log messages at runtime time."
|
||||
)
|
||||
|
||||
set(linyaps-box_ACTIVE_LOG_LEVEL
|
||||
LOG_WARNING
|
||||
CACHE
|
||||
STRING
|
||||
"The active syslog priority. This is used to filter log messages at compile time."
|
||||
)
|
||||
|
||||
set(linyaps-box_ENABLE_CPM
|
||||
OFF
|
||||
CACHE BOOL "enable CPM")
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS "3.14")
|
||||
set(linyaps-box_ENABLE_CPM OFF)
|
||||
message(
|
||||
STATUS "cmake version ${CMAKE_VERSION} not compatible with CPM.cmake.")
|
||||
endif()
|
||||
|
||||
# if just want to try local packages at first set CPM_USE_LOCAL_PACKAGES ON
|
||||
set(linyaps-box_CPM_LOCAL_PACKAGES_ONLY
|
||||
OFF
|
||||
CACHE BOOL "use local packages only")
|
||||
|
||||
# ==============================================================================
|
||||
|
||||
set(linyaps-box_LIBRARY linyaps-box)
|
||||
set(linyaps-box_LIBRARY_SOURCE
|
||||
# find -regex '\./src/.+\.[ch]\(pp\)?' -type f -printf '%P\n'| sort
|
||||
src/linyaps_box/app.cpp
|
||||
src/linyaps_box/app.h
|
||||
src/linyaps_box/cgroup.h
|
||||
src/linyaps_box/cgroup_manager.cpp
|
||||
src/linyaps_box/cgroup_manager.h
|
||||
src/linyaps_box/command/exec.cpp
|
||||
src/linyaps_box/command/exec.h
|
||||
src/linyaps_box/command/kill.cpp
|
||||
src/linyaps_box/command/kill.h
|
||||
src/linyaps_box/command/list.cpp
|
||||
src/linyaps_box/command/list.h
|
||||
src/linyaps_box/command/options.cpp
|
||||
src/linyaps_box/command/options.h
|
||||
src/linyaps_box/command/run.cpp
|
||||
src/linyaps_box/command/run.h
|
||||
src/linyaps_box/config.cpp
|
||||
src/linyaps_box/config.h
|
||||
src/linyaps_box/container.cpp
|
||||
src/linyaps_box/container.h
|
||||
src/linyaps_box/container_ref.cpp
|
||||
src/linyaps_box/container_ref.h
|
||||
src/linyaps_box/container_status.cpp
|
||||
src/linyaps_box/container_status.h
|
||||
src/linyaps_box/impl/disabled_cgroup_manager.cpp
|
||||
src/linyaps_box/impl/disabled_cgroup_manager.h
|
||||
src/linyaps_box/impl/json_printer.cpp
|
||||
src/linyaps_box/impl/json_printer.h
|
||||
src/linyaps_box/impl/status_directory.cpp
|
||||
src/linyaps_box/impl/status_directory.h
|
||||
src/linyaps_box/impl/table_printer.cpp
|
||||
src/linyaps_box/impl/table_printer.h
|
||||
src/linyaps_box/interface.cpp
|
||||
src/linyaps_box/interface.h
|
||||
src/linyaps_box/printer.cpp
|
||||
src/linyaps_box/printer.h
|
||||
src/linyaps_box/runtime.cpp
|
||||
src/linyaps_box/runtime.h
|
||||
src/linyaps_box/status_directory.cpp
|
||||
src/linyaps_box/status_directory.h
|
||||
src/linyaps_box/utils/atomic_write.cpp
|
||||
src/linyaps_box/utils/atomic_write.h
|
||||
src/linyaps_box/utils/cgroups.cpp
|
||||
src/linyaps_box/utils/cgroups.h
|
||||
src/linyaps_box/utils/close_range.cpp
|
||||
src/linyaps_box/utils/close_range.h
|
||||
src/linyaps_box/utils/defer.h
|
||||
src/linyaps_box/utils/file_describer.cpp
|
||||
src/linyaps_box/utils/file_describer.h
|
||||
src/linyaps_box/utils/fstat.cpp
|
||||
src/linyaps_box/utils/fstat.h
|
||||
src/linyaps_box/utils/inspect.cpp
|
||||
src/linyaps_box/utils/inspect.h
|
||||
src/linyaps_box/utils/log.cpp
|
||||
src/linyaps_box/utils/log.h
|
||||
src/linyaps_box/utils/mkdir.cpp
|
||||
src/linyaps_box/utils/mkdir.h
|
||||
src/linyaps_box/utils/mknod.cpp
|
||||
src/linyaps_box/utils/mknod.h
|
||||
src/linyaps_box/utils/open_file.cpp
|
||||
src/linyaps_box/utils/open_file.h
|
||||
src/linyaps_box/utils/platform.cpp
|
||||
src/linyaps_box/utils/platform.h
|
||||
src/linyaps_box/utils/semver.cpp
|
||||
src/linyaps_box/utils/semver.h
|
||||
src/linyaps_box/utils/socketpair.cpp
|
||||
src/linyaps_box/utils/socketpair.h
|
||||
src/linyaps_box/utils/symlink.cpp
|
||||
src/linyaps_box/utils/symlink.h
|
||||
src/linyaps_box/utils/touch.cpp
|
||||
src/linyaps_box/utils/touch.h)
|
||||
|
||||
set(LINYAPS_BOX_VERSION ${PROJECT_VERSION})
|
||||
|
||||
if(NOT linyaps-box_MAKE_RELEASE)
|
||||
message(STATUS "make dev build")
|
||||
|
||||
execute_process(
|
||||
COMMAND git rev-parse --short=7 HEAD
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE GIT_COMMIT_HASH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
set(LINYAPS_BOX_VERSION "${LINYAPS_BOX_VERSION}-dev-${GIT_COMMIT_HASH}")
|
||||
endif()
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/linyaps_box/version.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/src/linyaps_box/version.h @ONLY)
|
||||
|
||||
# for gcc 8
|
||||
set(linyaps-box_LIBRARY_LINK_LIBRARIES "stdc++fs")
|
||||
set(linyaps-box_LIBRARY_INCLUDE_DIRS PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/src")
|
||||
|
||||
if(linyaps-box_STATIC)
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||
endif()
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
if(linyaps-box_ENABLE_SECCOMP)
|
||||
pkg_check_modules(libseccomp REQUIRED IMPORTED_TARGET libseccomp>=2.3.3)
|
||||
list(APPEND linyaps-box_LIBRARY_LINK_LIBRARIES PUBLIC PkgConfig::libseccomp)
|
||||
endif()
|
||||
|
||||
if(linyaps-box_ENABLE_CAP)
|
||||
pkg_check_modules(libcap REQUIRED IMPORTED_TARGET libcap>=2.25)
|
||||
list(APPEND linyaps-box_LIBRARY_LINK_LIBRARIES PUBLIC PkgConfig::libcap)
|
||||
endif()
|
||||
|
||||
if(linyaps-box_ENABLE_CPM)
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
include(CPM)
|
||||
|
||||
if (linyaps-box_CPM_LOCAL_PACKAGES_ONLY)
|
||||
set(CPM_USE_LOCAL_PACKAGES ON)
|
||||
endif()
|
||||
|
||||
CPMFindPackage(
|
||||
NAME nlohmann_json
|
||||
VERSION 3.11.3
|
||||
GITHUB_REPOSITORY nlohmann/json
|
||||
GIT_TAG v3.12.0
|
||||
EXCLUDE_FROM_ALL ON
|
||||
OPTIONS "JSON_BuildTests OFF")
|
||||
CPMFindPackage(
|
||||
NAME CLI11
|
||||
VERSION 2.5.0
|
||||
GITHUB_REPOSITORY CLIUtils/CLI11
|
||||
GIT_TAG v2.5.0
|
||||
EXCLUDE_FROM_ALL ON
|
||||
OPTIONS "CLI11_BUILD_TESTS OFF")
|
||||
endif()
|
||||
|
||||
find_package(nlohmann_json 3.11.3 QUIET)
|
||||
if(NOT nlohmann_json_FOUND)
|
||||
add_subdirectory(external/nlohmann_json)
|
||||
list(APPEND CMAKE_MODULE_PATH
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake.external/nlohmann_json")
|
||||
find_package(nlohmann_json 3.11.3 REQUIRED)
|
||||
message(STATUS "use vendor nlohmann_json ${nlohmann_json_VERSION}")
|
||||
endif()
|
||||
|
||||
list(APPEND linyaps-box_LIBRARY_LINK_LIBRARIES PUBLIC
|
||||
nlohmann_json::nlohmann_json)
|
||||
|
||||
find_package(CLI11 2.5.0 QUIET)
|
||||
if(NOT CLI11_FOUND)
|
||||
add_subdirectory(external/CLI11)
|
||||
list(APPEND CMAKE_MODULE_PATH
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake.external/CLI11")
|
||||
find_package(CLI11 2.5.0 REQUIRED)
|
||||
message(STATUS "use vendor CLI11 ${CLI11_VERSION}")
|
||||
endif()
|
||||
|
||||
list(APPEND linyaps-box_LIBRARY_LINK_LIBRARIES PUBLIC CLI11::CLI11)
|
||||
|
||||
add_library("${linyaps-box_LIBRARY}" STATIC ${linyaps-box_LIBRARY_SOURCE})
|
||||
target_include_directories("${linyaps-box_LIBRARY}"
|
||||
${linyaps-box_LIBRARY_INCLUDE_DIRS})
|
||||
target_link_libraries("${linyaps-box_LIBRARY}"
|
||||
PRIVATE ${linyaps-box_LIBRARY_LINK_LIBRARIES})
|
||||
target_compile_features("${linyaps-box_LIBRARY}" PUBLIC cxx_std_17)
|
||||
set_property(TARGET "${linyaps-box_LIBRARY}" PROPERTY CXX_STANDARD 17)
|
||||
set_property(TARGET "${linyaps-box_LIBRARY}" PROPERTY CXX_EXTENSIONS OFF)
|
||||
set_property(TARGET "${linyaps-box_LIBRARY}" PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
include(CheckIncludeFileCXX)
|
||||
check_include_file_cxx("linux/openat2.h" LINYAPS_BOX_HAVE_OPENAT2_H)
|
||||
|
||||
if(${LINYAPS_BOX_HAVE_OPENAT2_H})
|
||||
target_compile_definitions("${linyaps-box_LIBRARY}"
|
||||
PRIVATE "LINYAPS_BOX_HAVE_OPENAT2_H")
|
||||
endif()
|
||||
|
||||
target_compile_definitions(
|
||||
"${linyaps-box_LIBRARY}"
|
||||
PRIVATE
|
||||
"LINYAPS_BOX_CLONE_CHILD_STACK_SIZE=${linyaps-box_CLONE_CHILD_STACK_SIZE}"
|
||||
PRIVATE "LINYAPS_BOX_STACK_GROWTH_DOWN=${linyaps-box_STACK_GROWTH_DOWN}"
|
||||
PRIVATE "LINYAPS_BOX_DEFAULT_LOG_LEVEL=${linyaps-box_DEFAULT_LOG_LEVEL}"
|
||||
PRIVATE "LINYAPS_BOX_ACTIVE_LOG_LEVEL=${linyaps-box_ACTIVE_LOG_LEVEL}")
|
||||
target_compile_options("${linyaps-box_LIBRARY}"
|
||||
PRIVATE -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}=.)
|
||||
if(linyaps-box_STATIC)
|
||||
target_compile_definitions("${linyaps-box_LIBRARY}"
|
||||
PUBLIC "LINYAPS_BOX_STATIC_LINK")
|
||||
endif()
|
||||
|
||||
if(linyaps-box_ENABLE_SECCOMP)
|
||||
target_compile_definitions("${linyaps-box_LIBRARY}"
|
||||
PUBLIC LINYAPS_BOX_ENABLE_SECCOMP)
|
||||
endif()
|
||||
|
||||
if(linyaps-box_ENABLE_CAP)
|
||||
target_compile_definitions("${linyaps-box_LIBRARY}"
|
||||
PUBLIC LINYAPS_BOX_ENABLE_CAP)
|
||||
endif()
|
||||
|
||||
if(linyaps-box_ENABLE_COVERAGE)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
target_compile_options("${linyaps-box_LIBRARY}"
|
||||
PRIVATE -fprofile-instr-generate -fcoverage-mapping)
|
||||
target_link_options("${linyaps-box_LIBRARY}" PUBLIC
|
||||
-fprofile-instr-generate -fcoverage-mapping)
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
target_compile_options("${linyaps-box_LIBRARY}" PRIVATE --coverage)
|
||||
target_link_options("${linyaps-box_LIBRARY}" PUBLIC --coverage)
|
||||
else()
|
||||
message(
|
||||
FATAL_ERROR "Coverage is not supported for ${CMAKE_CXX_COMPILER_ID}.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ==============================================================================
|
||||
|
||||
set(linyaps-box_APP ll-box)
|
||||
set(linyaps-box_APP_SOURCE "./app/${linyaps-box_APP}/src/main.cpp")
|
||||
set(linyaps-box_APP_LINK_LIBRARIES PRIVATE "${linyaps-box_LIBRARY}")
|
||||
set(linyaps-box_APP_SOURCE_INCLUDE_DIRS
|
||||
PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/app/${linyaps-box_APP}/src")
|
||||
|
||||
add_executable("${linyaps-box_APP}" ${linyaps-box_APP_SOURCE})
|
||||
target_include_directories("${linyaps-box_APP}"
|
||||
${linyaps-box_APP_SOURCE_INCLUDE_DIRS})
|
||||
target_link_libraries("${linyaps-box_APP}" ${linyaps-box_APP_LINK_LIBRARIES})
|
||||
if(linyaps-box_STATIC)
|
||||
target_link_options("${linyaps-box_APP}" PRIVATE -static -static-libgcc
|
||||
-static-libstdc++)
|
||||
endif()
|
||||
target_compile_features("${linyaps-box_APP}" PRIVATE cxx_std_17)
|
||||
set_property(TARGET "${linyaps-box_APP}" PROPERTY CXX_STANDARD 17)
|
||||
set_property(TARGET "${linyaps-box_APP}" PROPERTY CXX_EXTENSIONS OFF)
|
||||
set_property(TARGET "${linyaps-box_APP}" PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
target_compile_definitions(
|
||||
"${linyaps-box_APP}"
|
||||
PRIVATE "LINYAPS_BOX_DEFAULT_LOG_LEVEL=${linyaps-box_DEFAULT_LOG_LEVEL}"
|
||||
PRIVATE "LINYAPS_BOX_ACTIVE_LOG_LEVEL=${linyaps-box_AVTIVE_LOG_LEVEL}")
|
||||
target_compile_options("${linyaps-box_APP}"
|
||||
PRIVATE -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}=.)
|
||||
|
||||
# ==============================================================================
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include_directories(${linglong-box_SOURCE_DIR})
|
||||
include_directories(${linglong-box_SOURCE_DIR}/src)
|
||||
|
||||
# parameter TYPE was added in CMake 3.14
|
||||
if(CMAKE_VERSION VERSION_LESS "3.14")
|
||||
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${linyaps-box_APP}"
|
||||
DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
||||
else()
|
||||
install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${linyaps-box_APP}" TYPE BIN)
|
||||
endif()
|
||||
|
||||
find_package(PkgConfig)
|
||||
if(linyaps-box_ENABLE_CPACK)
|
||||
set(CPACK_PACKAGING_INSTALL_PREFIX
|
||||
"${linyaps-box_CPACK_PACKAGING_INSTALL_PREFIX}")
|
||||
set(CPACK_PACKAGE_CONTACT "chenlinxuan@uniontech.com")
|
||||
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
||||
set(CPACK_RPM_PACKAGE_AUTOREQ ON)
|
||||
include(CPack)
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
# ==============================================================================
|
||||
|
||||
add_subdirectory(test)
|
||||
if(NOT linyaps-box_ENABLE_TESTING)
|
||||
return()
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
|
||||
include(GoogleTest)
|
||||
|
||||
set(linyaps-box_UNIT_TESTS ll-box-ut)
|
||||
set(linyaps-box_UNIT_TESTS_SOURCE ./tests/ll-box-ut/src/test.cpp)
|
||||
set(linyaps-box_UNIT_TESTS_LINK_LIBRARIES PRIVATE "${linyaps-box_LIBRARY}")
|
||||
set(linyaps-box_UNIT_TESTS_SOURCE_INCLUDE_DIRS
|
||||
PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/tests/ll-box-ut/src")
|
||||
|
||||
find_package(GTest REQUIRED)
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS 3.20)
|
||||
add_library(GTest::gtest_main INTERFACE IMPORTED)
|
||||
target_link_libraries(GTest::gtest_main INTERFACE GTest::Main)
|
||||
endif()
|
||||
|
||||
list(APPEND linyaps-box_UNIT_TESTS_LINK_LIBRARIES PRIVATE GTest::gtest_main)
|
||||
|
||||
add_executable("${linyaps-box_UNIT_TESTS}" ${linyaps-box_UNIT_TESTS_SOURCE})
|
||||
target_include_directories("${linyaps-box_UNIT_TESTS}"
|
||||
${linyaps-box_UNIT_TESTS_SOURCE_INCLUDE_DIRS})
|
||||
target_link_libraries("${linyaps-box_UNIT_TESTS}"
|
||||
${linyaps-box_UNIT_TESTS_LINK_LIBRARIES})
|
||||
target_compile_features("${linyaps-box_UNIT_TESTS}" PRIVATE cxx_std_17)
|
||||
set_property(TARGET "${linyaps-box_UNIT_TESTS}" PROPERTY CXX_STANDARD 17)
|
||||
set_property(TARGET "${linyaps-box_UNIT_TESTS}" PROPERTY CXX_EXTENSIONS OFF)
|
||||
set_property(TARGET "${linyaps-box_UNIT_TESTS}" PROPERTY CXX_STANDARD_REQUIRED
|
||||
ON)
|
||||
target_compile_options("${linyaps-box_UNIT_TESTS}"
|
||||
PRIVATE -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}=.)
|
||||
|
||||
set(GTEST_DISCOVER_TESTS_ARGS "${linyaps-box_UNIT_TESTS}" WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/ll-box-ut")
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
list(APPEND GTEST_DISCOVER_TESTS_ARGS PROPERTIES ENVIRONMENT
|
||||
"LLVM_PROFILE_FILE=/dev/null")
|
||||
endif()
|
||||
|
||||
gtest_discover_tests(${GTEST_DISCOVER_TESTS_ARGS})
|
||||
|
||||
function(setup_linyaps_box_smoke_tests)
|
||||
if(NOT linyaps-box_ENABLE_SMOKE_TESTS)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(linyaps-box_SMOKE_TESTS
|
||||
./tests/ll-box-st/01-run-whoami.json
|
||||
./tests/ll-box-st/02-check-procfs.json
|
||||
./tests/ll-box-st/03-check-mounts.json
|
||||
./tests/ll-box-st/04-check-noNewPrivs.json
|
||||
./tests/ll-box-st/05-check-env.json
|
||||
./tests/ll-box-st/06-check-cwd.json
|
||||
./tests/ll-box-st/07-check-capability.json
|
||||
./tests/ll-box-st/08-check-umask.json
|
||||
./tests/ll-box-st/09-check-rlimit.json
|
||||
./tests/ll-box-st/10-check-oom.json
|
||||
./tests/ll-box-st/11-output-to-null.json
|
||||
./tests/ll-box-st/12-bind-host-dev.json
|
||||
./tests/ll-box-st/13-pid-extension.json)
|
||||
|
||||
foreach(test ${linyaps-box_SMOKE_TESTS})
|
||||
add_test(
|
||||
NAME "${test}"
|
||||
COMMAND
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/ll-box-st/ll-box-st"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${linyaps-box_APP}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/st-data"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${test}")
|
||||
list(APPEND linyaps-box_TESTS "${test}")
|
||||
|
||||
set_tests_properties(
|
||||
"${test}"
|
||||
PROPERTIES
|
||||
ENVIRONMENT
|
||||
"LSAN_OPTIONS=suppressions=${CMAKE_CURRENT_LIST_DIR}/tests/ll-box-st/glibc_leaks.txt"
|
||||
)
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
setup_linyaps_box_smoke_tests()
|
||||
|
||||
function(setup_linyaps_box_coverage)
|
||||
if(NOT linyaps-box_ENABLE_COVERAGE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(COVERAGE_INFO "coverage.info")
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set_tests_properties(
|
||||
${linyaps-box_TESTS}
|
||||
PROPERTIES ENVIRONMENT
|
||||
"LLVM_PROFILE_FILE=${CMAKE_CURRENT_BINARY_DIR}/default.profraw"
|
||||
)
|
||||
|
||||
find_program(LLVM_PROFDATA llvm-profdata REQUIRED)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT default.profdata
|
||||
DEPENDS "${linyaps-box_APP}" test
|
||||
COMMAND "${LLVM_PROFDATA}" merge -sparse default.profraw -o
|
||||
default.profdata)
|
||||
|
||||
find_program(LLVM_COV llvm-cov REQUIRED)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT coverage.info
|
||||
DEPENDS default.profdata
|
||||
COMMAND "${LLVM_COV}" show -instr-profile=default.profdata
|
||||
-object="$<TARGET_FILE_NAME:${linyaps-box_APP}>" > coverage.info)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT coverage.tar.gz
|
||||
DEPENDS default.profdata
|
||||
COMMAND rm -rf coverage
|
||||
COMMAND
|
||||
"${LLVM_COV}" show -instr-profile=default.profdata -format=html
|
||||
-object="$<TARGET_FILE_NAME:${linyaps-box_APP}>" -output-dir=coverage
|
||||
COMMAND tar -czf coverage-html.tar.gz coverage)
|
||||
|
||||
add_custom_target(coverage DEPENDS coverage.info coverage.tar.gz)
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
find_program(LCOV lcov REQUIRED)
|
||||
find_program(SED sed REQUIRED)
|
||||
add_custom_target(
|
||||
coverage
|
||||
COMMAND "${LCOV}" --capture --directory . --output-file coverage.info
|
||||
--branch-coverage --rc geninfo_unexecuted_blocks=1
|
||||
COMMAND "${LCOV}" --remove coverage.info '/usr/*' --output-file
|
||||
coverage.info
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
|
||||
DEPENDS "${linyaps-box_APP}" test)
|
||||
else()
|
||||
message(
|
||||
FATAL_ERROR "Coverage is not supported for ${CMAKE_CXX_COMPILER_ID}.")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
setup_linyaps_box_coverage()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,211 @@
|
|||
{
|
||||
"version": 10,
|
||||
"cmakeMinimumRequired": {
|
||||
"major": 3,
|
||||
"minor": 25,
|
||||
"patch": 0
|
||||
},
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "dev",
|
||||
"displayName": "The developer profile",
|
||||
"description": "The default configuration for developers",
|
||||
"binaryDir": "${sourceDir}/build-dev",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_COLOR_DIAGNOSTICS": true,
|
||||
"CMAKE_CXX_FLAGS": "-Wall -Wextra -Wpedantic -Werror -O0 -g3 -fsanitize=address,undefined $env{CXXFLAGS}",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": true,
|
||||
"linyaps-box_ENABLE_COVERAGE": true,
|
||||
"linyaps-box_ENABLE_CPACK": true,
|
||||
"linyaps-box_CPACK_PACKAGING_INSTALL_PREFIX": "",
|
||||
"linyaps-box_ENABLE_SMOKE_TESTS": true,
|
||||
"linyaps-box_DEFAULT_LOG_LEVEL": "7",
|
||||
"linyaps-box_ACTIVE_LOG_LEVEL": "7",
|
||||
"linyaps-box_ENABLE_CPM": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "release",
|
||||
"displayName": "The release profile",
|
||||
"description": "The default configuration for release",
|
||||
"binaryDir": "${sourceDir}/build-release",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"CMAKE_COLOR_DIAGNOSTICS": true,
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": true,
|
||||
"linyaps-box_ENABLE_CPACK": "ON",
|
||||
"linyaps-box_MAKE_RELEASE": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "static",
|
||||
"displayName": "The static build profile",
|
||||
"description": "The default configuration for produce static binary",
|
||||
"binaryDir": "${sourceDir}/build-static",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "MinSizeRel",
|
||||
"CMAKE_COLOR_DIAGNOSTICS": true,
|
||||
"CMAKE_CXX_FLAGS": "-fno-asynchronous-unwind-tables -fdata-sections -ffunction-sections -flto=auto $env{CXXFLAGS}",
|
||||
"CMAKE_EXE_LINKER_FLAGS_INIT": "-Wl,--gc-sections,--strip-all,--exclude-libs,ALL -flto=auto",
|
||||
"linyaps-box_STATIC": true,
|
||||
"linyaps-box_ENABLE_CPACK": "ON",
|
||||
"linyaps-box_MAKE_RELEASE": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci",
|
||||
"displayName": "The CI profile",
|
||||
"description": "The default configuration for CI",
|
||||
"binaryDir": "${sourceDir}/build-ci",
|
||||
"cacheVariables": {
|
||||
"CMAKE_COLOR_DIAGNOSTICS": true,
|
||||
"CMAKE_CXX_FLAGS": "-Wall -Wextra -Wpedantic -Werror -fsanitize=address,undefined $env{CXXFLAGS}",
|
||||
"linyaps-box_ENABLE_COVERAGE": true,
|
||||
"linyaps-box_ENABLE_SMOKE_TESTS": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "dev",
|
||||
"configurePreset": "dev"
|
||||
},
|
||||
{
|
||||
"name": "release",
|
||||
"configurePreset": "release"
|
||||
},
|
||||
{
|
||||
"name": "ci",
|
||||
"configurePreset": "ci"
|
||||
},
|
||||
{
|
||||
"name": "static",
|
||||
"configurePreset": "static"
|
||||
}
|
||||
],
|
||||
"testPresets": [
|
||||
{
|
||||
"name": "dev",
|
||||
"configurePreset": "dev",
|
||||
"output": {
|
||||
"outputOnFailure": true
|
||||
},
|
||||
"execution": {
|
||||
"noTestsAction": "default",
|
||||
"stopOnFailure": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "release",
|
||||
"configurePreset": "release",
|
||||
"output": {
|
||||
"outputOnFailure": true
|
||||
},
|
||||
"execution": {
|
||||
"noTestsAction": "default",
|
||||
"stopOnFailure": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ci",
|
||||
"configurePreset": "ci",
|
||||
"output": {
|
||||
"verbosity": "verbose"
|
||||
},
|
||||
"execution": {
|
||||
"noTestsAction": "default",
|
||||
"stopOnFailure": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "static",
|
||||
"configurePreset": "static",
|
||||
"output": {
|
||||
"verbosity": "verbose"
|
||||
},
|
||||
"execution": {
|
||||
"noTestsAction": "default",
|
||||
"stopOnFailure": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"workflowPresets": [
|
||||
{
|
||||
"name": "dev",
|
||||
"displayName": "The default workflow for developers",
|
||||
"description": "Configure, build then test with dev profile",
|
||||
"steps": [
|
||||
{
|
||||
"type": "configure",
|
||||
"name": "dev"
|
||||
},
|
||||
{
|
||||
"type": "build",
|
||||
"name": "dev"
|
||||
},
|
||||
{
|
||||
"type": "test",
|
||||
"name": "dev"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "release",
|
||||
"displayName": "The default workflow for release",
|
||||
"description": "Configure, build then test with release profile",
|
||||
"steps": [
|
||||
{
|
||||
"type": "configure",
|
||||
"name": "release"
|
||||
},
|
||||
{
|
||||
"type": "build",
|
||||
"name": "release"
|
||||
},
|
||||
{
|
||||
"type": "test",
|
||||
"name": "release"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ci",
|
||||
"displayName": "The default workflow for CI",
|
||||
"description": "Configure, build then test with CI profile",
|
||||
"steps": [
|
||||
{
|
||||
"type": "configure",
|
||||
"name": "ci"
|
||||
},
|
||||
{
|
||||
"type": "build",
|
||||
"name": "ci"
|
||||
},
|
||||
{
|
||||
"type": "test",
|
||||
"name": "ci"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "static",
|
||||
"displayName": "The default workflow for static build",
|
||||
"description": "Configure, build then test with static profile",
|
||||
"steps": [
|
||||
{
|
||||
"type": "configure",
|
||||
"name": "static"
|
||||
},
|
||||
{
|
||||
"type": "build",
|
||||
"name": "static"
|
||||
},
|
||||
{
|
||||
"type": "test",
|
||||
"name": "static"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
Copyright (c) <year> <owner>.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
@ -2,8 +2,17 @@ MIT License
|
|||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial
|
||||
portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
||||
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
|
|
|||
77
README.md
77
README.md
|
|
@ -1,79 +1,24 @@
|
|||
# 玲珑:沙箱
|
||||
# linyaps-box
|
||||
|
||||
玲珑(Linglong) is the container application toolkit of deepin.
|
||||
\[ **en** | [zh_CN](./README.zh_CN.md) \]
|
||||
|
||||
玲珑是玲珑塔的简称,既表示容器能对应用有管控作用,也表明了应用/运行时/系统向塔一样分层的思想。
|
||||
[](https://repology.org/project/linyaps-box/versions)
|
||||
|
||||
## Feature
|
||||
This project is a simple [OCI runtime] mainly used by [linyaps],
|
||||
which is a toolkit for Linux desktop application distributing.
|
||||
|
||||
- [x] Standard oci runtime
|
||||
[OCI runtime]: https://github.com/opencontainers/runtime-spec
|
||||
[linyaps]: https://github.com/OpenAtom-Linyaps/linyaps
|
||||
|
||||
## Roadmap
|
||||
## Build
|
||||
|
||||
### Current
|
||||
|
||||
- [ ] OCI Standard Box
|
||||
|
||||
## Dependencies
|
||||
It is recommend to use [cmake-presets]:
|
||||
|
||||
```bash
|
||||
#For release based on debian
|
||||
sudo apt-get install cmake build-essential libyaml-cpp-dev nlohmann-json3-dev libgtest-dev
|
||||
cmake --workflow --preset=dev
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
## Roadmap
|
||||
|
||||
### Current
|
||||
|
||||
- [ ] Configuration
|
||||
- [x] Root
|
||||
- [ ] Mount
|
||||
- [ ] Cgroup
|
||||
- [X] Hostname
|
||||
- [ ] Linux Container
|
||||
- [x] Default Filesystems
|
||||
- [X] Namespaces
|
||||
- [x] Network
|
||||
- [X] User namespace mappings
|
||||
- [ ] Devices
|
||||
- [ ] Default Devices
|
||||
- [ ] Control groups
|
||||
- [ ] IntelRdt
|
||||
- [ ] Sysctl
|
||||
- [ ] Seccomp
|
||||
- [ ] Rootfs Mount Propagation
|
||||
- [ ] Masked Paths
|
||||
- [ ] Readonly Paths
|
||||
- [ ] Mount Label
|
||||
- [ ] Extend
|
||||
- [x] Container manager
|
||||
- [x] Debug
|
||||
- [ ] DBus proxy permission control
|
||||
- [ ] Filesystem permission control base fuse
|
||||
- [ ] X11&&Wayland security
|
||||
|
||||
### TODO
|
||||
|
||||
- [ ] full support of parse all seccomp arch and syscall
|
||||
|
||||
## Getting help
|
||||
|
||||
Any usage issues can ask for help via
|
||||
|
||||
- [Gitter](https://gitter.im/orgs/linuxdeepin/rooms)
|
||||
- [IRC channel](https://webchat.freenode.net/?channels=deepin)
|
||||
- [Forum](https://bbs.deepin.org)
|
||||
- [WiKi](https://wiki.deepin.org/)
|
||||
|
||||
## Getting involved
|
||||
|
||||
We encourage you to report issues and contribute changes
|
||||
|
||||
- [Contribution guide for developers](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers-en)
|
||||
. (English)
|
||||
- [开发者代码贡献指南](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers) (中文)
|
||||
[cmake-presets]: https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
|||
|
|
@ -1,78 +1,25 @@
|
|||
# 玲珑:沙箱
|
||||
# linyaps-box
|
||||
|
||||
玲珑是玲珑塔的简称,既表示容器能对应用有管控作用,也表明了应用/运行时/系统向塔一样分层的思想。
|
||||
\[ [en](./README.md) | **zh_CN** \]
|
||||
|
||||
## Feature
|
||||
[](https://repology.org/project/linyaps-box/versions)
|
||||
|
||||
- [x] Standard oci runtime
|
||||
这个项目是一个简单的[OCI运行时],主要由[玲珑]使用,
|
||||
玲珑是一个用于Linux桌面应用程序分发的工具包。
|
||||
|
||||
## Roadmap
|
||||
[OCI运行时]: https://github.com/opencontainers/runtime-spec
|
||||
[玲珑]: https://github.com/OpenAtom-Linyaps/linyaps
|
||||
|
||||
### Current
|
||||
## 构建
|
||||
|
||||
- [ ] OCI Standard Box
|
||||
|
||||
## Dependencies
|
||||
推荐使用[cmake-presets]:
|
||||
|
||||
```bash
|
||||
#For release based on debian
|
||||
sudo apt-get install cmake build-essential libyaml-cpp-dev nlohmann-json3-dev libgtest-dev
|
||||
cmake --workflow --preset=dev
|
||||
```
|
||||
|
||||
## Installation
|
||||
[cmake-presets]: https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html
|
||||
|
||||
## Roadmap
|
||||
## 许可证
|
||||
|
||||
### Current
|
||||
|
||||
- [ ] Configuration
|
||||
- [x] Root
|
||||
- [ ] Mount
|
||||
- [ ] Cgroup
|
||||
- [X] Hostname
|
||||
- [ ] Linux Container
|
||||
- [x] Default Filesystems
|
||||
- [X] Namespaces
|
||||
- [x] Network
|
||||
- [X] User namespace mappings
|
||||
- [ ] Devices
|
||||
- [ ] Default Devices
|
||||
- [ ] Control groups
|
||||
- [ ] IntelRdt
|
||||
- [ ] Sysctl
|
||||
- [ ] Seccomp
|
||||
- [ ] Rootfs Mount Propagation
|
||||
- [ ] Masked Paths
|
||||
- [ ] Readonly Paths
|
||||
- [ ] Mount Label
|
||||
- [ ] Extend
|
||||
- [x] Container manager
|
||||
- [x] Debug
|
||||
- [ ] DBus proxy permission control
|
||||
- [ ] Filesystem permission control base fuse
|
||||
- [ ] X11&&Wayland security
|
||||
|
||||
### TODO
|
||||
|
||||
- [ ] full support of parse all seccomp arch and syscall
|
||||
|
||||
## Getting help
|
||||
|
||||
Any usage issues can ask for help via
|
||||
|
||||
- [Gitter](https://gitter.im/orgs/linuxdeepin/rooms)
|
||||
- [IRC channel](https://webchat.freenode.net/?channels=deepin)
|
||||
- [Forum](https://bbs.deepin.org)
|
||||
- [WiKi](https://wiki.deepin.org/)
|
||||
|
||||
## Getting involved
|
||||
|
||||
We encourage you to report issues and contribute changes
|
||||
|
||||
- [Contribution guide for developers](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers-en)
|
||||
. (English)
|
||||
- [开发者代码贡献指南](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers) (中文)
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under [LGPL-3.0-or-later](LICENSE).
|
||||
本项目使用[LGPL-3.0-or-later](LICENSE)许可证授权。
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
version = 1
|
||||
SPDX-PackageName = "linglong-box"
|
||||
SPDX-PackageSupplier = "UnionTech Software Technology Co., Ltd. <>"
|
||||
SPDX-PackageDownloadLocation = "https://github.com/linuxdeepin/linglong-box"
|
||||
|
||||
[[annotations]]
|
||||
path = [
|
||||
".github/**",
|
||||
".gitlab-ci.yml",
|
||||
"tests/ll-box-st/**.json",
|
||||
"tests/ll-box-st/*.txt",
|
||||
"tests/ll-box-ut/data/**",
|
||||
".obs/workflows.yml",
|
||||
]
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "UnionTech Software Technology Co., Ltd."
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = [
|
||||
"README.md",
|
||||
"README.zh_CN.md",
|
||||
]
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "UnionTech Software Technology Co., Ltd."
|
||||
SPDX-License-Identifier = "CC-BY-4.0"
|
||||
|
||||
[[annotations]]
|
||||
path = [
|
||||
"CMakePresets.json",
|
||||
"CMakeLists.txt",
|
||||
".gitignore",
|
||||
"tests/ll-box-ut/.gitignore",
|
||||
]
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "UnionTech Software Technology Co., Ltd."
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = [".clang-format", ".cmake-format.py"]
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "UnionTech Software Technology Co., Ltd."
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = ["cmake/CPM.cmake"]
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2019-2023 Lars Melchior and contributors"
|
||||
SPDX-License-Identifier = "MIT"
|
||||
|
||||
[[annotations]]
|
||||
path = ["cmake.external/**"]
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "UnionTech Software Technology Co., Ltd."
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = ["external/nlohmann_json/include/**"]
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2013-2023 Niels Lohmann <https://nlohmann.me>"
|
||||
SPDX-License-Identifier = "MIT"
|
||||
|
||||
[[annotations]]
|
||||
path = ["external/CLI11/include/**"]
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2017-2025 University of Cincinnati, developed by Henry Schreiner under NSF AWARD 1414736."
|
||||
SPDX-License-Identifier = "BSD-3-Clause"
|
||||
|
||||
[[annotations]]
|
||||
path = ["external/*/CMakeLists.txt"]
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "UnionTech Software Technology Co., Ltd."
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/app.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return linyaps_box::main(argc, argv);
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
if(TARGET CLI11::CLI11)
|
||||
set(CLI11_FOUND TRUE)
|
||||
|
||||
# Set version variables
|
||||
set(CLI11_VERSION_MAJOR 2)
|
||||
set(CLI11_VERSION_MINOR 5)
|
||||
set(CLI11_VERSION_PATCH 0)
|
||||
set(CLI11_VERSION "2.5.0")
|
||||
endif()
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
if(TARGET nlohmann_json::nlohmann_json)
|
||||
set(nlohmann_json_FOUND TRUE)
|
||||
|
||||
# Set version variables
|
||||
set(nlohmann_json_VERSION_MAJOR 3)
|
||||
set(nlohmann_json_VERSION_MINOR 12)
|
||||
set(nlohmann_json_VERSION_PATCH 0)
|
||||
set(nlohmann_json_VERSION "3.12.0")
|
||||
endif()
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,149 +0,0 @@
|
|||
linglong-box (1.3.3.15-1) unstable; urgency=medium
|
||||
|
||||
* update version.
|
||||
|
||||
-- huqinghong <huqinghong@uniontech.com> Tue, 27 Dec 2022 14:54:52 +0800
|
||||
|
||||
linglong-box (1.3.3.14-1) unstable; urgency=medium
|
||||
|
||||
* update version.
|
||||
|
||||
-- yuanqiliang <yuanqiliang@uniontech.com> Thu, 25 Nov 2022 11:02:00 +0800
|
||||
|
||||
linglong-box (1.3.3.13-1) unstable; urgency=medium
|
||||
|
||||
* update version.
|
||||
|
||||
-- Chen Linxuan <chenlinxuan@uniontech.com> Thu, 24 Nov 2022 11:02:00 +0800
|
||||
|
||||
linglong-box (1.3.3.12-1) unstable; urgency=medium
|
||||
|
||||
* update version.
|
||||
|
||||
-- Chen Linxuan <chenlinxuan@uniontech.com> Thu, 27 Oct 2022 14:58:00 +0800
|
||||
|
||||
linglong-box (1.3.3.11-1) unstable; urgency=medium
|
||||
|
||||
* update version to 1.3.3.11-1 for deepin.
|
||||
|
||||
-- huqinghong <huqinghong@uniontech.com> Wed, 26 Oct 2022 15:33:06 +0800
|
||||
|
||||
linglong-box (1.3.3.10-1) unstable; urgency=medium
|
||||
|
||||
* update version.
|
||||
|
||||
-- chenhuixing <chenhuixing@uniontech.com> Fri, 23 Sep 2022 11:19:11 +0800
|
||||
|
||||
linglong-box (1.3.3.9-1) unstable; urgency=medium
|
||||
|
||||
* update version.
|
||||
|
||||
-- chenlinxuan <chenlinxuan@uniontech.com> Thu, 22 Sep 2022 11:09:15 +0800
|
||||
|
||||
linglong-box (1.3.3.7-1) unstable; urgency=medium
|
||||
|
||||
* update version.
|
||||
|
||||
-- chenhuixing <chenhuixing@uniontech.com> Tue, 06 Sep 2022 10:58:15 +0800
|
||||
|
||||
linglong-box (1.3.3.5-1) unstable; urgency=medium
|
||||
|
||||
* update version to 1.3.3.5-1 for deepin.
|
||||
|
||||
-- liujianqiang <liujianqiang@uniontech.com> Mon, 01 Aug 2022 20:50:57 +0800
|
||||
|
||||
linglong-box (1.3.3-1) unstable; urgency=medium
|
||||
|
||||
* update version to 1.3.3-1 for deepin.
|
||||
|
||||
-- liujianqiang <liujianqiang@uniontech.com> Thu, 28 Jul 2022 15:29:46 +0800
|
||||
|
||||
linglong-box (1.3.2-1) unstable; urgency=medium
|
||||
|
||||
* update version.
|
||||
|
||||
-- liujianqiang <liujianqiang@uniontech.com> Fri, 24 Jun 2022 16:56:42 +0800
|
||||
|
||||
linglong-box (1.3.0-1) unstable; urgency=medium
|
||||
|
||||
* update version.
|
||||
|
||||
-- liujianqiang <liujianqiang@uniontech.com> Fri, 27 May 2022 17:45:46 +0800
|
||||
|
||||
linglong-box (1.2.7-1) unstable; urgency=medium
|
||||
|
||||
* fix build issue.
|
||||
|
||||
-- liujianqiang <liujianqiang@uniontech.com> Fri, 15 Apr 2022 18:33:27 +0800
|
||||
|
||||
linglong-box (1.2.6-1) unstable; urgency=medium
|
||||
|
||||
* 1. adjust wait pid strategy.
|
||||
* 2. print pidns in log.
|
||||
* 3. configure uid/gid mapping after clone.
|
||||
* 4. remove CLONE-FS flag when cloning NonePrivilegeProc.
|
||||
* 5. wrong /dev/ptmx link.
|
||||
|
||||
-- liujianqiang <liujianqiang@uniontech.com> Tue, 22 Mar 2022 13:38:53 +0800
|
||||
|
||||
linglong-box (1.2.5-1) unstable; urgency=medium
|
||||
|
||||
* 1. rename json fields.
|
||||
* 2. close leaked fds.
|
||||
* 3. remove forced CLONE_NEWPID flag for second clone.
|
||||
* 4. add waitpid helper.
|
||||
* 5. add support for dbus proxy.
|
||||
* 6. remove unused code.
|
||||
|
||||
-- liujianqiang <liujianqiang@uniontech.com> Tue, 15 Mar 2022 10:04:16 +0800
|
||||
|
||||
linglong-box (1.2.4-1) unstable; urgency=medium
|
||||
|
||||
* 1. void c_str() of destoryed string
|
||||
|
||||
-- chenlinxuan <chenlinxuan@uniontech.com> Tue, 08 Mar 2022 13:27:24 +0800
|
||||
|
||||
linglong-box (1.2.3-1) unstable; urgency=medium
|
||||
|
||||
* 1. make fuse-overlayfs defalut.
|
||||
* 2. fix update error info.
|
||||
* 3. fix do mount by proc fd.
|
||||
|
||||
-- liujianqiang <liujianqiang@uniontech.com> Tue, 08 Mar 2022 13:27:24 +0800
|
||||
|
||||
linglong-box (1.2.2-1) unstable; urgency=medium
|
||||
|
||||
* 1. fix read/write /dev/null failed.
|
||||
* 2. add log fliter.
|
||||
* 3. fix mount mqueue amd cgroup in rootless mode.
|
||||
* 4. fix make mountnode const again.
|
||||
* 5. fix make ro bind work.
|
||||
|
||||
-- liujianqiang <liujianqiang@uniontech.com> Wed, 16 Feb 2022 13:47:58 +0800
|
||||
|
||||
linglong-box (1.2.1-1) unstable; urgency=medium
|
||||
|
||||
* 1. fuse proxy support
|
||||
* 2. fix construct string with nullptr cause crash
|
||||
* 3. fallback to bind when sysfs mount failed
|
||||
* 4. root mount for ll-fuse-proxy
|
||||
|
||||
-- liujianqiang <liujianqiang@uniontech.com> Mon, 24 Jan 2022 08:55:58 +0800
|
||||
|
||||
linglong-box (1.2.0-1) unstable; urgency=medium
|
||||
|
||||
* mount add a MS_REC flag
|
||||
|
||||
-- liujianqiang <liujianqiang@uniontech.com> Fri, 14 Jan 2022 10:51:13 +0800
|
||||
|
||||
linglong-box (1.0.1-1) unstable; urgency=medium
|
||||
|
||||
* support rootless and fuse
|
||||
|
||||
-- iceyer <me@iceyer.net> Wed, 29 Dec 2021 17:57:01 +0800
|
||||
|
||||
linglong-box (1.0-1) unstable; urgency=medium
|
||||
|
||||
* Init package.
|
||||
|
||||
-- chenhuixing <chenhuixing@uniontech.com> Thu, 09 Sep 2021 11:41:48 +0000
|
||||
|
|
@ -1 +0,0 @@
|
|||
11
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
Source: linglong-box
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Maintainer: Deepin Packages Builder <packages@deepin.org>
|
||||
Build-Depends:
|
||||
debhelper (>= 11),
|
||||
cmake,
|
||||
libyaml-cpp-dev,
|
||||
pkg-config,
|
||||
libseccomp-dev,
|
||||
libgtest-dev
|
||||
Standards-Version: 4.1.3
|
||||
Homepage: https://www.deepin.org
|
||||
|
||||
Package: linglong-box
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}
|
||||
Description: Deepin sandbox with OCI standard.
|
||||
Deepin sandbox...
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: linglong-box
|
||||
|
||||
Files: *
|
||||
Copyright: 2017 Deepin Technology Co., Ltd.
|
||||
License: GPL-3+
|
||||
This package is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
.
|
||||
This package is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
.
|
||||
On Debian systems, the complete text of the GNU General
|
||||
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
|
||||
|
|
@ -1 +0,0 @@
|
|||
linglong-box: statically-linked-binary usr/bin/ll-box-static
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
#!/usr/bin/make -f
|
||||
include /usr/share/dpkg/default.mk
|
||||
DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
|
||||
|
||||
%:
|
||||
dh $@
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
-DAPP_VERSION=$(DEB_VERSION_UPSTREAM) -DVERSION=$(DEB_VERSION_UPSTREAM) LIB_INSTALL_DIR=/usr/lib DH_AUTO_ARGS
|
||||
|
|
@ -1 +0,0 @@
|
|||
3.0 (quilt)
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
# Filesystem Drivers
|
||||
|
||||
For a container, there are always need to create some file not exist. So we need use a virtual filesystem to mount file not exist or override lower file.
|
||||
|
||||
In flatpak, it not allow to override file, that is a good imagine, but how to bind a file not exist in the base, the flatpak can not deal with that now.
|
||||
|
||||
For docker or other container tools, an overlayfs (or other filesystem with same function) is need.
|
||||
|
||||
For linglong, we do not need a powerful overlayfs to action complex function, but just fix some issue that case by some not standard apps. so we use an mini fuse proxy to fake mount point or path not exist.
|
||||
|
||||
So apps should keep the rules first. And just keep compatibility with some not open source apps by fuse proxy filesystem.
|
||||
|
||||
## The access control
|
||||
|
||||
The access control is not an mandatory standard. OCI runtime spec do not care it, especially an dynamic access control. We use fuse proxy filesystem to finish this.
|
||||
|
||||
When app in container access an path not exist, the fuse proxy can get it. It the path is define as an permission control path, it will as user to confirm. and notify ll-box freeze all process in sandbox.
|
||||
|
||||
## How to use fuse-proxy?
|
||||
|
||||
fuse-proxy is a mount backend for ll-box. the ll-box call it before chroot in the new mount namespace.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
# SPDX-FileCopyrightText: None
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
DisableFormat: true
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
# SPDX-FileCopyrightText: None
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
with section("format"):
|
||||
disable = True
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
add_library(CLI11 INTERFACE)
|
||||
add_library(CLI11::CLI11 ALIAS CLI11)
|
||||
target_include_directories(CLI11 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include/")
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,5 @@
|
|||
# https://github.com/nlohmann/json/tree/v3.11.3?tab=readme-ov-file#integration
|
||||
|
||||
add_library(nlohmann_json INTERFACE)
|
||||
add_library(nlohmann_json::nlohmann_json ALIAS nlohmann_json)
|
||||
target_include_directories(nlohmann_json INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include/")
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,187 @@
|
|||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||
#define INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||
|
||||
#include <cstdint> // int64_t, uint64_t
|
||||
#include <map> // map
|
||||
#include <memory> // allocator
|
||||
#include <string> // string
|
||||
#include <vector> // vector
|
||||
|
||||
// #include <nlohmann/detail/abi_macros.hpp>
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
|
||||
// This file contains all macro definitions affecting or depending on the ABI
|
||||
|
||||
#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
|
||||
#if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)
|
||||
#if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 12 || NLOHMANN_JSON_VERSION_PATCH != 0
|
||||
#warning "Already included a different version of the library!"
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum)
|
||||
#define NLOHMANN_JSON_VERSION_MINOR 12 // NOLINT(modernize-macro-to-enum)
|
||||
#define NLOHMANN_JSON_VERSION_PATCH 0 // NOLINT(modernize-macro-to-enum)
|
||||
|
||||
#ifndef JSON_DIAGNOSTICS
|
||||
#define JSON_DIAGNOSTICS 0
|
||||
#endif
|
||||
|
||||
#ifndef JSON_DIAGNOSTIC_POSITIONS
|
||||
#define JSON_DIAGNOSTIC_POSITIONS 0
|
||||
#endif
|
||||
|
||||
#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
|
||||
#endif
|
||||
|
||||
#if JSON_DIAGNOSTICS
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS
|
||||
#endif
|
||||
|
||||
#if JSON_DIAGNOSTIC_POSITIONS
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS _dp
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS
|
||||
#endif
|
||||
|
||||
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp
|
||||
#else
|
||||
#define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#endif
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
|
||||
#define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
|
||||
#endif
|
||||
|
||||
// Construct the namespace ABI tags component
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) json_abi ## a ## b ## c
|
||||
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c) \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c)
|
||||
|
||||
#define NLOHMANN_JSON_ABI_TAGS \
|
||||
NLOHMANN_JSON_ABI_TAGS_CONCAT( \
|
||||
NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
|
||||
NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON, \
|
||||
NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS)
|
||||
|
||||
// Construct the namespace version component
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
|
||||
_v ## major ## _ ## minor ## _ ## patch
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch)
|
||||
|
||||
#if NLOHMANN_JSON_NAMESPACE_NO_VERSION
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION
|
||||
#else
|
||||
#define NLOHMANN_JSON_NAMESPACE_VERSION \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \
|
||||
NLOHMANN_JSON_VERSION_MINOR, \
|
||||
NLOHMANN_JSON_VERSION_PATCH)
|
||||
#endif
|
||||
|
||||
// Combine namespace components
|
||||
#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b
|
||||
#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \
|
||||
NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b)
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE
|
||||
#define NLOHMANN_JSON_NAMESPACE \
|
||||
nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \
|
||||
NLOHMANN_JSON_ABI_TAGS, \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION)
|
||||
#endif
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
#define NLOHMANN_JSON_NAMESPACE_BEGIN \
|
||||
namespace nlohmann \
|
||||
{ \
|
||||
inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \
|
||||
NLOHMANN_JSON_ABI_TAGS, \
|
||||
NLOHMANN_JSON_NAMESPACE_VERSION) \
|
||||
{
|
||||
#endif
|
||||
|
||||
#ifndef NLOHMANN_JSON_NAMESPACE_END
|
||||
#define NLOHMANN_JSON_NAMESPACE_END \
|
||||
} /* namespace (inline namespace) NOLINT(readability/namespace) */ \
|
||||
} // namespace nlohmann
|
||||
#endif
|
||||
|
||||
|
||||
/*!
|
||||
@brief namespace for Niels Lohmann
|
||||
@see https://github.com/nlohmann
|
||||
@since version 1.0.0
|
||||
*/
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
|
||||
/*!
|
||||
@brief default JSONSerializer template argument
|
||||
|
||||
This serializer ignores the template arguments and uses ADL
|
||||
([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))
|
||||
for serialization.
|
||||
*/
|
||||
template<typename T = void, typename SFINAE = void>
|
||||
struct adl_serializer;
|
||||
|
||||
/// a class to store JSON values
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/
|
||||
template<template<typename U, typename V, typename... Args> class ObjectType =
|
||||
std::map,
|
||||
template<typename U, typename... Args> class ArrayType = std::vector,
|
||||
class StringType = std::string, class BooleanType = bool,
|
||||
class NumberIntegerType = std::int64_t,
|
||||
class NumberUnsignedType = std::uint64_t,
|
||||
class NumberFloatType = double,
|
||||
template<typename U> class AllocatorType = std::allocator,
|
||||
template<typename T, typename SFINAE = void> class JSONSerializer =
|
||||
adl_serializer,
|
||||
class BinaryType = std::vector<std::uint8_t>, // cppcheck-suppress syntaxError
|
||||
class CustomBaseClass = void>
|
||||
class basic_json;
|
||||
|
||||
/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document
|
||||
/// @sa https://json.nlohmann.me/api/json_pointer/
|
||||
template<typename RefStringType>
|
||||
class json_pointer;
|
||||
|
||||
/*!
|
||||
@brief default specialization
|
||||
@sa https://json.nlohmann.me/api/json/
|
||||
*/
|
||||
using json = basic_json<>;
|
||||
|
||||
/// @brief a minimal map-like container that preserves insertion order
|
||||
/// @sa https://json.nlohmann.me/api/ordered_map/
|
||||
template<class Key, class T, class IgnoredLess, class Allocator>
|
||||
struct ordered_map;
|
||||
|
||||
/// @brief specialization that maintains the insertion order of object keys
|
||||
/// @sa https://json.nlohmann.me/api/ordered_json/
|
||||
using ordered_json = basic_json<nlohmann::ordered_map>;
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
pkg_check_modules(SECCOMP REQUIRED libseccomp)
|
||||
|
||||
set(LINK_LIBS
|
||||
seccomp
|
||||
stdc++)
|
||||
|
||||
set(LL_BOX_SOURCES
|
||||
# cmake-format: sortable
|
||||
main.cpp
|
||||
loader.cpp
|
||||
util/common.cpp
|
||||
util/filesystem.cpp
|
||||
util/semaphore.cpp
|
||||
util/debug/debug.cpp
|
||||
util/platform.cpp
|
||||
util/logger.cpp
|
||||
util/message_reader.cpp
|
||||
container/container.cpp
|
||||
container/mount/host_mount.cpp
|
||||
container/mount/filesystem_driver.cpp
|
||||
container/seccomp.cpp
|
||||
)
|
||||
add_executable(ll-box ${LL_BOX_SOURCES})
|
||||
target_link_libraries(ll-box ${LINK_LIBS})
|
||||
|
||||
if (BUILD_STATIC)
|
||||
add_executable(ll-box-static ${LL_BOX_SOURCES})
|
||||
target_link_libraries(ll-box-static -static ${LINK_LIBS})
|
||||
install(TARGETS ll-box-static RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/libexec)
|
||||
endif (BUILD_STATIC)
|
||||
|
||||
install(TARGETS ll-box RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
#install(TARGETS ll-box RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
# PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE SETUID)
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
# ll-box
|
||||
|
||||
ll-box is a standard oci runtime.
|
||||
|
||||
## Feature
|
||||
|
||||
- [x] No root daemon, use setuid
|
||||
- [x] Standard oci runtime
|
||||
|
||||
## Roadmap
|
||||
|
||||
### Current
|
||||
|
||||
- [ ] Configuration
|
||||
- [x] Root
|
||||
- [ ] Mount
|
||||
- [x] Cgroup
|
||||
- [ ] All support
|
||||
- [x] Hostname
|
||||
- [ ] Linux Container
|
||||
- [x] Default Filesystems
|
||||
- [x] Namespaces
|
||||
- [x] Network
|
||||
- [x] User namespace mappings
|
||||
- [ ] Devices
|
||||
- [ ] Default Devices
|
||||
- [ ] Control groups v2
|
||||
- [ ] cpu
|
||||
- [ ] memory
|
||||
- [ ] pids
|
||||
- [ ] devices
|
||||
- [ ] io
|
||||
- [ ] cpuset
|
||||
- [ ] rdma
|
||||
- [ ] perf_event
|
||||
- [ ] IntelRdt
|
||||
- [ ] Sysctl
|
||||
- [x] Seccomp
|
||||
- [ ] full support of all syscall
|
||||
- [ ] full support of arch
|
||||
- [ ] Rootfs Mount Propagation
|
||||
- [ ] Masked Paths
|
||||
- [ ] Readonly Paths
|
||||
- [ ] Mount Label
|
||||
|
||||
### Next
|
||||
|
||||
- [ ] TODO
|
||||
|
||||
## Dependencies
|
||||
|
||||
- [ ] C++11/STL
|
||||
- [ ] nlonmann-json3
|
||||
- [ ] gtest
|
||||
|
||||
```bash
|
||||
#For release based on debian
|
||||
sudo apt-get cmake build-essential \
|
||||
nlonmann-json3-dev \
|
||||
libgtest-dev
|
||||
```
|
||||
|
||||
## Getting help
|
||||
|
||||
Any usage issues can ask for help via
|
||||
|
||||
- [Gitter](https://gitter.im/orgs/linuxdeepin/rooms)
|
||||
- [IRC channel](https://webchat.freenode.net/?channels=deepin)
|
||||
- [Forum](https://bbs.deepin.org)
|
||||
- [WiKi](https://wiki.deepin.org/)
|
||||
|
||||
## Getting involved
|
||||
|
||||
We encourage you to report issues and contribute changes
|
||||
|
||||
- [Contribution guide for developers](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers-en)
|
||||
. (English)
|
||||
- [开发者代码贡献指南](https://github.com/linuxdeepin/developer-center/wiki/Contribution-Guidelines-for-Developers) (中文)
|
||||
|
||||
## License
|
||||
|
||||
Deepin Boot Maker is licensed under GPLv3.
|
||||
|
||||
## Credits and references
|
||||
|
||||
- [OStree](https://github.com/ostreedev/ostree)
|
||||
|
|
@ -1,845 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "container.h"
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <fcntl.h>
|
||||
#include <grp.h>
|
||||
#include <sched.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
#include "util/logger.h"
|
||||
#include "util/filesystem.h"
|
||||
#include "util/semaphore.h"
|
||||
#include "util/debug/debug.h"
|
||||
#include "util/platform.h"
|
||||
|
||||
#include "container/seccomp.h"
|
||||
#include "container/container_option.h"
|
||||
#include "container/mount/host_mount.h"
|
||||
#include "container/mount/filesystem_driver.h"
|
||||
|
||||
namespace linglong {
|
||||
|
||||
static const std::string llDbusProxyBin = "/usr/bin/ll-dbus-proxy";
|
||||
// start dbus proxy
|
||||
static int StartDbusProxy(const Runtime &runtime)
|
||||
{
|
||||
if (!(runtime.annotations.has_value() && runtime.annotations->dbus_proxy_info.has_value()
|
||||
&& runtime.annotations->dbus_proxy_info->enable)) {
|
||||
logInf() << "dbus proxy disabled";
|
||||
return -1;
|
||||
}
|
||||
|
||||
const auto &info = runtime.annotations->dbus_proxy_info;
|
||||
|
||||
std::string socket_path = info->proxy_path;
|
||||
|
||||
pid_t proxy_pid = fork();
|
||||
if (proxy_pid < 0) {
|
||||
logErr() << "fork to start dbus proxy failed:", util::errnoString();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0 == proxy_pid) {
|
||||
// FIXME: parent may dead before this return.
|
||||
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
||||
std::string bus_type = info->bus_type;
|
||||
std::string app_id = info->app_id;
|
||||
std::vector<std::string> name_fliter = info->name;
|
||||
std::vector<std::string> path_fliter = info->path;
|
||||
std::vector<std::string> interface_fliter = info->interface;
|
||||
std::string name_fliter_string = linglong::util::str_vec_join(name_fliter, ',');
|
||||
std::string path_fliter_string = linglong::util::str_vec_join(path_fliter, ',');
|
||||
std::string interface_fliter_string = linglong::util::str_vec_join(interface_fliter, ',');
|
||||
char const *const args[] = {llDbusProxyBin.c_str(),
|
||||
app_id.c_str(),
|
||||
bus_type.c_str(),
|
||||
socket_path.c_str(),
|
||||
name_fliter_string.c_str(),
|
||||
path_fliter_string.c_str(),
|
||||
interface_fliter_string.c_str(),
|
||||
NULL};
|
||||
int ret = execvp(args[0], (char **)args);
|
||||
logErr() << "start dbus proxy failed, ret=" << ret;
|
||||
exit(ret);
|
||||
} else {
|
||||
// FIXME: this call make 10ms lag at least
|
||||
if (util::fs::path(socket_path).wait_until_exsit() != 0) {
|
||||
logErr() << util::format("timeout! socketPath [\"%s\"] not exsit", socket_path.c_str());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DropToNormalUser(int uid, int gid)
|
||||
{
|
||||
setuid(uid);
|
||||
seteuid(uid);
|
||||
setgid(gid);
|
||||
setegid(gid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ConfigUserNamespace(const linglong::Linux &linux, int initPid)
|
||||
{
|
||||
std::string pid = "self";
|
||||
if (initPid > 0) {
|
||||
pid = util::format("%d", initPid);
|
||||
}
|
||||
|
||||
logDbg() << "old uid:" << getuid() << "gid:" << getgid();
|
||||
logDbg() << "start write uid_map and pid_map" << initPid;
|
||||
|
||||
// write uid map
|
||||
std::ofstream uidMapFile(util::format("/proc/%s/uid_map", pid.c_str()));
|
||||
for (auto const &idMap : linux.uidMappings) {
|
||||
uidMapFile << util::format("%lu %lu %lu\n", idMap.containerID, idMap.hostID, idMap.size);
|
||||
}
|
||||
uidMapFile.close();
|
||||
|
||||
// write gid map
|
||||
auto setgroupsPath = util::format("/proc/%s/setgroups", pid.c_str());
|
||||
std::ofstream setgroupsFile(setgroupsPath);
|
||||
setgroupsFile << "deny";
|
||||
setgroupsFile.close();
|
||||
|
||||
std::ofstream gidMapFile(util::format("/proc/%s/gid_map", pid.c_str()));
|
||||
for (auto const &idMap : linux.gidMappings) {
|
||||
gidMapFile << util::format("%lu %lu %lu\n", idMap.containerID, idMap.hostID, idMap.size);
|
||||
}
|
||||
gidMapFile.close();
|
||||
|
||||
logDbg() << "new uid:" << getuid() << "gid:" << getgid();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// FIXME(iceyer): not work now
|
||||
static int ConfigCgroupV2(const std::string &cgroupsPath, const linglong::Resources &res, int initPid)
|
||||
{
|
||||
if (cgroupsPath.empty()) {
|
||||
logWan() << "skip with empty cgroupsPath";
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto writeConfig = [](const std::map<std::string, std::string> &cfgs) {
|
||||
for (auto const &cfg : cfgs) {
|
||||
logWan() << "ConfigCgroupV2" << cfg.first << cfg.second;
|
||||
std::ofstream cfgFile(cfg.first);
|
||||
cfgFile << cfg.second << std::endl;
|
||||
cfgFile.close();
|
||||
}
|
||||
};
|
||||
|
||||
auto cgroupsRoot = util::fs::path(cgroupsPath);
|
||||
util::fs::create_directories(cgroupsRoot, 0755);
|
||||
|
||||
int ret = mount("cgroup2", cgroupsRoot.string().c_str(), "cgroup2", 0u, nullptr);
|
||||
if (ret != 0) {
|
||||
logErr() << "mount cgroup failed" << util::RetErrString(ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO: should sub path with pid?
|
||||
auto subCgroupRoot = cgroupsRoot / "ll-box";
|
||||
if (!util::fs::create_directories(util::fs::path(subCgroupRoot), 0755)) {
|
||||
logErr() << "create_directories subCgroupRoot failed" << util::errnoString();
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto subCgroupPath = [subCgroupRoot](const std::string &compents) -> std::string {
|
||||
return (subCgroupRoot / compents).string();
|
||||
};
|
||||
|
||||
// config memory
|
||||
const auto memMax = res.memory.limit;
|
||||
|
||||
if (memMax > 0) {
|
||||
const auto memSwapMax = res.memory.swap - memMax;
|
||||
const auto memLow = res.memory.reservation;
|
||||
writeConfig({
|
||||
{subCgroupPath("memory.max"), util::format("%d", memMax)},
|
||||
{subCgroupPath("memory.swap.max"), util::format("%d", memSwapMax)},
|
||||
{subCgroupPath("memory.low"), util::format("%d", memLow)},
|
||||
});
|
||||
}
|
||||
|
||||
// config cpu
|
||||
const auto cpuPeriod = res.cpu.period;
|
||||
const auto cpuMax = res.cpu.quota;
|
||||
// convert from [2-262144] to [1-10000], 262144 is 2^18
|
||||
const auto cpuWeight = (1 + ((res.cpu.shares - 2) * 9999) / 262142);
|
||||
|
||||
writeConfig({
|
||||
{subCgroupPath("cpu.max"), util::format("%d %d", cpuMax, cpuPeriod)},
|
||||
{subCgroupPath("cpu.weight"), util::format("%d", cpuWeight)},
|
||||
});
|
||||
|
||||
// config pid
|
||||
writeConfig({
|
||||
{subCgroupPath("cgroup.procs"), util::format("%d", initPid)},
|
||||
});
|
||||
|
||||
logDbg() << "move" << initPid << "to new cgroups";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void epoll_ctl_add(int epfd, int fd)
|
||||
{
|
||||
static epoll_event ev = {};
|
||||
ev.events = EPOLLIN;
|
||||
ev.data.fd = fd;
|
||||
int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
|
||||
if (ret != 0)
|
||||
logWan() << util::errnoString();
|
||||
}
|
||||
|
||||
// if wstatus says child exit normally, return true else false
|
||||
static bool parse_wstatus(const int &wstatus, std::string &info)
|
||||
{
|
||||
if (WIFEXITED(wstatus)) {
|
||||
auto code = WEXITSTATUS(wstatus);
|
||||
info = util::format("exited with code %d", code);
|
||||
return code == 0;
|
||||
} else if (WIFSIGNALED(wstatus)) {
|
||||
info = util::format("terminated by signal %d", WTERMSIG(wstatus));
|
||||
return false;
|
||||
} else {
|
||||
info = util::format("is dead with wstatus=%d", wstatus);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
struct ContainerPrivate {
|
||||
public:
|
||||
ContainerPrivate(Runtime r, std::unique_ptr<util::MessageReader> reader, Container * /*parent*/)
|
||||
: hostRoot(r.root.path)
|
||||
, runtime(std::move(r))
|
||||
, nativeMounter(new HostMount)
|
||||
, overlayfsMounter(new HostMount)
|
||||
, fuseproxyMounter(new HostMount)
|
||||
, reader(std::move(reader))
|
||||
{
|
||||
}
|
||||
|
||||
std::string hostRoot;
|
||||
|
||||
Runtime runtime;
|
||||
|
||||
// bool use_delay_new_user_ns = false;
|
||||
bool useNewCgroupNs = false;
|
||||
|
||||
Option option;
|
||||
|
||||
uid_t hostUid = -1;
|
||||
gid_t hostGid = -1;
|
||||
|
||||
std::unique_ptr<HostMount> nativeMounter;
|
||||
std::unique_ptr<HostMount> overlayfsMounter;
|
||||
std::unique_ptr<HostMount> fuseproxyMounter;
|
||||
|
||||
HostMount *containerMounter = nullptr;
|
||||
|
||||
std::unique_ptr<util::MessageReader> reader;
|
||||
|
||||
std::map<int, std::string> pidMap;
|
||||
|
||||
public:
|
||||
static int DropPermissions()
|
||||
{
|
||||
__gid_t newgid[1] = {getgid()};
|
||||
auto newuid = getuid();
|
||||
auto olduid = geteuid();
|
||||
|
||||
if (0 == olduid) {
|
||||
setgroups(1, newgid);
|
||||
}
|
||||
seteuid(newuid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PrepareLinks() const
|
||||
{
|
||||
chdir("/");
|
||||
|
||||
if (option.linkLfs) {
|
||||
symlink("/usr/bin", "/bin");
|
||||
symlink("/usr/lib", "/lib");
|
||||
symlink("/usr/lib32", "/lib32");
|
||||
symlink("/usr/lib64", "/lib64");
|
||||
symlink("/usr/libx32", "/libx32");
|
||||
}
|
||||
|
||||
// default link
|
||||
symlink("/proc/kcore", "/dev/core");
|
||||
symlink("/proc/self/fd", "/dev/fd");
|
||||
symlink("/proc/self/fd/2", "/dev/stderr");
|
||||
symlink("/proc/self/fd/0", "/dev/stdin");
|
||||
symlink("/proc/self/fd/1", "/dev/stdout");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PrepareDefaultDevices() const
|
||||
{
|
||||
struct Device {
|
||||
std::string path;
|
||||
mode_t mode;
|
||||
dev_t dev;
|
||||
};
|
||||
|
||||
std::vector<Device> list = {
|
||||
{"/dev/null", S_IFCHR | 0666, makedev(1, 3)}, {"/dev/zero", S_IFCHR | 0666, makedev(1, 5)},
|
||||
{"/dev/full", S_IFCHR | 0666, makedev(1, 7)}, {"/dev/random", S_IFCHR | 0666, makedev(1, 8)},
|
||||
{"/dev/urandom", S_IFCHR | 0666, makedev(1, 9)}, {"/dev/tty", S_IFCHR | 0666, makedev(5, 0)},
|
||||
};
|
||||
|
||||
// TODO(iceyer): not work now
|
||||
if (!option.rootless) {
|
||||
for (auto const &dev : list) {
|
||||
auto path = hostRoot + dev.path;
|
||||
int ret = mknod(path.c_str(), dev.mode, dev.dev);
|
||||
if (0 != ret) {
|
||||
logErr() << "mknod" << path << dev.mode << dev.dev << "failed with" << util::RetErrString(ret);
|
||||
}
|
||||
chmod(path.c_str(), dev.mode | 0xFFFF);
|
||||
chown(path.c_str(), 0, 0);
|
||||
}
|
||||
} else {
|
||||
for (auto const &dev : list) {
|
||||
Mount mount;
|
||||
mount.destination = dev.path;
|
||||
mount.type = "bind";
|
||||
mount.data = std::vector<std::string> {};
|
||||
mount.flags = MS_BIND;
|
||||
mount.fsType = Mount::Bind;
|
||||
mount.source = dev.path;
|
||||
|
||||
this->containerMounter->MountNode(mount);
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(iceyer): /dev/console is set up if terminal is enabled in the config by bind mounting the
|
||||
// pseudoterminal slave to /dev/console.
|
||||
symlink("/dev/pts/ptmx", (this->hostRoot + "/dev/ptmx").c_str());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void waitChildAndExec()
|
||||
{
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGCHLD);
|
||||
sigaddset(&mask, SIGTERM);
|
||||
// FIXME: add more signals.
|
||||
|
||||
/* Block signals so that they aren't handled
|
||||
according to their default dispositions. */
|
||||
|
||||
if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
|
||||
logWan() << "sigprocmask block";
|
||||
|
||||
int sfd = signalfd(-1, &mask, 0);
|
||||
if (sfd == -1)
|
||||
logWan() << "signalfd";
|
||||
|
||||
auto epfd = epoll_create(1);
|
||||
epoll_ctl_add(epfd, sfd);
|
||||
if (reader.get() != nullptr)
|
||||
epoll_ctl_add(epfd, reader->fd);
|
||||
|
||||
for (;;) {
|
||||
struct epoll_event events[10];
|
||||
int event_cnt = epoll_wait(epfd, events, 5, -1);
|
||||
for (int i = 0; i < event_cnt; i++) {
|
||||
const auto &event = events[i];
|
||||
if (event.data.fd == sfd) {
|
||||
struct signalfd_siginfo fdsi;
|
||||
ssize_t s = read(sfd, &fdsi, sizeof(fdsi));
|
||||
if (s != sizeof(fdsi)) {
|
||||
logWan() << "error read from signal fd";
|
||||
}
|
||||
if (fdsi.ssi_signo == SIGCHLD) {
|
||||
logWan() << "recive SIGCHLD";
|
||||
|
||||
int wstatus;
|
||||
while (int child = waitpid(-1, &wstatus, WNOHANG)) {
|
||||
if (child > 0) {
|
||||
std::string info;
|
||||
auto normal = parse_wstatus(wstatus, info);
|
||||
info = util::format("child [%d] [%s].", child, info.c_str());
|
||||
if (normal) {
|
||||
logDbg() << info;
|
||||
} else {
|
||||
logWan() << info;
|
||||
}
|
||||
auto it = pidMap.find(child);
|
||||
if (it != pidMap.end()) {
|
||||
if (reader.get() != nullptr)
|
||||
reader->writeChildExit(child, it->second, wstatus, info);
|
||||
pidMap.erase(it);
|
||||
}
|
||||
} else if (child < 0) {
|
||||
if (errno == ECHILD) {
|
||||
logDbg() << util::format("no child to wait");
|
||||
return;
|
||||
} else {
|
||||
auto str = util::errnoString();
|
||||
logErr() << util::format("waitpid failed, %s", str.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (fdsi.ssi_signo == SIGTERM) {
|
||||
// FIXME: box should exit with failed return code.
|
||||
logWan() << util::format("Terminated\n");
|
||||
return;
|
||||
} else {
|
||||
logWan() << util::format("Read unexpected signal [%d]\n", fdsi.ssi_signo);
|
||||
}
|
||||
} else if (reader.get() != nullptr && event.data.fd == reader->fd) {
|
||||
auto json = reader->read();
|
||||
if (json.empty()) {
|
||||
break;
|
||||
}
|
||||
auto process = json.get<Process>();
|
||||
forkAndExecProcess(process, true);
|
||||
} else {
|
||||
logWan() << "Unknown fd";
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
bool forkAndExecProcess(const Process process, bool unblock = false)
|
||||
{
|
||||
// FIXME: parent may dead before this return.
|
||||
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
||||
|
||||
int pid = fork();
|
||||
if (pid < 0) {
|
||||
logErr() << "fork failed" << util::RetErrString(pid);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 == pid) {
|
||||
if (unblock) {
|
||||
// FIXME: As we use signalfd, we have to block signal, but child created by fork
|
||||
// will inherit blocked signal set, so we have to unblock it. This is just a
|
||||
// workround.
|
||||
sigset_t mask;
|
||||
sigfillset(&mask);
|
||||
if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1)
|
||||
logWan() << "sigprocmask unblock";
|
||||
}
|
||||
logDbg() << "process.args:" << process.args;
|
||||
|
||||
int ret;
|
||||
ret = chdir(process.cwd.c_str());
|
||||
if (ret) {
|
||||
logErr() << "failed to chdir to" << process.cwd.c_str();
|
||||
}
|
||||
|
||||
// for PATH
|
||||
for (const auto &env : process.env) {
|
||||
auto kv = util::str_spilt(env, "=");
|
||||
if (kv.size() == 2)
|
||||
setenv(kv.at(0).c_str(), kv.at(1).c_str(), 1);
|
||||
else if (kv.size() == 1) {
|
||||
setenv(kv.at(0).c_str(), "", 1);
|
||||
} else {
|
||||
logWan() << "Unknown env:" << env;
|
||||
}
|
||||
}
|
||||
|
||||
logInf() << "start exec process";
|
||||
ret = util::Exec(process.args, process.env);
|
||||
if (0 != ret) {
|
||||
logErr() << "exec failed" << util::RetErrString(ret);
|
||||
}
|
||||
exit(ret);
|
||||
} else {
|
||||
pidMap.insert(make_pair(pid, process.args[0]));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int PivotRoot() const
|
||||
{
|
||||
int ret = -1;
|
||||
chdir(hostRoot.c_str());
|
||||
|
||||
if (option.rootless && runtime.annotations->overlayfs.has_value()) {
|
||||
int flag = MS_MOVE;
|
||||
ret = mount(".", "/", nullptr, flag, nullptr);
|
||||
if (0 != ret) {
|
||||
logErr() << "mount / failed" << util::RetErrString(ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = chroot(".");
|
||||
if (0 != ret) {
|
||||
logErr() << "chroot . failed" << util::RetErrString(ret);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
int flag = MS_BIND | MS_REC;
|
||||
ret = mount(".", ".", "bind", flag, nullptr);
|
||||
if (0 != ret) {
|
||||
logErr() << "mount / failed" << util::RetErrString(ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto llHostFilename = "ll-host";
|
||||
|
||||
auto llHostPath = hostRoot + "/" + llHostFilename;
|
||||
|
||||
mkdir(llHostPath.c_str(), 0755);
|
||||
|
||||
ret = syscall(SYS_pivot_root, hostRoot.c_str(), llHostPath.c_str());
|
||||
if (0 != ret) {
|
||||
logErr() << "SYS_pivot_root failed" << hostRoot << util::errnoString() << errno << ret;
|
||||
return -1;
|
||||
}
|
||||
|
||||
chdir("/");
|
||||
ret = chroot(".");
|
||||
if (0 != ret) {
|
||||
logErr() << "chroot failed" << hostRoot << util::errnoString() << errno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
chdir("/");
|
||||
umount2(llHostFilename, MNT_DETACH);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PrepareRootfs()
|
||||
{
|
||||
auto PrepareOverlayfsRootfs = [&](const AnnotationsOverlayfs &overlayfs) -> int {
|
||||
nativeMounter->Setup(new NativeFilesystemDriver(overlayfs.lower_parent));
|
||||
|
||||
util::str_vec lowerDirs = {};
|
||||
int prefixIndex = 0;
|
||||
for (auto mount : overlayfs.mounts) {
|
||||
auto prefix = util::fs::path(util::format("/%d", prefixIndex));
|
||||
mount.destination = (prefix / mount.destination).string();
|
||||
if (0 == nativeMounter->MountNode(mount)) {
|
||||
lowerDirs.push_back((util::fs::path(overlayfs.lower_parent) / prefix).string());
|
||||
}
|
||||
++prefixIndex;
|
||||
}
|
||||
|
||||
overlayfsMounter->Setup(
|
||||
new OverlayfsFuseFilesystemDriver(lowerDirs, overlayfs.upper, overlayfs.workdir, hostRoot));
|
||||
|
||||
containerMounter = overlayfsMounter.get();
|
||||
return -1;
|
||||
};
|
||||
|
||||
auto PrepareFuseProxyRootfs = [&](const AnnotationsOverlayfs &overlayfs) -> int {
|
||||
nativeMounter->Setup(new NativeFilesystemDriver(overlayfs.lower_parent));
|
||||
|
||||
util::str_vec mounts = {};
|
||||
for (auto const &mount : overlayfs.mounts) {
|
||||
auto mountItem = util::format("%s:%s\n", mount.source.c_str(), mount.destination.c_str());
|
||||
mounts.push_back(mountItem);
|
||||
}
|
||||
|
||||
fuseproxyMounter->Setup(new FuseProxyFilesystemDriver(mounts, hostRoot));
|
||||
|
||||
containerMounter = fuseproxyMounter.get();
|
||||
return -1;
|
||||
};
|
||||
|
||||
auto PrepareNativeRootfs = [&](const AnnotationsNativeRootfs &native) -> int {
|
||||
nativeMounter->Setup(new NativeFilesystemDriver(runtime.root.path));
|
||||
|
||||
for (const auto &mount : native.mounts) {
|
||||
nativeMounter->MountNode(mount);
|
||||
}
|
||||
|
||||
containerMounter = nativeMounter.get();
|
||||
return -1;
|
||||
};
|
||||
|
||||
if (runtime.annotations.has_value() && runtime.annotations->overlayfs.has_value()) {
|
||||
auto env = getenv("LL_BOX_FS_BACKEND");
|
||||
if (env && std::string(env) == "fuse-proxy") {
|
||||
return PrepareFuseProxyRootfs(runtime.annotations->overlayfs.value());
|
||||
} else {
|
||||
return PrepareOverlayfsRootfs(runtime.annotations->overlayfs.value());
|
||||
}
|
||||
} else {
|
||||
return PrepareNativeRootfs(runtime.annotations->native.has_value() ? runtime.annotations->native.value()
|
||||
: AnnotationsNativeRootfs());
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int MountContainerPath()
|
||||
{
|
||||
if (runtime.mounts.has_value()) {
|
||||
for (auto const &mount : runtime.mounts.value()) {
|
||||
containerMounter->MountNode(mount);
|
||||
}
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
int HookExec(const Hook &hook)
|
||||
{
|
||||
int execPid = fork();
|
||||
if (execPid < 0) {
|
||||
logErr() << "fork failed" << util::RetErrString(execPid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (execPid == 0) {
|
||||
util::str_vec argStrVec;
|
||||
argStrVec.push_back(hook.path);
|
||||
|
||||
std::copy(hook.args->begin(), hook.args->end(), std::back_inserter(argStrVec));
|
||||
|
||||
util::Exec(argStrVec, hook.env.value());
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
return waitpid(execPid, nullptr, 0);
|
||||
}
|
||||
|
||||
int NonePrivilegeProc(void *arg)
|
||||
{
|
||||
auto &containerPrivate = *reinterpret_cast<ContainerPrivate *>(arg);
|
||||
|
||||
if (containerPrivate.option.rootless) {
|
||||
// TODO(iceyer): use option
|
||||
|
||||
Linux linux;
|
||||
IDMap idMap;
|
||||
|
||||
idMap.containerID = containerPrivate.hostUid;
|
||||
idMap.hostID = 0;
|
||||
idMap.size = 1;
|
||||
linux.uidMappings.push_back(idMap);
|
||||
|
||||
idMap.containerID = containerPrivate.hostGid;
|
||||
idMap.hostID = 0;
|
||||
idMap.size = 1;
|
||||
linux.gidMappings.push_back(idMap);
|
||||
|
||||
ConfigUserNamespace(linux, 0);
|
||||
}
|
||||
|
||||
auto ret = mount("proc", "/proc", "proc", 0, nullptr);
|
||||
if (0 != ret) {
|
||||
logErr() << "mount proc failed" << util::RetErrString(ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (containerPrivate.runtime.hooks.has_value() && containerPrivate.runtime.hooks->prestart.has_value()) {
|
||||
for (auto const &preStart : *containerPrivate.runtime.hooks->prestart) {
|
||||
HookExec(preStart);
|
||||
}
|
||||
}
|
||||
|
||||
if (!containerPrivate.option.rootless) {
|
||||
seteuid(0);
|
||||
// todo: check return value
|
||||
ConfigSeccomp(containerPrivate.runtime.linux.seccomp);
|
||||
ContainerPrivate::DropPermissions();
|
||||
}
|
||||
|
||||
containerPrivate.forkAndExecProcess(containerPrivate.runtime.process);
|
||||
|
||||
containerPrivate.waitChildAndExec();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sigtermHandler(int)
|
||||
{
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int EntryProc(void *arg)
|
||||
{
|
||||
auto &containerPrivate = *reinterpret_cast<ContainerPrivate *>(arg);
|
||||
|
||||
if (containerPrivate.option.rootless) {
|
||||
ConfigUserNamespace(containerPrivate.runtime.linux, 0);
|
||||
}
|
||||
|
||||
// FIXME: change HOSTNAME will broken XAUTH
|
||||
auto new_hostname = containerPrivate.runtime.hostname;
|
||||
// if (sethostname(new_hostname.c_str(), strlen(new_hostname.c_str())) == -1) {
|
||||
// logErr() << "sethostname failed" << util::errnoString();
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
uint32_t flags = MS_REC | MS_SLAVE;
|
||||
int ret = mount(nullptr, "/", nullptr, flags, nullptr);
|
||||
if (0 != ret) {
|
||||
logErr() << "mount / failed" << util::RetErrString(ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string container_root = containerPrivate.runtime.annotations->container_root_path;
|
||||
flags = MS_NODEV | MS_NOSUID;
|
||||
ret = mount("tmpfs", container_root.c_str(), "tmpfs", flags, nullptr);
|
||||
if (0 != ret) {
|
||||
logErr() << util::format("mount container root (%s) failed:", container_root.c_str())
|
||||
<< util::RetErrString(ret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// NOTE(iceyer): it's not standard oci action
|
||||
containerPrivate.PrepareRootfs();
|
||||
|
||||
containerPrivate.MountContainerPath();
|
||||
|
||||
if (containerPrivate.useNewCgroupNs) {
|
||||
ConfigCgroupV2(containerPrivate.runtime.linux.cgroupsPath, containerPrivate.runtime.linux.resources, getpid());
|
||||
}
|
||||
|
||||
containerPrivate.PrepareDefaultDevices();
|
||||
|
||||
containerPrivate.PivotRoot();
|
||||
|
||||
containerPrivate.PrepareLinks();
|
||||
|
||||
if (!containerPrivate.option.rootless) {
|
||||
auto unshareFlags = 0;
|
||||
// TODO(iceyer): no need user namespace in setuid
|
||||
// if (c.use_delay_new_user_ns) {
|
||||
// unshare_flags |= CLONE_NEWUSER;
|
||||
// }
|
||||
if (containerPrivate.useNewCgroupNs) {
|
||||
unshareFlags |= CLONE_NEWCGROUP;
|
||||
}
|
||||
if (unshareFlags) {
|
||||
ret = unshare(unshareFlags);
|
||||
if (0 != ret) {
|
||||
logErr() << "unshare failed" << unshareFlags << util::RetErrString(ret);
|
||||
}
|
||||
}
|
||||
// if (c.use_delay_new_user_ns) {
|
||||
// s.vrijgeven();
|
||||
// s.passeren();
|
||||
// }
|
||||
}
|
||||
|
||||
int nonePrivilegeProcFlag = SIGCHLD | CLONE_NEWUSER | CLONE_NEWPID | CLONE_NEWNS;
|
||||
|
||||
int noPrivilegePid = util::PlatformClone(NonePrivilegeProc, nonePrivilegeProcFlag, arg);
|
||||
if (noPrivilegePid < 0) {
|
||||
logErr() << "clone failed" << util::RetErrString(noPrivilegePid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ContainerPrivate::DropPermissions();
|
||||
|
||||
// FIXME: parent may dead before this return.
|
||||
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
||||
|
||||
// FIXME(interactive bash): if need keep interactive shell
|
||||
|
||||
containerPrivate.reader.reset();
|
||||
signal(SIGTERM, sigtermHandler);
|
||||
util::WaitAllUntil(noPrivilegePid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Container::Container(const Runtime &r, std::unique_ptr<util::MessageReader> reader)
|
||||
: dd_ptr(new ContainerPrivate(r, std::move(reader), this))
|
||||
{
|
||||
}
|
||||
|
||||
int Container::Start(const Option &option)
|
||||
{
|
||||
auto &contanerPrivate = *reinterpret_cast<ContainerPrivate *>(dd_ptr.get());
|
||||
contanerPrivate.option = option;
|
||||
|
||||
if (option.rootless) {
|
||||
contanerPrivate.hostUid = geteuid();
|
||||
contanerPrivate.hostGid = getegid();
|
||||
}
|
||||
|
||||
int flags = SIGCHLD | CLONE_NEWNS;
|
||||
|
||||
for (auto const &n : contanerPrivate.runtime.linux.namespaces) {
|
||||
switch (n.type) {
|
||||
case CLONE_NEWIPC:
|
||||
case CLONE_NEWUTS:
|
||||
case CLONE_NEWNS:
|
||||
case CLONE_NEWPID:
|
||||
case CLONE_NEWNET:
|
||||
flags |= n.type;
|
||||
break;
|
||||
case CLONE_NEWUSER:
|
||||
// dd_ptr->use_delay_new_user_ns = true;
|
||||
break;
|
||||
case CLONE_NEWCGROUP:
|
||||
contanerPrivate.useNewCgroupNs = true;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (option.rootless) {
|
||||
flags |= CLONE_NEWUSER;
|
||||
}
|
||||
|
||||
StartDbusProxy(contanerPrivate.runtime);
|
||||
|
||||
int entryPid = util::PlatformClone(EntryProc, flags, (void *)dd_ptr.get());
|
||||
if (entryPid < 0) {
|
||||
logErr() << "clone failed" << util::RetErrString(entryPid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
contanerPrivate.reader.reset();
|
||||
|
||||
// FIXME: maybe we need c.opt.child_need_wait?
|
||||
|
||||
ContainerPrivate::DropPermissions();
|
||||
|
||||
// FIXME: parent may dead before this return.
|
||||
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
||||
|
||||
// FIXME(interactive bash): if need keep interactive shell
|
||||
util::WaitAllUntil(entryPid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Container::~Container() = default;
|
||||
|
||||
} // namespace linglong
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef LINGLONG_BOX_SRC_CONTAINER_CONTAINER_H_
|
||||
#define LINGLONG_BOX_SRC_CONTAINER_CONTAINER_H_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "util/oci_runtime.h"
|
||||
#include "util/message_reader.h"
|
||||
|
||||
namespace linglong {
|
||||
|
||||
struct Option;
|
||||
struct ContainerPrivate;
|
||||
|
||||
class Container
|
||||
{
|
||||
public:
|
||||
explicit Container(const Runtime &r, std::unique_ptr<util::MessageReader> reader);
|
||||
|
||||
~Container();
|
||||
|
||||
int Start(const Option &opt);
|
||||
|
||||
private:
|
||||
std::unique_ptr<ContainerPrivate> dd_ptr;
|
||||
};
|
||||
|
||||
} // namespace linglong
|
||||
|
||||
#endif /* LINGLONG_BOX_SRC_CONTAINER_CONTAINER_H_ */
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "container_option.h"
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef LINGLONG_BOX_SRC_CONTAINER_CONTAINER_OPTION_H_
|
||||
#define LINGLONG_BOX_SRC_CONTAINER_CONTAINER_OPTION_H_
|
||||
|
||||
#include "util/json.h"
|
||||
|
||||
namespace linglong {
|
||||
|
||||
/*!
|
||||
* It's seem not a good idea to add extra config option.
|
||||
* The oci runtime json should contain option, but now it's hard to modify
|
||||
* the work flow.
|
||||
* If there is more information about how to deal user namespace, it can remove
|
||||
*/
|
||||
struct Option {
|
||||
bool rootless = false;
|
||||
bool linkLfs = true;
|
||||
};
|
||||
|
||||
} // namespace linglong
|
||||
|
||||
#endif /* LINGLONG_BOX_SRC_CONTAINER_CONTAINER_OPTION_H_ */
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "filesystem_driver.h"
|
||||
#include "util/platform.h"
|
||||
|
||||
namespace linglong {
|
||||
|
||||
FilesystemDriver::~FilesystemDriver() = default;
|
||||
|
||||
OverlayfsFuseFilesystemDriver::OverlayfsFuseFilesystemDriver(util::str_vec lower_dirs, std::string upper_dir,
|
||||
std::string work_dir, std::string mount_point)
|
||||
: lower_dirs_(std::move(lower_dirs))
|
||||
, upper_dir_(std::move(upper_dir))
|
||||
, work_dir_(std::move(work_dir))
|
||||
, mount_point_(std::move(mount_point))
|
||||
{
|
||||
}
|
||||
|
||||
util::fs::path OverlayfsFuseFilesystemDriver::HostPath(const util::fs::path &dest_full_path) const
|
||||
{
|
||||
return HostSource(util::fs::path(mount_point_) / dest_full_path);
|
||||
}
|
||||
|
||||
int OverlayfsFuseFilesystemDriver::CreateDestinationPath(const util::fs::path &container_destination_path)
|
||||
{
|
||||
__mode_t dest_mode = 0755;
|
||||
|
||||
auto host_destination_path = HostSource(util::fs::path(mount_point_) / container_destination_path);
|
||||
if (!util::fs::create_directories(host_destination_path, dest_mode)) {
|
||||
logErr() << "create_directories" << host_destination_path << util::errnoString();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OverlayfsFuseFilesystemDriver::Setup()
|
||||
{
|
||||
// fork and exec fuse
|
||||
int pid = fork();
|
||||
if (0 == pid) {
|
||||
util::fs::create_directories(util::fs::path(work_dir_), 0755);
|
||||
util::fs::create_directories(util::fs::path(upper_dir_), 0755);
|
||||
util::fs::create_directories(util::fs::path(mount_point_), 0755);
|
||||
// fuse-overlayfs -o lowerdir=/ -o upperdir=./upper -o workdir=./work overlaydir
|
||||
util::str_vec args;
|
||||
args.push_back("/usr/bin/fuse-overlayfs");
|
||||
args.push_back("-o");
|
||||
args.push_back("lowerdir=" + util::str_vec_join(lower_dirs_, ':'));
|
||||
args.push_back("-o");
|
||||
args.push_back("upperdir=" + upper_dir_);
|
||||
args.push_back("-o");
|
||||
args.push_back("workdir=" + work_dir_);
|
||||
args.push_back(mount_point_);
|
||||
|
||||
logErr() << util::Exec(args, {});
|
||||
logErr() << util::errnoString();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
util::Wait(pid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
util::fs::path OverlayfsFuseFilesystemDriver::HostSource(const util::fs::path &dest_full_path) const
|
||||
{
|
||||
return dest_full_path;
|
||||
}
|
||||
|
||||
util::fs::path NativeFilesystemDriver::HostPath(const util::fs::path &dest_full_path) const
|
||||
{
|
||||
return util::fs::path(root_path_) / dest_full_path;
|
||||
}
|
||||
|
||||
util::fs::path NativeFilesystemDriver::HostSource(const util::fs::path &dest_full_path) const
|
||||
{
|
||||
return dest_full_path;
|
||||
}
|
||||
|
||||
int NativeFilesystemDriver::CreateDestinationPath(const util::fs::path &container_destination_path)
|
||||
{
|
||||
__mode_t dest_mode = 0755;
|
||||
|
||||
auto host_destination_path = util::fs::path(root_path_) / container_destination_path;
|
||||
|
||||
util::fs::create_directories(host_destination_path, dest_mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
NativeFilesystemDriver::NativeFilesystemDriver(std::string root_path)
|
||||
: root_path_(std::move(root_path))
|
||||
{
|
||||
}
|
||||
|
||||
NativeFilesystemDriver::~NativeFilesystemDriver()
|
||||
{
|
||||
}
|
||||
|
||||
FuseProxyFilesystemDriver::FuseProxyFilesystemDriver(util::str_vec mounts, std::string mount_point)
|
||||
: mounts_(mounts)
|
||||
, mount_point_(mount_point)
|
||||
{
|
||||
}
|
||||
|
||||
util::fs::path FuseProxyFilesystemDriver::HostPath(const util::fs::path &dest_full_path) const
|
||||
{
|
||||
return HostSource(util::fs::path(mount_point_) / dest_full_path);
|
||||
}
|
||||
|
||||
util::fs::path FuseProxyFilesystemDriver::HostSource(const util::fs::path &dest_full_path) const
|
||||
{
|
||||
return dest_full_path;
|
||||
}
|
||||
|
||||
int FuseProxyFilesystemDriver::CreateDestinationPath(const util::fs::path &container_destination_path)
|
||||
{
|
||||
__mode_t dest_mode = 0755;
|
||||
|
||||
auto host_destination_path = HostSource(util::fs::path(mount_point_) / container_destination_path);
|
||||
if (!util::fs::create_directories(host_destination_path, dest_mode)) {
|
||||
logErr() << "create_directories" << host_destination_path << util::errnoString();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FuseProxyFilesystemDriver::Setup()
|
||||
{
|
||||
int pipe_ends[2];
|
||||
if (0 != pipe(pipe_ends)) {
|
||||
logErr() << "pipe failed:" << util::errnoString();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pid = fork();
|
||||
if (pid < 0) {
|
||||
logErr() << "fork failed:" << util::errnoString();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (0 == pid) {
|
||||
close(pipe_ends[1]);
|
||||
if (-1 == dup2(pipe_ends[0], 112)) {
|
||||
logErr() << "dup2 failed:" << util::errnoString();
|
||||
return -1;
|
||||
}
|
||||
close(pipe_ends[0]);
|
||||
|
||||
util::fs::create_directories(util::fs::path(mount_point_), 0755);
|
||||
util::fs::create_directories(util::fs::path(mount_point_ + "/.root"), 0755);
|
||||
|
||||
util::str_vec args;
|
||||
args.push_back("/usr/bin/ll-fuse-proxy");
|
||||
args.push_back("112");
|
||||
args.push_back(mount_point_);
|
||||
|
||||
logErr() << util::Exec(args, {});
|
||||
|
||||
exit(0);
|
||||
} else {
|
||||
close(pipe_ends[0]);
|
||||
std::string root_mount = mount_point_ + "/.root:/\n";
|
||||
write(pipe_ends[1], root_mount.c_str(), root_mount.size()); // FIXME: handle write error
|
||||
for (auto const &m : mounts_) {
|
||||
write(pipe_ends[1], m.c_str(), m.size());
|
||||
}
|
||||
close(pipe_ends[1]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace linglong
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef LINGLONG_BOX_SRC_CONTAINER_MOUNT_FILESYSTEM_DRIVER_H_
|
||||
#define LINGLONG_BOX_SRC_CONTAINER_MOUNT_FILESYSTEM_DRIVER_H_
|
||||
|
||||
#include "util/util.h"
|
||||
|
||||
namespace linglong {
|
||||
|
||||
class FilesystemDriver
|
||||
{
|
||||
public:
|
||||
virtual int Setup() = 0;
|
||||
virtual ~FilesystemDriver();
|
||||
virtual int CreateDestinationPath(const util::fs::path &container_destination_path) = 0;
|
||||
virtual util::fs::path HostPath(const util::fs::path &container_destination_path) const = 0;
|
||||
virtual util::fs::path HostSource(const util::fs::path &container_destination_path) const = 0;
|
||||
};
|
||||
|
||||
class OverlayfsFuseFilesystemDriver : public FilesystemDriver
|
||||
{
|
||||
public:
|
||||
explicit OverlayfsFuseFilesystemDriver(util::str_vec lower_dirs, std::string upper_dir, std::string work_dir,
|
||||
std::string mount_point);
|
||||
|
||||
int Setup() override;
|
||||
|
||||
int CreateDestinationPath(const util::fs::path &container_destination_path) override;
|
||||
|
||||
util::fs::path HostPath(const util::fs::path &dest_full_path) const override;
|
||||
|
||||
util::fs::path HostSource(const util::fs::path &dest_full_path) const override;
|
||||
|
||||
private:
|
||||
util::str_vec lower_dirs_;
|
||||
std::string upper_dir_;
|
||||
std::string work_dir_;
|
||||
std::string mount_point_;
|
||||
};
|
||||
|
||||
class FuseProxyFilesystemDriver : public FilesystemDriver
|
||||
{
|
||||
public:
|
||||
explicit FuseProxyFilesystemDriver(util::str_vec mounts, std::string mount_point);
|
||||
|
||||
int Setup() override;
|
||||
|
||||
int CreateDestinationPath(const util::fs::path &container_destination_path) override;
|
||||
|
||||
util::fs::path HostPath(const util::fs::path &dest_full_path) const override;
|
||||
|
||||
util::fs::path HostSource(const util::fs::path &dest_full_path) const override;
|
||||
|
||||
private:
|
||||
util::str_vec mounts_;
|
||||
std::string mount_point_;
|
||||
};
|
||||
|
||||
class NativeFilesystemDriver : public FilesystemDriver
|
||||
{
|
||||
public:
|
||||
explicit NativeFilesystemDriver(std::string root_path);
|
||||
~NativeFilesystemDriver();
|
||||
|
||||
int Setup() override { return 0; }
|
||||
|
||||
int CreateDestinationPath(const util::fs::path &container_destination_path) override;
|
||||
|
||||
util::fs::path HostPath(const util::fs::path &dest_full_path) const override;
|
||||
|
||||
util::fs::path HostSource(const util::fs::path &dest_full_path) const override;
|
||||
|
||||
private:
|
||||
std::string root_path_;
|
||||
};
|
||||
|
||||
} // namespace linglong
|
||||
|
||||
#endif /* LINGLONG_BOX_SRC_CONTAINER_MOUNT_FILESYSTEM_DRIVER_H_ */
|
||||
|
|
@ -1,209 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "host_mount.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "filesystem_driver.h"
|
||||
#include "util/debug/debug.h"
|
||||
|
||||
namespace linglong {
|
||||
|
||||
class HostMountPrivate
|
||||
{
|
||||
public:
|
||||
explicit HostMountPrivate() = default;
|
||||
|
||||
int CreateDestinationPath(const util::fs::path &container_destination_path) const
|
||||
{
|
||||
return driver_->CreateDestinationPath(container_destination_path);
|
||||
}
|
||||
|
||||
int MountNode(const struct Mount &m) const
|
||||
{
|
||||
int ret = -1;
|
||||
struct stat source_stat {
|
||||
};
|
||||
bool is_path = false;
|
||||
|
||||
auto source = m.source;
|
||||
|
||||
if (!m.source.empty() && m.source[0] == '/') {
|
||||
is_path = true;
|
||||
source = driver_->HostSource(util::fs::path(m.source)).string();
|
||||
}
|
||||
|
||||
ret = lstat(source.c_str(), &source_stat);
|
||||
if (0 == ret) {
|
||||
} else {
|
||||
// source not exist
|
||||
if (m.fsType == Mount::Bind) {
|
||||
logErr() << "lstat" << source << "failed";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
auto dest_full_path = util::fs::path(m.destination);
|
||||
auto dest_parent_path = util::fs::path(dest_full_path).parent_path();
|
||||
auto host_dest_full_path = driver_->HostPath(dest_full_path);
|
||||
auto root = driver_->HostPath(util::fs::path("/"));
|
||||
|
||||
logDbg() << "host_dest_full_path" << host_dest_full_path;
|
||||
|
||||
switch (source_stat.st_mode & S_IFMT) {
|
||||
case S_IFCHR: {
|
||||
driver_->CreateDestinationPath(dest_parent_path);
|
||||
host_dest_full_path.touch();
|
||||
break;
|
||||
}
|
||||
case S_IFSOCK: {
|
||||
driver_->CreateDestinationPath(dest_parent_path);
|
||||
// FIXME: can not mound dbus socket on rootless
|
||||
host_dest_full_path.touch();
|
||||
break;
|
||||
}
|
||||
case S_IFLNK: {
|
||||
driver_->CreateDestinationPath(dest_parent_path);
|
||||
host_dest_full_path.touch();
|
||||
source = util::fs::read_symlink(util::fs::path(source)).string();
|
||||
break;
|
||||
}
|
||||
case S_IFREG: {
|
||||
driver_->CreateDestinationPath(dest_parent_path);
|
||||
host_dest_full_path.touch();
|
||||
break;
|
||||
}
|
||||
case S_IFDIR:
|
||||
driver_->CreateDestinationPath(dest_full_path);
|
||||
break;
|
||||
default:
|
||||
driver_->CreateDestinationPath(dest_full_path);
|
||||
if (is_path) {
|
||||
logWan() << "unknown file type" << (source_stat.st_mode & S_IFMT) << source;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
auto data = util::str_vec_join(m.data, ',');
|
||||
auto real_data = data;
|
||||
auto real_flags = m.flags;
|
||||
|
||||
switch (m.fsType) {
|
||||
case Mount::Bind:
|
||||
// make sure m.flags always have MS_BIND
|
||||
real_flags |= MS_BIND;
|
||||
|
||||
// When doing a bind mount, all flags expect MS_BIND and MS_REC are ignored by kernel.
|
||||
real_flags &= (MS_BIND | MS_REC);
|
||||
|
||||
// When doing a bind mount, data and fstype are ignored by kernel. We should set them by remounting.
|
||||
real_data = "";
|
||||
ret = util::fs::do_mount_with_fd(root.c_str(), source.c_str(), host_dest_full_path.string().c_str(),
|
||||
nullptr, real_flags, nullptr);
|
||||
if (0 != ret) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (source == "/sys") {
|
||||
sysfs_is_binded = true;
|
||||
}
|
||||
|
||||
if (data.empty() && (m.flags & ~(MS_BIND | MS_REC | MS_REMOUNT)) == 0) {
|
||||
// no need to be remounted
|
||||
break;
|
||||
}
|
||||
|
||||
real_flags = m.flags | MS_BIND | MS_REMOUNT;
|
||||
|
||||
// When doing a remount, source and fstype are ignored by kernel.
|
||||
real_data = data;
|
||||
ret = util::fs::do_mount_with_fd(root.c_str(), nullptr, host_dest_full_path.string().c_str(), nullptr,
|
||||
real_flags, real_data.c_str());
|
||||
break;
|
||||
case Mount::Proc:
|
||||
case Mount::Devpts:
|
||||
case Mount::Mqueue:
|
||||
case Mount::Tmpfs:
|
||||
case Mount::Sysfs:
|
||||
ret = util::fs::do_mount_with_fd(root.c_str(), source.c_str(), host_dest_full_path.string().c_str(),
|
||||
m.type.c_str(), real_flags, real_data.c_str());
|
||||
if (ret < 0) {
|
||||
// refers:
|
||||
// https://github.com/containers/podman/blob/466b8991c4025006eeb43cb30e6dc990d92df72d/pkg/specgen/generate/oci.go#L178
|
||||
// https://github.com/containers/crun/blob/38e1b5e2a3e9567ff188258b435085e329aaba42/src/libcrun/linux.c#L768-L789
|
||||
if (m.fsType == Mount::Sysfs) {
|
||||
real_flags = MS_BIND | MS_REC;
|
||||
real_data = "";
|
||||
ret = util::fs::do_mount_with_fd(root.c_str(), "/sys", host_dest_full_path.string().c_str(),
|
||||
nullptr, real_flags, nullptr);
|
||||
if (ret == 0) {
|
||||
sysfs_is_binded = true;
|
||||
}
|
||||
} else if (m.fsType == Mount::Mqueue) {
|
||||
real_flags = MS_BIND | MS_REC;
|
||||
real_data = "";
|
||||
ret = util::fs::do_mount_with_fd(root.c_str(), "/dev/mqueue", host_dest_full_path.string().c_str(),
|
||||
nullptr, real_flags, nullptr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Mount::Cgroup:
|
||||
ret = util::fs::do_mount_with_fd(root.c_str(), source.c_str(), host_dest_full_path.string().c_str(),
|
||||
m.type.c_str(), real_flags, real_data.c_str());
|
||||
// When sysfs is bind-mounted, It is ok to let cgroup mount failed.
|
||||
// https://github.com/containers/podman/blob/466b8991c4025006eeb43cb30e6dc990d92df72d/pkg/specgen/generate/oci.go#L281
|
||||
if (sysfs_is_binded) {
|
||||
ret = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logErr() << "unsupported type" << m.type;
|
||||
}
|
||||
|
||||
if (EXIT_SUCCESS != ret) {
|
||||
logErr() << "mount" << source << "to" << host_dest_full_path << "failed:" << util::RetErrString(ret)
|
||||
<< "\nmount args is:" << m.type << real_flags << real_data;
|
||||
if (is_path) {
|
||||
logErr() << "source file type is: 0x" << std::hex << (source_stat.st_mode & S_IFMT);
|
||||
DUMP_FILE_INFO(source);
|
||||
}
|
||||
DUMP_FILE_INFO(host_dest_full_path.string());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::unique_ptr<FilesystemDriver> driver_;
|
||||
mutable bool sysfs_is_binded = false;
|
||||
};
|
||||
|
||||
HostMount::HostMount()
|
||||
: dd_ptr(new HostMountPrivate())
|
||||
{
|
||||
}
|
||||
|
||||
int HostMount::MountNode(const struct Mount &m)
|
||||
{
|
||||
return dd_ptr->MountNode(m);
|
||||
}
|
||||
|
||||
int HostMount::Setup(FilesystemDriver *driver)
|
||||
{
|
||||
if (nullptr == driver) {
|
||||
logWan() << this << dd_ptr->driver_.get();
|
||||
return 0;
|
||||
}
|
||||
|
||||
dd_ptr->driver_ = std::unique_ptr<FilesystemDriver>(driver);
|
||||
return dd_ptr->driver_->Setup();
|
||||
}
|
||||
|
||||
HostMount::~HostMount() {};
|
||||
|
||||
} // namespace linglong
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef LINGLONG_BOX_SRC_CONTAINER_MOUNT_HOST_MOUNT_H_
|
||||
#define LINGLONG_BOX_SRC_CONTAINER_MOUNT_HOST_MOUNT_H_
|
||||
|
||||
#include "util/oci_runtime.h"
|
||||
|
||||
namespace linglong {
|
||||
|
||||
class FilesystemDriver;
|
||||
class HostMountPrivate;
|
||||
|
||||
class HostMount
|
||||
{
|
||||
public:
|
||||
HostMount();
|
||||
~HostMount();
|
||||
|
||||
int Setup(FilesystemDriver *driver);
|
||||
|
||||
int MountNode(const Mount &m);
|
||||
|
||||
private:
|
||||
std::unique_ptr<HostMountPrivate> dd_ptr;
|
||||
};
|
||||
|
||||
} // namespace linglong
|
||||
|
||||
#endif /* LINGLONG_BOX_SRC_CONTAINER_MOUNT_HOST_MOUNT_H_ */
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "seccomp.h"
|
||||
|
||||
#include <seccomp.h>
|
||||
|
||||
namespace {
|
||||
|
||||
#define SYSCALL_PAIR(SYSCALL) \
|
||||
{ \
|
||||
LL_TOSTRING(SYSCALL), SCMP_SYS(SYSCALL) \
|
||||
}
|
||||
|
||||
std::vector<struct scmp_arg_cmp> toScmpArgCmpArray(const std::vector<linglong::SyscallArg> &args)
|
||||
{
|
||||
static const std::map<std::string, scmp_compare> seccompArgOpMap = {
|
||||
{"_SCMP_CMP_MIN", _SCMP_CMP_MIN}, {"SCMP_CMP_NE", SCMP_CMP_NE},
|
||||
{"SCMP_CMP_LT", SCMP_CMP_LT}, {"SCMP_CMP_LE", SCMP_CMP_LE},
|
||||
{"SCMP_CMP_EQ", SCMP_CMP_EQ}, {"SCMP_CMP_GE", SCMP_CMP_GE},
|
||||
{"SCMP_CMP_GT", SCMP_CMP_GT}, {"SCMP_CMP_MASKED_EQ", SCMP_CMP_MASKED_EQ},
|
||||
{"_SCMP_CMP_MAX", _SCMP_CMP_MAX},
|
||||
};
|
||||
|
||||
std::vector<struct scmp_arg_cmp> scmpArgs;
|
||||
|
||||
unsigned int index = 0;
|
||||
for (auto const &arg : args) {
|
||||
scmpArgs.push_back({
|
||||
.arg = index,
|
||||
.op = seccompArgOpMap.at(arg.op),
|
||||
.datum_a = arg.value,
|
||||
.datum_b = arg.valueTwo,
|
||||
});
|
||||
++index;
|
||||
}
|
||||
|
||||
return scmpArgs;
|
||||
}
|
||||
|
||||
int toSyscallNumber(const std::string &name)
|
||||
{
|
||||
// unistd.h for example: __NR_read
|
||||
|
||||
// FIXME: need full support
|
||||
static const std::map<std::string, int> syscallNameMap = {
|
||||
SYSCALL_PAIR(read), SYSCALL_PAIR(write), SYSCALL_PAIR(open), SYSCALL_PAIR(stat),
|
||||
SYSCALL_PAIR(getcwd), SYSCALL_PAIR(chmod), SYSCALL_PAIR(syslog), SYSCALL_PAIR(uselib),
|
||||
SYSCALL_PAIR(acct), SYSCALL_PAIR(modify_ldt), SYSCALL_PAIR(quotactl), SYSCALL_PAIR(add_key),
|
||||
SYSCALL_PAIR(keyctl), SYSCALL_PAIR(request_key), SYSCALL_PAIR(move_pages), SYSCALL_PAIR(mbind),
|
||||
SYSCALL_PAIR(get_mempolicy), SYSCALL_PAIR(set_mempolicy), SYSCALL_PAIR(migrate_pages), SYSCALL_PAIR(unshare),
|
||||
SYSCALL_PAIR(mount), SYSCALL_PAIR(pivot_root), SYSCALL_PAIR(clone), SYSCALL_PAIR(ioctl),
|
||||
};
|
||||
|
||||
return syscallNameMap.at(name);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace linglong {
|
||||
|
||||
int ConfigSeccomp(const tl::optional<linglong::Seccomp> &seccomp)
|
||||
{
|
||||
if (!seccomp.has_value()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const std::map<std::string, int> seccompActionMap = {
|
||||
{"SCMP_ACT_KILL", SCMP_ACT_KILL}, {"SCMP_ACT_TRAP", SCMP_ACT_TRAP},
|
||||
{"SCMP_ACT_ERRNO", SCMP_ACT_ERRNO(EPERM)}, {"SCMP_ACT_TRACE", SCMP_ACT_TRACE(EPERM)},
|
||||
{"SCMP_ACT_ALLOW", SCMP_ACT_ALLOW},
|
||||
};
|
||||
|
||||
// FIXME: need full support
|
||||
static const std::map<std::string, int> seccompArchMap = {
|
||||
{"SCMP_ARCH_X86", SCMP_ARCH_X86},
|
||||
{"SCMP_ARCH_X86_64", SCMP_ARCH_X86_64},
|
||||
{"SCMP_ARCH_X32", SCMP_ARCH_X32},
|
||||
|
||||
{"SCMP_ARCH_ARM", SCMP_ARCH_ARM},
|
||||
{"SCMP_ARCH_AARCH64", SCMP_ARCH_AARCH64},
|
||||
|
||||
{"SCMP_ARCH_MIPS", SCMP_ARCH_MIPS},
|
||||
{"SCMP_ARCH_MIPS64", SCMP_ARCH_MIPS64},
|
||||
{"SCMP_ARCH_MIPS64N32", SCMP_ARCH_MIPS64N32},
|
||||
{"SCMP_ARCH_MIPSEL", SCMP_ARCH_MIPSEL},
|
||||
{"SCMP_ARCH_MIPSEL64", SCMP_ARCH_MIPSEL64},
|
||||
{"SCMP_ARCH_MIPSEL64N32", SCMP_ARCH_MIPSEL64N32},
|
||||
};
|
||||
|
||||
int ret;
|
||||
scmp_filter_ctx ctx = nullptr;
|
||||
|
||||
try {
|
||||
auto defaultAction = seccompActionMap.at(seccomp->defaultAction);
|
||||
|
||||
ctx = seccomp_init(defaultAction);
|
||||
if (ctx == nullptr) {
|
||||
throw std::runtime_error(util::errnoString() + " seccomp_init=" + seccomp->defaultAction);
|
||||
}
|
||||
for (auto const &architecture : seccomp->architectures) {
|
||||
auto scmpArch = seccompArchMap.at(architecture);
|
||||
if (seccomp_arch_exist(ctx, scmpArch) == -EEXIST) {
|
||||
ret = seccomp_arch_add(ctx, scmpArch);
|
||||
if (ret != 0) {
|
||||
throw std::runtime_error(util::errnoString() + " architecture=" + architecture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const &syscall : seccomp->syscalls) {
|
||||
auto action = seccompActionMap.at(syscall.action);
|
||||
auto argc = syscall.args.size();
|
||||
auto args = toScmpArgCmpArray(syscall.args);
|
||||
|
||||
for (auto const &name : syscall.names) {
|
||||
auto sysNumber = toSyscallNumber(name);
|
||||
|
||||
ret = seccomp_rule_add_array(ctx, action, sysNumber, argc, args.data());
|
||||
if (ret != 0) {
|
||||
throw std::runtime_error(util::errnoString() + " syscall.name=" + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
ret = seccomp_load(ctx);
|
||||
} catch (const std::exception &e) {
|
||||
logErr() << "config seccomp failed:" << e.what();
|
||||
ret = -1;
|
||||
} catch (...) {
|
||||
logErr() << "unknown error";
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (!ctx) {
|
||||
seccomp_release(ctx);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace linglong
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef LINGLONG_BOX_SRC_CONTAINER_SECCOMP_H_
|
||||
#define LINGLONG_BOX_SRC_CONTAINER_SECCOMP_H_
|
||||
|
||||
#include "util/oci_runtime.h"
|
||||
|
||||
namespace linglong {
|
||||
int ConfigSeccomp(const tl::optional<linglong::Seccomp> &seccomp);
|
||||
}
|
||||
|
||||
#endif /* LINGLONG_BOX_SRC_CONTAINER_SECCOMP_H_ */
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/app.h"
|
||||
|
||||
#include "linyaps_box/command/exec.h"
|
||||
#include "linyaps_box/command/kill.h"
|
||||
#include "linyaps_box/command/list.h"
|
||||
#include "linyaps_box/command/run.h"
|
||||
#include "linyaps_box/utils/log.h"
|
||||
#include "utils/log.h"
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename... T>
|
||||
struct subCommand : T...
|
||||
{
|
||||
using T::operator()...;
|
||||
};
|
||||
|
||||
template<typename... T>
|
||||
subCommand(T...) -> subCommand<T...>;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace linyaps_box {
|
||||
|
||||
// The main function of the ll-box,
|
||||
// it is the entry point.
|
||||
// Command line arguments are parsed according to
|
||||
// https://github.com/opencontainers/runtime-tools/blob/v0.9.0/docs/command-line-interface.md
|
||||
// Extended commands and options should be compatible with crun.
|
||||
auto main(int argc, char **argv) noexcept -> int
|
||||
try {
|
||||
LINYAPS_BOX_DEBUG() << "linyaps box called with" << [=]() -> std::string {
|
||||
std::stringstream result;
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
result << " \"";
|
||||
for (const auto ch : std::string_view(argv[i])) { // NOLINT
|
||||
if (ch == '\\') {
|
||||
result << "\\\\";
|
||||
} else if (ch == '"') {
|
||||
result << "\\\"";
|
||||
} else {
|
||||
result << ch;
|
||||
}
|
||||
}
|
||||
result << "\"";
|
||||
}
|
||||
return result.str();
|
||||
}();
|
||||
|
||||
auto opts = command::parse(argc, argv);
|
||||
if (opts.global.return_code != 0) {
|
||||
return opts.global.return_code;
|
||||
}
|
||||
|
||||
return std::visit(subCommand{ [](const command::list_options &options) {
|
||||
command::list(options);
|
||||
return 0;
|
||||
},
|
||||
[](const command::exec_options &options) -> int {
|
||||
command::exec(options);
|
||||
__builtin_unreachable();
|
||||
},
|
||||
[](const command::kill_options &options) {
|
||||
command::kill(options);
|
||||
return 0;
|
||||
},
|
||||
[](const command::run_options &options) {
|
||||
return command::run(options);
|
||||
},
|
||||
[](const std::monostate &) {
|
||||
return 0;
|
||||
} },
|
||||
opts.subcommand_opt);
|
||||
} catch (const std::exception &e) {
|
||||
LINYAPS_BOX_ERR() << "Error: " << e.what();
|
||||
return -1;
|
||||
} catch (...) {
|
||||
LINYAPS_BOX_ERR() << "unknown error";
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace linyaps_box
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace linyaps_box {
|
||||
|
||||
auto main(int argc, char **argv) noexcept -> int;
|
||||
|
||||
} // namespace linyaps_box
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace linyaps_box {
|
||||
|
||||
enum class cgroup_manager_t : std::uint8_t { disabled, systemd, cgroupfs };
|
||||
|
||||
struct cgroup_options
|
||||
{
|
||||
std::unordered_map<std::string, std::string> annotations;
|
||||
std::filesystem::path cgroup_path;
|
||||
std::filesystem::path state_root;
|
||||
std::string id;
|
||||
pid_t pid;
|
||||
// resources and so on...
|
||||
};
|
||||
|
||||
struct cgroup_status
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] auto path() const noexcept -> std::filesystem::path { return path_; }
|
||||
|
||||
[[nodiscard]] auto scope() const noexcept -> std::string_view { return scope_; }
|
||||
|
||||
[[nodiscard]] auto manager() const noexcept -> cgroup_manager_t { return manager_; }
|
||||
|
||||
private:
|
||||
friend class cgroup_manager;
|
||||
std::filesystem::path path_;
|
||||
std::string scope_;
|
||||
cgroup_manager_t manager_;
|
||||
};
|
||||
|
||||
inline auto operator<<(std::ostream &stream, cgroup_manager_t manager) -> std::ostream &
|
||||
{
|
||||
switch (manager) {
|
||||
case cgroup_manager_t::disabled: {
|
||||
stream << "disabled";
|
||||
} break;
|
||||
case cgroup_manager_t::systemd: {
|
||||
stream << "systemd";
|
||||
} break;
|
||||
case cgroup_manager_t::cgroupfs: {
|
||||
stream << "cgroupfs";
|
||||
} break;
|
||||
default: {
|
||||
stream << "unknown";
|
||||
} break;
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
} // namespace linyaps_box
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include <linyaps_box/cgroup_manager.h>
|
||||
|
||||
namespace linyaps_box {
|
||||
|
||||
cgroup_manager::~cgroup_manager() = default;
|
||||
|
||||
} // namespace linyaps_box
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "linyaps_box/utils/file_describer.h"
|
||||
|
||||
#include <linyaps_box/cgroup.h>
|
||||
#include <linyaps_box/interface.h>
|
||||
|
||||
namespace linyaps_box {
|
||||
class cgroup_manager : public virtual interface
|
||||
{
|
||||
public:
|
||||
cgroup_manager() = default;
|
||||
~cgroup_manager() override;
|
||||
|
||||
cgroup_manager(const cgroup_manager &) = delete;
|
||||
auto operator=(const cgroup_manager &) -> cgroup_manager & = delete;
|
||||
cgroup_manager(cgroup_manager &&) = delete;
|
||||
auto operator=(cgroup_manager &&) -> cgroup_manager & = delete;
|
||||
|
||||
[[nodiscard]] virtual auto type() const -> cgroup_manager_t = 0;
|
||||
|
||||
virtual auto create_cgroup(const cgroup_options &options) -> cgroup_status = 0;
|
||||
|
||||
virtual void precreate_cgroup(const cgroup_options &options, utils::file_descriptor &dirfd) = 0;
|
||||
|
||||
virtual void destroy_cgroup(const cgroup_status &status) = 0;
|
||||
|
||||
// TODO: support update resource
|
||||
// virtual void update_resource(const cgroup_status &status, ) = 0;
|
||||
protected:
|
||||
static void set_manager(cgroup_status &status, cgroup_manager_t type) noexcept
|
||||
{
|
||||
status.manager_ = type;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace linyaps_box
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/command/exec.h"
|
||||
|
||||
#include "linyaps_box/impl/status_directory.h"
|
||||
#include "linyaps_box/runtime.h"
|
||||
#include "linyaps_box/status_directory.h"
|
||||
|
||||
void linyaps_box::command::exec(const struct exec_options &options)
|
||||
{
|
||||
std::unique_ptr<status_directory> dir =
|
||||
std::make_unique<impl::status_directory>(options.global_.get().root);
|
||||
runtime_t runtime(std::move(dir));
|
||||
|
||||
auto container_refs = runtime.containers();
|
||||
auto container = container_refs.find(options.ID);
|
||||
if (container == container_refs.end()) {
|
||||
throw std::runtime_error("container not found");
|
||||
}
|
||||
|
||||
config::process_t proc;
|
||||
proc.cwd = options.cwd.value_or("/");
|
||||
proc.args = options.command;
|
||||
proc.terminal = isatty(STDIN_FILENO) == 1 && isatty(STDOUT_FILENO) == 1;
|
||||
proc.no_new_privileges = options.no_new_privs;
|
||||
proc.env = options.envs.value_or(std::vector<std::string>{});
|
||||
|
||||
#ifdef LINYAPS_BOX_ENABLE_CAP
|
||||
if (options.caps) {
|
||||
const auto &caps = options.caps.value();
|
||||
auto transform_cap = [&caps](std::vector<cap_value_t> &cap_set) {
|
||||
std::transform(caps.cbegin(),
|
||||
caps.cend(),
|
||||
std::back_inserter(cap_set),
|
||||
[](const std::string &cap) {
|
||||
cap_value_t val{ 0 };
|
||||
if (cap_from_name(cap.c_str(), &val) < 0) {
|
||||
throw std::system_error(errno,
|
||||
std::generic_category(),
|
||||
"cap_from_name");
|
||||
}
|
||||
|
||||
return val;
|
||||
});
|
||||
};
|
||||
|
||||
transform_cap(proc.capabilities.effective);
|
||||
transform_cap(proc.capabilities.ambient);
|
||||
transform_cap(proc.capabilities.bounding);
|
||||
transform_cap(proc.capabilities.permitted);
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO: support exec fully
|
||||
|
||||
container->second.exec(proc);
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "linyaps_box/command/options.h"
|
||||
|
||||
namespace linyaps_box::command {
|
||||
|
||||
[[noreturn]] void exec(const exec_options &options);
|
||||
|
||||
} // namespace linyaps_box::command
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/command/kill.h"
|
||||
|
||||
#include "linyaps_box/impl/status_directory.h"
|
||||
#include "linyaps_box/runtime.h"
|
||||
#include "linyaps_box/utils/platform.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
void linyaps_box::command::kill(const struct kill_options &options)
|
||||
{
|
||||
auto signal{ options.signal };
|
||||
int sig{ -1 };
|
||||
while (true) {
|
||||
if (std::all_of(signal.cbegin(), signal.cend(), ::isdigit)) {
|
||||
sig = std::stoi(signal);
|
||||
break;
|
||||
}
|
||||
|
||||
if (signal.rfind("SIG", 0) == std::string::npos) {
|
||||
signal.insert(0, "SIG");
|
||||
}
|
||||
|
||||
sig = utils::str_to_signal(signal);
|
||||
break;
|
||||
}
|
||||
|
||||
auto status_dir = std::make_unique<impl::status_directory>(options.global_.get().root);
|
||||
if (!status_dir) {
|
||||
throw std::runtime_error("failed to create status directory");
|
||||
}
|
||||
|
||||
runtime_t runtime(std::move(status_dir));
|
||||
const auto &containers = runtime.containers();
|
||||
for (const auto &[id, ref] : containers) {
|
||||
if (id != options.container) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ref.kill(sig);
|
||||
return;
|
||||
}
|
||||
|
||||
throw std::runtime_error("container not found");
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "linyaps_box/command/options.h"
|
||||
|
||||
namespace linyaps_box::command {
|
||||
|
||||
void kill(const kill_options &options);
|
||||
|
||||
} // namespace linyaps_box::command
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/command/list.h"
|
||||
|
||||
#include "linyaps_box/impl/json_printer.h"
|
||||
#include "linyaps_box/impl/status_directory.h"
|
||||
#include "linyaps_box/impl/table_printer.h"
|
||||
#include "linyaps_box/runtime.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
void linyaps_box::command::list(const struct list_options &options)
|
||||
{
|
||||
auto status_dir = std::make_unique<impl::status_directory>(options.global_.get().root);
|
||||
if (!status_dir) {
|
||||
throw std::runtime_error("failed to create status directory");
|
||||
}
|
||||
|
||||
runtime_t runtime(std::move(status_dir));
|
||||
|
||||
std::unique_ptr<printer> printer;
|
||||
if (options.output_format == list_options::output_format_t::json) {
|
||||
printer = std::make_unique<impl::json_printer>();
|
||||
} else {
|
||||
printer = std::make_unique<impl::table_printer>();
|
||||
}
|
||||
|
||||
auto containers = runtime.containers();
|
||||
std::vector<container_status_t> statuses;
|
||||
statuses.reserve(containers.size());
|
||||
for (const auto &[_, container] : containers) {
|
||||
statuses.emplace_back(container.status());
|
||||
}
|
||||
|
||||
printer->print_statuses(statuses);
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "linyaps_box/command/options.h"
|
||||
|
||||
namespace linyaps_box::command {
|
||||
|
||||
void list(const list_options &options);
|
||||
|
||||
} // namespace linyaps_box::command
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/command/options.h"
|
||||
|
||||
#include "linyaps_box/config.h"
|
||||
#include "linyaps_box/version.h"
|
||||
|
||||
#include <CLI/CLI.hpp>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
linyaps_box::command::options linyaps_box::command::parse(int argc, char *argv[]) // NOLINT
|
||||
{
|
||||
CLI::App app{ "A simple OCI runtime implementation focused on desktop applications.",
|
||||
"ll-box" };
|
||||
app.set_version_flag("-v,--version", [] {
|
||||
std::stringstream ss;
|
||||
ss << "ll-box version " << LINYAPS_BOX_VERSION << "\n";
|
||||
ss << "spec " << linyaps_box::config::oci_version;
|
||||
return ss.str();
|
||||
});
|
||||
app.require_subcommand();
|
||||
|
||||
linyaps_box::command::options options;
|
||||
|
||||
auto default_root = std::filesystem::current_path().root_path() / "run" / "user"
|
||||
/ std::to_string(geteuid()) / "linglong" / "box";
|
||||
|
||||
if (auto *env = getenv("XDG_RUNTIME_DIR"); env != nullptr) {
|
||||
default_root = std::filesystem::path{ env } / "linglong" / "box";
|
||||
}
|
||||
|
||||
app.add_option("--root", options.global.root, "Root directory for storage of container state")
|
||||
->default_val(default_root);
|
||||
app.add_option("--cgroup-manager", options.global.manager, "Cgroup manager to use")
|
||||
->type_name("MANAGER")
|
||||
->transform(
|
||||
CLI::CheckedTransformer(std::unordered_map<std::string_view, cgroup_manager_t>{
|
||||
{ "cgroupfs", cgroup_manager_t::cgroupfs },
|
||||
{ "systemd", cgroup_manager_t::systemd },
|
||||
{ "disabled", cgroup_manager_t::disabled },
|
||||
}))
|
||||
->default_val(cgroup_manager_t::disabled);
|
||||
|
||||
list_options list_opt{ options.global };
|
||||
auto *cmd_list = app.add_subcommand("list", "List know containers");
|
||||
cmd_list->add_option("-f,--format", list_opt.output_format, "Specify the output format")
|
||||
->type_name("FORMAT")
|
||||
->transform(CLI::CheckedTransformer(
|
||||
std::unordered_map<std::string_view, list_options::output_format_t>{
|
||||
{ "json", list_options::output_format_t::json },
|
||||
{ "table", list_options::output_format_t::table },
|
||||
}))
|
||||
->default_val(list_options::output_format_t::table);
|
||||
|
||||
run_options run_opt{ options.global };
|
||||
auto *cmd_run = app.add_subcommand("run", "Create and immediately start a container");
|
||||
cmd_run->add_option("CONTAINER", run_opt.ID, "The container ID")->required();
|
||||
cmd_run->add_option("-b,--bundle", run_opt.bundle, "Path to the OCI bundle")->default_val(".");
|
||||
cmd_run->add_option("-f,--config", run_opt.config, "Override the configuration file to use")
|
||||
->default_val("config.json");
|
||||
cmd_run->add_option("--preserve-fds",
|
||||
run_opt.preserve_fds,
|
||||
"Pass N additional file descriptors to the container")
|
||||
->default_val(0);
|
||||
|
||||
exec_options exec_opt{ options.global };
|
||||
auto *cmd_exec = app.add_subcommand("exec", "Exec a command in a running container")
|
||||
->positionals_at_end();
|
||||
cmd_exec->add_option("-u,--user",
|
||||
exec_opt.user,
|
||||
"Specify the user, "
|
||||
"for example `1000` for UID=1000 "
|
||||
"or `1000:1000` for UID=1000 and GID=1000")
|
||||
->type_name("UID[:GID]");
|
||||
cmd_exec->add_option("--cwd", exec_opt.cwd, "Current working directory.");
|
||||
cmd_exec->add_option("--env", exec_opt.envs, "Environment variables to set")
|
||||
->multi_option_policy(CLI::MultiOptionPolicy::TakeAll)
|
||||
->check(
|
||||
[](const std::string &str) {
|
||||
if (str.find('=') == std::string::npos) {
|
||||
return "invalid argument, env must be in the format of KEY=VALUE";
|
||||
}
|
||||
return "";
|
||||
},
|
||||
"env_check");
|
||||
// TODO: enable capabilities and no_new_privs support after rewrite exec,
|
||||
// cmd_exec->add_option("-c,--cap", options.exec.caps, "Set capabilities")
|
||||
// ->check(
|
||||
// [](const std::string &val) -> std::string {
|
||||
// if (val.rfind("CAP_", 0) != std::string::npos) {
|
||||
// return "";
|
||||
// }
|
||||
|
||||
// return "invalid argument, capability must start with CAP_";
|
||||
// },
|
||||
// "cap_check");
|
||||
// cmd_exec->add_flag("--no-new-privs",
|
||||
// options.exec.no_new_privs,
|
||||
// "Set the no new privileges value for the process")
|
||||
// ->default_val(false);
|
||||
cmd_exec->add_option("CONTAINER", exec_opt.ID, "Container ID")->required();
|
||||
cmd_exec->add_option("COMMAND", exec_opt.command, "Command to execute")->required();
|
||||
|
||||
kill_options kill_opt{ options.global };
|
||||
auto *cmd_kill =
|
||||
app.add_subcommand("kill", "Send the specified signal to the container init process");
|
||||
cmd_kill->add_option("CONTAINER", kill_opt.container, "The container ID")->required();
|
||||
cmd_kill->add_option("SIGNAL", kill_opt.signal, "Signal to send")->default_val("SIGTERM");
|
||||
|
||||
argv = app.ensure_utf8(argv);
|
||||
try {
|
||||
app.parse(argc, argv);
|
||||
} catch (const CLI::ParseError &e) {
|
||||
options.global.return_code = app.exit(e);
|
||||
return options;
|
||||
}
|
||||
|
||||
if (cmd_list->parsed()) {
|
||||
options.subcommand_opt = list_opt;
|
||||
} else if (cmd_run->parsed()) {
|
||||
options.subcommand_opt = run_opt;
|
||||
} else if (cmd_exec->parsed()) {
|
||||
options.subcommand_opt = exec_opt;
|
||||
} else if (cmd_kill->parsed()) {
|
||||
options.subcommand_opt = kill_opt;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <linyaps_box/cgroup_manager.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace linyaps_box::command {
|
||||
|
||||
struct global_options
|
||||
{
|
||||
cgroup_manager_t manager{ cgroup_manager_t::disabled };
|
||||
std::filesystem::path root;
|
||||
int return_code{ 0 };
|
||||
};
|
||||
|
||||
struct list_options
|
||||
{
|
||||
enum class output_format_t : std::uint8_t { table, json };
|
||||
|
||||
explicit list_options(global_options &global)
|
||||
: global_(global)
|
||||
{
|
||||
}
|
||||
|
||||
output_format_t output_format{ output_format_t::table };
|
||||
std::reference_wrapper<global_options> global_;
|
||||
};
|
||||
|
||||
struct exec_options
|
||||
{
|
||||
explicit exec_options(global_options &global)
|
||||
: no_new_privs(false)
|
||||
, global_(global)
|
||||
{
|
||||
}
|
||||
|
||||
bool no_new_privs;
|
||||
std::reference_wrapper<global_options> global_;
|
||||
std::vector<std::string> command;
|
||||
std::string user;
|
||||
std::optional<std::vector<std::string>> caps;
|
||||
std::string ID;
|
||||
std::optional<std::string> cwd;
|
||||
std::optional<std::vector<std::string>> envs;
|
||||
};
|
||||
|
||||
struct run_options
|
||||
{
|
||||
explicit run_options(global_options &global)
|
||||
: global_(global)
|
||||
{
|
||||
}
|
||||
|
||||
std::reference_wrapper<global_options> global_;
|
||||
std::string ID;
|
||||
std::string bundle;
|
||||
std::string config;
|
||||
int preserve_fds;
|
||||
};
|
||||
|
||||
struct kill_options
|
||||
{
|
||||
explicit kill_options(global_options &global)
|
||||
: global_(global)
|
||||
{
|
||||
}
|
||||
|
||||
std::reference_wrapper<global_options> global_;
|
||||
std::string container;
|
||||
std::string signal;
|
||||
};
|
||||
|
||||
struct options
|
||||
{
|
||||
options()
|
||||
: global()
|
||||
{
|
||||
}
|
||||
|
||||
using subcommand_opt_t =
|
||||
std::variant<std::monostate, list_options, exec_options, run_options, kill_options>;
|
||||
|
||||
global_options global;
|
||||
subcommand_opt_t subcommand_opt;
|
||||
};
|
||||
|
||||
// This function parses the command line arguments.
|
||||
// It might print help or usage to stdout or stderr.
|
||||
options parse(int argc, char *argv[]); // NOLINT
|
||||
|
||||
} // namespace linyaps_box::command
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/command/run.h"
|
||||
|
||||
#include "linyaps_box/impl/status_directory.h"
|
||||
#include "linyaps_box/runtime.h"
|
||||
#include "linyaps_box/status_directory.h"
|
||||
|
||||
auto linyaps_box::command::run(const struct run_options &options) -> int
|
||||
{
|
||||
std::unique_ptr<status_directory> dir =
|
||||
std::make_unique<impl::status_directory>(options.global_.get().root);
|
||||
runtime_t runtime(std::move(dir));
|
||||
const create_container_options_t create_container_options{ options.global_.get().manager,
|
||||
options.preserve_fds,
|
||||
options.ID,
|
||||
options.bundle,
|
||||
options.config };
|
||||
|
||||
auto container = runtime.create_container(create_container_options);
|
||||
return container.run(container.get_config().process);
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "linyaps_box/command/options.h"
|
||||
|
||||
namespace linyaps_box::command {
|
||||
|
||||
[[nodiscard]] auto run(const run_options &options) -> int;
|
||||
|
||||
} // namespace linyaps_box::command
|
||||
|
|
@ -0,0 +1,467 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/config.h"
|
||||
|
||||
#include "linyaps_box/utils/semver.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
#include <sys/resource.h>
|
||||
|
||||
namespace {
|
||||
|
||||
// This function is used to parse the mount options from the config file and it only will be called
|
||||
// once.
|
||||
auto parse_mount_options(const std::vector<std::string> &options)
|
||||
-> std::tuple<unsigned long, unsigned long, std::uint8_t, std::string>
|
||||
{
|
||||
const std::unordered_map<std::string_view, unsigned long> propagation_flags_map{
|
||||
{ "rprivate", MS_PRIVATE | MS_REC }, { "private", MS_PRIVATE },
|
||||
{ "rslave", MS_SLAVE | MS_REC }, { "slave", MS_SLAVE },
|
||||
{ "rshared", MS_SHARED | MS_REC }, { "shared", MS_SHARED },
|
||||
{ "runbindable", MS_UNBINDABLE | MS_REC }, { "unbindable", MS_UNBINDABLE },
|
||||
};
|
||||
|
||||
const std::unordered_map<std::string_view, unsigned long> flags_map{
|
||||
{ "bind", MS_BIND },
|
||||
{ "defaults", 0 },
|
||||
{ "dirsync", MS_DIRSYNC },
|
||||
{ "iversion", MS_I_VERSION },
|
||||
{ "lazytime", MS_LAZYTIME },
|
||||
{ "mand", MS_MANDLOCK },
|
||||
{ "noatime", MS_NOATIME },
|
||||
{ "nodev", MS_NODEV },
|
||||
{ "nodiratime", MS_NODIRATIME },
|
||||
{ "noexec", MS_NOEXEC },
|
||||
{ "nosuid", MS_NOSUID },
|
||||
{ "nosymfollow", LINGYAPS_MS_NOSYMFOLLOW },
|
||||
{ "rbind", MS_BIND | MS_REC },
|
||||
{ "relatime", MS_RELATIME },
|
||||
{ "remount", MS_REMOUNT },
|
||||
{ "ro", MS_RDONLY },
|
||||
{ "silent", MS_SILENT },
|
||||
{ "strictatime", MS_STRICTATIME },
|
||||
{ "sync", MS_SYNCHRONOUS },
|
||||
};
|
||||
|
||||
const std::unordered_map<std::string_view, unsigned long> unset_flags_map{
|
||||
{ "async", MS_SYNCHRONOUS },
|
||||
{ "atime", MS_NOATIME },
|
||||
{ "dev", MS_NODEV },
|
||||
{ "diratime", MS_NODIRATIME },
|
||||
{ "exec", MS_NOEXEC },
|
||||
{ "loud", MS_SILENT },
|
||||
{ "noiversion", MS_I_VERSION },
|
||||
{ "nolazytime", MS_LAZYTIME },
|
||||
{ "nomand", MS_MANDLOCK },
|
||||
{ "norelatime", MS_RELATIME },
|
||||
{ "nostrictatime", MS_STRICTATIME },
|
||||
{ "rw", MS_RDONLY },
|
||||
{ "suid", MS_NOSUID },
|
||||
{ "symfollow", LINGYAPS_MS_NOSYMFOLLOW },
|
||||
};
|
||||
|
||||
const std::unordered_map<std::string_view, std::uint8_t> extra_flags_map{
|
||||
{ "copy-symlink", linyaps_box::config::mount_t::COPY_SYMLINK }
|
||||
};
|
||||
|
||||
unsigned long flags = 0;
|
||||
std::uint8_t extra_flags = 0;
|
||||
unsigned long propagation_flags = 0;
|
||||
std::stringstream data;
|
||||
|
||||
for (const auto &opt : options) {
|
||||
if (auto it = flags_map.find(opt); it != flags_map.end()) {
|
||||
flags |= it->second;
|
||||
continue;
|
||||
}
|
||||
if (auto it = unset_flags_map.find(opt); it != unset_flags_map.end()) {
|
||||
flags &= ~it->second;
|
||||
continue;
|
||||
}
|
||||
if (auto it = propagation_flags_map.find(opt); it != propagation_flags_map.end()) {
|
||||
propagation_flags |= it->second;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto it = extra_flags_map.find(opt); it != extra_flags_map.end()) {
|
||||
extra_flags |= it->second;
|
||||
continue;
|
||||
}
|
||||
|
||||
data << "," << opt;
|
||||
}
|
||||
auto str = data.str();
|
||||
if (!str.empty()) {
|
||||
str = str.substr(1);
|
||||
}
|
||||
|
||||
return { flags, propagation_flags, extra_flags, str };
|
||||
}
|
||||
|
||||
#ifdef LINYAPS_BOX_ENABLE_CAP
|
||||
linyaps_box::config::process_t::capabilities_t
|
||||
parse_capability(const nlohmann::json &obj, const nlohmann::json::json_pointer &ptr)
|
||||
{
|
||||
auto parse_cap_set = [&obj, &ptr](const char *set_name) {
|
||||
const auto set = ptr / set_name;
|
||||
std::vector<cap_value_t> cap_list;
|
||||
if (!obj.contains(set)) {
|
||||
return cap_list;
|
||||
}
|
||||
|
||||
const auto vec = obj[set].get<std::vector<std::string>>();
|
||||
std::for_each(vec.cbegin(), vec.cend(), [&cap_list](const std::string &cap) {
|
||||
cap_value_t val{ 0 };
|
||||
if (cap_from_name(cap.c_str(), &val) < 0) {
|
||||
throw std::runtime_error("unknown capability: " + cap);
|
||||
}
|
||||
|
||||
cap_list.push_back(val);
|
||||
});
|
||||
|
||||
return cap_list;
|
||||
};
|
||||
|
||||
linyaps_box::config::process_t::capabilities_t cap{};
|
||||
cap.effective = parse_cap_set("effective");
|
||||
cap.ambient = parse_cap_set("ambient");
|
||||
cap.bounding = parse_cap_set("bounding");
|
||||
cap.inheritable = parse_cap_set("inheritable");
|
||||
cap.permitted = parse_cap_set("permitted");
|
||||
|
||||
return cap;
|
||||
}
|
||||
#endif
|
||||
|
||||
linyaps_box::config::process_t::rlimits_t parse_rlimits(const nlohmann::json &obj,
|
||||
const nlohmann::json::json_pointer &ptr)
|
||||
{
|
||||
const auto &vec = obj[ptr];
|
||||
if (!vec.is_array()) {
|
||||
throw std::runtime_error("rlimits must be an array");
|
||||
}
|
||||
|
||||
linyaps_box::config::process_t::rlimits_t ret{};
|
||||
std::transform(
|
||||
vec.cbegin(),
|
||||
vec.cend(),
|
||||
std::back_inserter(ret),
|
||||
[](const nlohmann::json &json) {
|
||||
if (!json.is_object()) {
|
||||
throw std::runtime_error("rlimit must be an object");
|
||||
}
|
||||
|
||||
if (!json.contains("type")) {
|
||||
throw std::runtime_error("rlimit must contain type");
|
||||
}
|
||||
|
||||
return linyaps_box::config::process_t::rlimit_t{ json["type"].get<std::string>(),
|
||||
json["soft"].get<uint64_t>(),
|
||||
json["hard"].get<uint64_t>() };
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
auto parse_linux(const nlohmann::json &obj, const nlohmann::json::json_pointer &ptr)
|
||||
-> linyaps_box::config::linux_t
|
||||
{
|
||||
auto linux = linyaps_box::config::linux_t{};
|
||||
if (auto uid_ptr = ptr / "uidMappings"; obj.contains(uid_ptr)) {
|
||||
const auto &vec = obj[uid_ptr];
|
||||
std::vector<linyaps_box::config::linux_t::id_mapping_t> uid_mappings;
|
||||
std::transform(vec.cbegin(),
|
||||
vec.cend(),
|
||||
std::back_inserter(uid_mappings),
|
||||
[](const nlohmann::json &json) {
|
||||
return linyaps_box::config::linux_t::id_mapping_t{
|
||||
json["hostID"].get<uid_t>(),
|
||||
json["containerID"].get<uid_t>(),
|
||||
json["size"].get<size_t>(),
|
||||
};
|
||||
});
|
||||
linux.uid_mappings = std::move(uid_mappings);
|
||||
}
|
||||
|
||||
if (auto gid_ptr = ptr / "gidMappings"; obj.contains(gid_ptr)) {
|
||||
const auto &vec = obj[gid_ptr];
|
||||
std::vector<linyaps_box::config::linux_t::id_mapping_t> gid_mappings;
|
||||
std::transform(vec.cbegin(),
|
||||
vec.cend(),
|
||||
std::back_inserter(gid_mappings),
|
||||
[](const nlohmann::json &json) {
|
||||
return linyaps_box::config::linux_t::id_mapping_t{
|
||||
json["hostID"].get<uid_t>(),
|
||||
json["containerID"].get<uid_t>(),
|
||||
json["size"].get<size_t>(),
|
||||
};
|
||||
});
|
||||
linux.gid_mappings = std::move(gid_mappings);
|
||||
}
|
||||
|
||||
if (auto namespace_ptr = ptr / "namespaces"; obj.contains(namespace_ptr)) {
|
||||
auto map_fn = [](const nlohmann::json &json) {
|
||||
if (!json.contains("type")) {
|
||||
throw std::runtime_error("property `type` is REQUIRED for linux namespaces");
|
||||
}
|
||||
|
||||
linyaps_box::config::linux_t::namespace_t n;
|
||||
auto type = json["type"].get<std::string>();
|
||||
if (type == "pid") {
|
||||
n.type = linyaps_box::config::linux_t::namespace_t::type_t::PID;
|
||||
} else if (type == "network") {
|
||||
n.type = linyaps_box::config::linux_t::namespace_t::type_t::NET;
|
||||
} else if (type == "ipc") {
|
||||
n.type = linyaps_box::config::linux_t::namespace_t::type_t::IPC;
|
||||
} else if (type == "uts") {
|
||||
n.type = linyaps_box::config::linux_t::namespace_t::type_t::UTS;
|
||||
} else if (type == "mount") {
|
||||
n.type = linyaps_box::config::linux_t::namespace_t::type_t::MOUNT;
|
||||
} else if (type == "user") {
|
||||
n.type = linyaps_box::config::linux_t::namespace_t::type_t::USER;
|
||||
} else if (type == "cgroup") {
|
||||
n.type = linyaps_box::config::linux_t::namespace_t::type_t::CGROUP;
|
||||
} else {
|
||||
throw std::runtime_error("unsupported namespace type: " + type);
|
||||
}
|
||||
|
||||
if (json.contains("path")) {
|
||||
n.path = json["path"].get<std::string>();
|
||||
}
|
||||
|
||||
return n;
|
||||
};
|
||||
|
||||
const auto &vec = obj[namespace_ptr];
|
||||
std::vector<linyaps_box::config::linux_t::namespace_t> ns;
|
||||
std::transform(vec.cbegin(), vec.cend(), std::back_inserter(ns), map_fn);
|
||||
|
||||
linux.namespaces = std::move(ns);
|
||||
}
|
||||
|
||||
if (auto masked_path = ptr / "maskedPaths"; obj.contains(masked_path)) {
|
||||
const auto &vec = obj[masked_path];
|
||||
std::vector<std::filesystem::path> masked_paths;
|
||||
std::transform(vec.cbegin(),
|
||||
vec.cend(),
|
||||
std::back_inserter(masked_paths),
|
||||
[](const nlohmann::json &json) {
|
||||
return json.get<std::string>();
|
||||
});
|
||||
linux.masked_paths = std::move(masked_paths);
|
||||
}
|
||||
|
||||
if (auto readonly_path = ptr / "readonlyPaths"; obj.contains(readonly_path)) {
|
||||
const auto &vec = obj[readonly_path];
|
||||
std::vector<std::filesystem::path> readonly_paths;
|
||||
std::transform(vec.cbegin(),
|
||||
vec.cend(),
|
||||
std::back_inserter(readonly_paths),
|
||||
[](const nlohmann::json &json) {
|
||||
return json.get<std::string>();
|
||||
});
|
||||
linux.readonly_paths = std::move(readonly_paths);
|
||||
}
|
||||
|
||||
if (auto rootfs_propagation = ptr / "rootfsPropagation"; obj.contains(rootfs_propagation)) {
|
||||
auto val = obj[rootfs_propagation].get<std::string>();
|
||||
if (val == "shared") {
|
||||
linux.rootfs_propagation = MS_SHARED;
|
||||
} else if (val == "slave") {
|
||||
linux.rootfs_propagation = MS_SLAVE;
|
||||
} else if (val == "private") {
|
||||
linux.rootfs_propagation = MS_PRIVATE;
|
||||
} else if (val == "unbindable") {
|
||||
linux.rootfs_propagation = MS_UNBINDABLE;
|
||||
} else {
|
||||
throw std::runtime_error("unsupported rootfs propagation: " + val);
|
||||
}
|
||||
}
|
||||
|
||||
return linux;
|
||||
}
|
||||
|
||||
auto parse_1_2_0(const nlohmann::json &j) -> linyaps_box::config
|
||||
{
|
||||
const auto ptr = ""_json_pointer;
|
||||
|
||||
auto semver = linyaps_box::utils::semver(j[ptr / "ociVersion"].get<std::string>());
|
||||
if (!linyaps_box::utils::semver(linyaps_box::config::oci_version).is_compatible_with(semver)) {
|
||||
throw std::runtime_error("unsupported OCI version: " + semver.to_string());
|
||||
}
|
||||
|
||||
linyaps_box::config cfg;
|
||||
|
||||
{
|
||||
if (j.contains(ptr / "process" / "terminal")) {
|
||||
cfg.process.terminal = j[ptr / "process" / "terminal"].get<bool>();
|
||||
}
|
||||
|
||||
// https://github.com/opencontainers/runtime-spec/blob/09fcb39bb7185b46dfb206bc8f3fea914c674779/config.md?plain=1#L245
|
||||
if (cfg.process.terminal && j.contains(ptr / "process" / "consoleSize")) {
|
||||
cfg.process.console.height = j[ptr / "process" / "consoleSize" / "height"].get<uint>();
|
||||
cfg.process.console.width = j[ptr / "process" / "consoleSize" / "width"].get<uint>();
|
||||
}
|
||||
|
||||
cfg.process.cwd = j[ptr / "process" / "cwd"].get<std::string>();
|
||||
|
||||
if (j.contains(ptr / "process" / "env")) {
|
||||
auto env = j[ptr / "process" / "env"].get<std::vector<std::string>>();
|
||||
for (const auto &e : env) {
|
||||
auto pos = e.find('=');
|
||||
if (pos == std::string::npos) {
|
||||
throw std::runtime_error("invalid env entry: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
cfg.process.env = std::move(env);
|
||||
}
|
||||
|
||||
cfg.process.args = j[ptr / "process" / "args"].get<std::vector<std::string>>();
|
||||
|
||||
if (auto rlimits = ptr / "process" / "rlimits"; j.contains(rlimits)) {
|
||||
cfg.process.rlimits = parse_rlimits(j, rlimits);
|
||||
}
|
||||
|
||||
// TODO: apparmorProfile
|
||||
#ifdef LINYAPS_BOX_ENABLE_CAP
|
||||
if (auto cap = ptr / "process" / "capabilities"; j.contains(cap)) {
|
||||
cfg.process.capabilities = parse_capability(j, cap);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (j.contains(ptr / "process" / "noNewPrivileges")) {
|
||||
cfg.process.no_new_privileges = j[ptr / "process" / "noNewPrivileges"].get<bool>();
|
||||
}
|
||||
|
||||
if (j.contains(ptr / "process" / "oomScoreAdj")) {
|
||||
cfg.process.oom_score_adj = j[ptr / "process" / "oomScoreAdj"].get<int>();
|
||||
}
|
||||
|
||||
cfg.process.user.uid = j[ptr / "process" / "user" / "uid"].get<uid_t>();
|
||||
cfg.process.user.gid = j[ptr / "process" / "user" / "gid"].get<gid_t>();
|
||||
|
||||
if (j.contains(ptr / "process" / "user" / "umask")) {
|
||||
cfg.process.user.umask = j[ptr / "process" / "user" / "umask"].get<mode_t>();
|
||||
}
|
||||
|
||||
if (j.contains(ptr / "process" / "user" / "additionalGids")) {
|
||||
cfg.process.user.additional_gids =
|
||||
j[ptr / "process" / "user" / "additionalGids"].get<std::vector<gid_t>>();
|
||||
}
|
||||
}
|
||||
|
||||
if (auto linux_ptr = ptr / "linux"; j.contains(linux_ptr)) {
|
||||
cfg.linux = parse_linux(j, linux_ptr);
|
||||
}
|
||||
|
||||
if (j.contains(ptr / "hooks")) {
|
||||
auto hooks = j[ptr / "hooks"];
|
||||
auto get_hooks = [&](const std::string &key)
|
||||
-> std::optional<std::vector<linyaps_box::config::hooks_t::hook_t>> {
|
||||
if (!hooks.contains(key)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<linyaps_box::config::hooks_t::hook_t> result;
|
||||
for (const auto &h : hooks[key]) {
|
||||
linyaps_box::config::hooks_t::hook_t hook;
|
||||
hook.path = h["path"].get<std::string>();
|
||||
if (!hook.path.is_absolute()) {
|
||||
throw std::runtime_error(key + "path must be absolute");
|
||||
}
|
||||
|
||||
if (h.contains("args")) {
|
||||
hook.args = h["args"].get<std::vector<std::string>>();
|
||||
}
|
||||
|
||||
if (h.contains("env")) {
|
||||
std::unordered_map<std::string, std::string> env;
|
||||
|
||||
for (const auto &e : h["env"].get<std::vector<std::string>>()) {
|
||||
auto pos = e.find('=');
|
||||
if (pos == std::string::npos) {
|
||||
throw std::runtime_error("invalid env entry: " + e);
|
||||
}
|
||||
|
||||
env[e.substr(0, pos)] = e.substr(pos + 1);
|
||||
}
|
||||
|
||||
hook.env = std::move(env);
|
||||
}
|
||||
|
||||
if (h.contains("timeout")) {
|
||||
hook.timeout = h["timeout"].get<int>();
|
||||
if (hook.timeout <= 0) {
|
||||
throw std::runtime_error(key + "timeout must be greater than zero");
|
||||
}
|
||||
}
|
||||
|
||||
result.push_back(hook);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
cfg.hooks.prestart = get_hooks("prestart");
|
||||
cfg.hooks.create_runtime = get_hooks("createRuntime");
|
||||
cfg.hooks.create_container = get_hooks("createContainer");
|
||||
cfg.hooks.start_container = get_hooks("startContainer");
|
||||
cfg.hooks.poststart = get_hooks("poststart");
|
||||
cfg.hooks.poststop = get_hooks("poststop");
|
||||
}
|
||||
|
||||
if (j.contains(ptr / "mounts")) {
|
||||
std::vector<linyaps_box::config::mount_t> mounts;
|
||||
for (const auto &m : j[ptr / "mounts"]) {
|
||||
linyaps_box::config::mount_t mount;
|
||||
if (m.contains("source")) {
|
||||
mount.source = m["source"].get<std::string>();
|
||||
}
|
||||
if (m.contains("destination")) {
|
||||
mount.destination = m["destination"].get<std::string>();
|
||||
}
|
||||
mount.type = m["type"].get<std::string>();
|
||||
|
||||
const auto it = m.find("options");
|
||||
if (it != m.end()) {
|
||||
auto options = it->get<std::vector<std::string>>();
|
||||
std::tie(mount.flags, mount.propagation_flags, mount.extra_flags, mount.data) =
|
||||
parse_mount_options(options);
|
||||
}
|
||||
|
||||
mounts.push_back(mount);
|
||||
}
|
||||
cfg.mounts = mounts;
|
||||
}
|
||||
|
||||
auto root = ptr / "root";
|
||||
if (!j.contains(root)) {
|
||||
throw std::runtime_error("root must be specified");
|
||||
}
|
||||
|
||||
if (!j.contains(root / "path")) {
|
||||
throw std::runtime_error("root.path must be specified");
|
||||
}
|
||||
cfg.root.path = j[root / "path"].get<std::filesystem::path>();
|
||||
|
||||
if (j.contains(root / "readonly")) {
|
||||
cfg.root.readonly = j[root / "readonly"].get<bool>();
|
||||
}
|
||||
|
||||
auto annotations = ptr / "annotations";
|
||||
if (j.contains(annotations)) {
|
||||
cfg.annotations = j[annotations].get<std::unordered_map<std::string, std::string>>();
|
||||
}
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
linyaps_box::config linyaps_box::config::parse(std::istream &is)
|
||||
{
|
||||
auto j = nlohmann::json::parse(is);
|
||||
return parse_1_2_0(j);
|
||||
}
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef LINYAPS_BOX_ENABLE_CAP
|
||||
#include <sys/capability.h>
|
||||
#endif
|
||||
|
||||
// Compatible with linux kernel which is under 5.10
|
||||
#ifndef MS_NOSYMFOLLOW
|
||||
#define LINGYAPS_MS_NOSYMFOLLOW 256
|
||||
#else
|
||||
#define LINGYAPS_MS_NOSYMFOLLOW MS_NOSYMFOLLOW
|
||||
#endif
|
||||
|
||||
namespace linyaps_box {
|
||||
|
||||
struct config
|
||||
{
|
||||
static constexpr auto oci_version = "1.2.0";
|
||||
|
||||
static auto parse(std::istream &is) -> config;
|
||||
|
||||
struct process_t
|
||||
{
|
||||
bool terminal = false;
|
||||
|
||||
struct console_t
|
||||
{
|
||||
uint height = 0;
|
||||
uint width = 0;
|
||||
};
|
||||
|
||||
console_t console;
|
||||
|
||||
std::filesystem::path cwd;
|
||||
std::vector<std::string> env;
|
||||
std::vector<std::string> args;
|
||||
|
||||
struct rlimit_t
|
||||
{
|
||||
// use string for runtime log
|
||||
std::string type;
|
||||
uint64_t soft;
|
||||
uint64_t hard;
|
||||
};
|
||||
|
||||
using rlimits_t = std::vector<rlimit_t>;
|
||||
|
||||
std::optional<rlimits_t> rlimits;
|
||||
std::optional<std::string> apparmor_profile;
|
||||
|
||||
// TODO: not use cap_value_t directly
|
||||
#ifdef LINYAPS_BOX_ENABLE_CAP
|
||||
struct capabilities_t
|
||||
{
|
||||
std::vector<cap_value_t> effective;
|
||||
std::vector<cap_value_t> bounding;
|
||||
std::vector<cap_value_t> inheritable;
|
||||
std::vector<cap_value_t> permitted;
|
||||
std::vector<cap_value_t> ambient;
|
||||
};
|
||||
|
||||
capabilities_t capabilities;
|
||||
#endif
|
||||
|
||||
bool no_new_privileges = false;
|
||||
std::optional<int> oom_score_adj;
|
||||
|
||||
struct user_t
|
||||
{
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
std::optional<mode_t> umask;
|
||||
std::optional<std::vector<gid_t>> additional_gids;
|
||||
};
|
||||
|
||||
user_t user;
|
||||
};
|
||||
|
||||
process_t process;
|
||||
|
||||
struct linux_t
|
||||
{
|
||||
struct id_mapping_t
|
||||
{
|
||||
uid_t host_id;
|
||||
uid_t container_id;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct namespace_t
|
||||
{
|
||||
enum type_t {
|
||||
INVALID = 0,
|
||||
IPC = CLONE_NEWIPC,
|
||||
UTS = CLONE_NEWUTS,
|
||||
MOUNT = CLONE_NEWNS,
|
||||
PID = CLONE_NEWPID,
|
||||
NET = CLONE_NEWNET,
|
||||
USER = CLONE_NEWUSER,
|
||||
CGROUP = CLONE_NEWCGROUP,
|
||||
};
|
||||
|
||||
type_t type{ type_t::INVALID };
|
||||
std::optional<std::filesystem::path> path;
|
||||
};
|
||||
|
||||
std::optional<std::vector<namespace_t>> namespaces;
|
||||
std::optional<std::vector<id_mapping_t>> uid_mappings;
|
||||
std::optional<std::vector<id_mapping_t>> gid_mappings;
|
||||
std::optional<std::vector<std::filesystem::path>> masked_paths;
|
||||
std::optional<std::vector<std::filesystem::path>> readonly_paths;
|
||||
unsigned int rootfs_propagation{ 0 };
|
||||
};
|
||||
|
||||
std::optional<linux_t> linux;
|
||||
|
||||
struct hooks_t
|
||||
{
|
||||
struct hook_t
|
||||
{
|
||||
std::filesystem::path path;
|
||||
std::optional<std::vector<std::string>> args;
|
||||
std::optional<std::unordered_map<std::string, std::string>> env;
|
||||
std::optional<int> timeout;
|
||||
};
|
||||
|
||||
std::optional<std::vector<hook_t>> prestart;
|
||||
std::optional<std::vector<hook_t>> create_runtime;
|
||||
std::optional<std::vector<hook_t>> create_container;
|
||||
std::optional<std::vector<hook_t>> start_container;
|
||||
std::optional<std::vector<hook_t>> poststart;
|
||||
std::optional<std::vector<hook_t>> poststop;
|
||||
};
|
||||
|
||||
hooks_t hooks;
|
||||
|
||||
struct mount_t
|
||||
{
|
||||
enum extension : std::uint8_t { COPY_SYMLINK = 1 };
|
||||
|
||||
std::optional<std::string> source;
|
||||
std::optional<std::filesystem::path> destination;
|
||||
std::string type;
|
||||
std::uint8_t extra_flags{ 0 };
|
||||
unsigned long flags{ 0 };
|
||||
unsigned long propagation_flags{ 0 };
|
||||
std::string data;
|
||||
};
|
||||
|
||||
std::vector<mount_t> mounts;
|
||||
|
||||
struct root_t
|
||||
{
|
||||
std::filesystem::path path;
|
||||
bool readonly{ false };
|
||||
};
|
||||
|
||||
root_t root;
|
||||
|
||||
std::optional<std::unordered_map<std::string, std::string>> annotations;
|
||||
};
|
||||
|
||||
} // namespace linyaps_box
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,59 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "linyaps_box/cgroup_manager.h"
|
||||
#include "linyaps_box/container_ref.h"
|
||||
#include "linyaps_box/status_directory.h"
|
||||
#include "linyaps_box/utils/file_describer.h"
|
||||
|
||||
namespace linyaps_box {
|
||||
|
||||
struct container_data;
|
||||
|
||||
struct create_container_options_t
|
||||
{
|
||||
cgroup_manager_t manager;
|
||||
int preserve_fds;
|
||||
std::string ID;
|
||||
std::filesystem::path bundle;
|
||||
std::filesystem::path config;
|
||||
};
|
||||
|
||||
class container final : public container_ref
|
||||
{
|
||||
public:
|
||||
container(const status_directory &status_dir, const create_container_options_t &options);
|
||||
|
||||
container(const container &) = delete;
|
||||
auto operator=(const container &) -> container & = delete;
|
||||
container(container &&) = delete;
|
||||
auto operator=(container &&) -> container & = delete;
|
||||
|
||||
[[nodiscard]] auto get_config() const -> const linyaps_box::config &;
|
||||
[[nodiscard]] auto get_bundle() const -> const std::filesystem::path &;
|
||||
[[nodiscard]] auto run(const config::process_t &process) const -> int;
|
||||
// TODO:: support fully container capabilities, e.g. create, start, stop, delete...
|
||||
friend auto get_private_data(const container &c) noexcept -> container_data &;
|
||||
~container() noexcept override;
|
||||
|
||||
[[nodiscard]] auto host_gid() const noexcept { return host_gid_; }
|
||||
|
||||
[[nodiscard]] auto host_uid() const noexcept { return host_uid_; }
|
||||
|
||||
[[nodiscard]] auto preserve_fds() const noexcept { return preserve_fds_; }
|
||||
|
||||
private:
|
||||
void cgroup_preenter(const cgroup_options &options, utils::file_descriptor &dirfd);
|
||||
int preserve_fds_;
|
||||
gid_t host_gid_;
|
||||
uid_t host_uid_;
|
||||
container_data *data{ nullptr };
|
||||
std::filesystem::path bundle;
|
||||
std::unique_ptr<cgroup_manager> manager;
|
||||
linyaps_box::config config;
|
||||
};
|
||||
|
||||
} // namespace linyaps_box
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/container_ref.h"
|
||||
|
||||
#include "linyaps_box/utils/log.h"
|
||||
|
||||
#include <csignal> // IWYU pragma: keep
|
||||
#include <utility>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
linyaps_box::container_ref::container_ref(const status_directory &status_dir, std::string id)
|
||||
: id_(std::move(id))
|
||||
, status_dir_(status_dir)
|
||||
{
|
||||
}
|
||||
|
||||
linyaps_box::container_ref::~container_ref() noexcept = default;
|
||||
|
||||
linyaps_box::container_status_t linyaps_box::container_ref::status() const
|
||||
{
|
||||
return this->status_dir_.read(this->id_);
|
||||
}
|
||||
|
||||
void linyaps_box::container_ref::kill(int signal) const
|
||||
{
|
||||
auto pid = this->status().PID;
|
||||
|
||||
LINYAPS_BOX_DEBUG() << "kill process " << pid << " with signal " << signal;
|
||||
if (::kill(pid, signal) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "failed to kill process " << pid << " with signal " << signal;
|
||||
throw std::system_error(errno, std::generic_category(), std::move(ss).str());
|
||||
}
|
||||
|
||||
void linyaps_box::container_ref::exec(const linyaps_box::config::process_t &process)
|
||||
{
|
||||
auto target = std::to_string(this->status().PID);
|
||||
|
||||
std::vector<const char *> argv{
|
||||
"nsenter",
|
||||
"--target",
|
||||
target.c_str(),
|
||||
"--user",
|
||||
"--mount",
|
||||
"--pid",
|
||||
// FIXME:
|
||||
// Old nsenter command do not support --wdns,
|
||||
// so we have to implement nsenter by ourself in the future.
|
||||
"--preserve-credentials",
|
||||
};
|
||||
|
||||
for (const auto &arg : process.args) {
|
||||
argv.push_back(arg.c_str());
|
||||
}
|
||||
argv.push_back(nullptr);
|
||||
|
||||
std::vector<const char *> c_env;
|
||||
c_env.reserve(process.env.size());
|
||||
for (const auto &env : process.env) {
|
||||
c_env.push_back(env.c_str());
|
||||
}
|
||||
c_env.push_back(nullptr);
|
||||
|
||||
LINYAPS_BOX_DEBUG() << [&argv]() -> std::string {
|
||||
auto result = std::accumulate(argv.cbegin(),
|
||||
argv.cend() - 1,
|
||||
std::string{ "args:[" },
|
||||
[](std::string init, const std::string &val) {
|
||||
init += val;
|
||||
init.push_back(' ');
|
||||
return init;
|
||||
});
|
||||
result.push_back(']');
|
||||
result.insert(0, "execvp nsenter with arguments: ");
|
||||
return result;
|
||||
}();
|
||||
|
||||
// FIXME:
|
||||
// We only handle the command arguments for now
|
||||
// here are some other fields in process we need to consider:
|
||||
// terminal
|
||||
// console.height
|
||||
// console.width
|
||||
// cwd
|
||||
// env
|
||||
// rlimits
|
||||
// apparmor_profile
|
||||
// capabilities
|
||||
// no_new_privileges
|
||||
// oom_score_adj
|
||||
|
||||
::execvpe("nsenter", const_cast<char **>(argv.data()), const_cast<char **>(c_env.data()));
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "execvp nsenter with arguments:";
|
||||
for (const auto &arg : argv) {
|
||||
ss << " " << arg;
|
||||
}
|
||||
|
||||
throw std::system_error(errno, std::generic_category(), std::move(ss).str());
|
||||
}
|
||||
|
||||
const linyaps_box::status_directory &linyaps_box::container_ref::status_dir() const
|
||||
{
|
||||
return this->status_dir_;
|
||||
}
|
||||
|
||||
const std::string &linyaps_box::container_ref::get_id() const
|
||||
{
|
||||
return this->id_;
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "linyaps_box/config.h"
|
||||
#include "linyaps_box/container_status.h"
|
||||
#include "linyaps_box/status_directory.h"
|
||||
|
||||
namespace linyaps_box {
|
||||
|
||||
class container_ref
|
||||
{
|
||||
public:
|
||||
container_ref(const status_directory &status_dir, std::string id);
|
||||
virtual ~container_ref() noexcept;
|
||||
|
||||
container_ref(const container_ref &) = delete;
|
||||
auto operator=(const container_ref &) -> container_ref & = delete;
|
||||
container_ref(container_ref &&) = delete;
|
||||
auto operator=(container_ref &&) -> container_ref & = delete;
|
||||
|
||||
[[nodiscard]] auto status() const -> container_status_t;
|
||||
void kill(int signal) const;
|
||||
[[noreturn]] void exec(const config::process_t &process);
|
||||
|
||||
protected:
|
||||
[[nodiscard]] auto status_dir() const -> const status_directory &;
|
||||
[[nodiscard]] auto get_id() const -> const std::string &;
|
||||
|
||||
private:
|
||||
std::string id_;
|
||||
const status_directory &status_dir_;
|
||||
};
|
||||
|
||||
} // namespace linyaps_box
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/container_status.h"
|
||||
|
||||
namespace linyaps_box {
|
||||
auto to_string(linyaps_box::container_status_t::runtime_status status) -> std::string
|
||||
{
|
||||
switch (status) {
|
||||
case linyaps_box::container_status_t::runtime_status::CREATING:
|
||||
return "creating";
|
||||
case linyaps_box::container_status_t::runtime_status::CREATED:
|
||||
return "created";
|
||||
case linyaps_box::container_status_t::runtime_status::RUNNING:
|
||||
return "running";
|
||||
case linyaps_box::container_status_t::runtime_status::STOPPED:
|
||||
return "stopped";
|
||||
default:
|
||||
throw std::logic_error("unknown status");
|
||||
}
|
||||
}
|
||||
|
||||
auto from_string(std::string_view status) -> linyaps_box::container_status_t::runtime_status
|
||||
{
|
||||
if (status == "creating") {
|
||||
return linyaps_box::container_status_t::runtime_status::CREATING;
|
||||
}
|
||||
if (status == "created") {
|
||||
return linyaps_box::container_status_t::runtime_status::CREATED;
|
||||
}
|
||||
if (status == "running") {
|
||||
return linyaps_box::container_status_t::runtime_status::RUNNING;
|
||||
}
|
||||
if (status == "stopped") {
|
||||
return linyaps_box::container_status_t::runtime_status::STOPPED;
|
||||
}
|
||||
|
||||
throw std::logic_error("unknown status");
|
||||
}
|
||||
|
||||
auto status_to_json(const linyaps_box::container_status_t &status) -> nlohmann::json
|
||||
{
|
||||
return nlohmann::json::object({ { "id", status.ID },
|
||||
{ "pid", status.PID },
|
||||
{ "status", to_string(status.status) },
|
||||
{ "bundle", status.bundle.string() },
|
||||
{ "created", status.created },
|
||||
{ "owner", status.owner },
|
||||
{ "annotations", status.annotations },
|
||||
{ "ociVersion", status.oci_version } });
|
||||
}
|
||||
|
||||
} // namespace linyaps_box
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace linyaps_box {
|
||||
|
||||
struct container_status_t
|
||||
{
|
||||
std::string ID;
|
||||
pid_t PID;
|
||||
|
||||
std::string oci_version;
|
||||
enum class runtime_status : std::uint8_t { CREATING, CREATED, RUNNING, STOPPED };
|
||||
runtime_status status;
|
||||
std::filesystem::path bundle;
|
||||
std::string created; // extension field
|
||||
std::string owner; // extension field
|
||||
std::unordered_map<std::string, std::string> annotations;
|
||||
};
|
||||
|
||||
auto to_string(linyaps_box::container_status_t::runtime_status status) -> std::string;
|
||||
auto from_string(std::string_view status) -> linyaps_box::container_status_t::runtime_status;
|
||||
auto status_to_json(const linyaps_box::container_status_t &status) -> nlohmann::json;
|
||||
|
||||
} // namespace linyaps_box
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/impl/disabled_cgroup_manager.h"
|
||||
|
||||
namespace linyaps_box {
|
||||
[[nodiscard]] auto disabled_cgroup_manager::type() const -> cgroup_manager_t
|
||||
{
|
||||
return cgroup_manager_t::disabled;
|
||||
}
|
||||
|
||||
auto disabled_cgroup_manager::create_cgroup([[maybe_unused]] const cgroup_options &options)
|
||||
-> cgroup_status
|
||||
{
|
||||
cgroup_status status{};
|
||||
set_manager(status, type());
|
||||
return status;
|
||||
}
|
||||
|
||||
void disabled_cgroup_manager::precreate_cgroup([[maybe_unused]] const cgroup_options &options,
|
||||
[[maybe_unused]] utils::file_descriptor &dirfd)
|
||||
{
|
||||
}
|
||||
|
||||
void disabled_cgroup_manager::destroy_cgroup([[maybe_unused]] const cgroup_status &status) { }
|
||||
} // namespace linyaps_box
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <linyaps_box/cgroup_manager.h>
|
||||
|
||||
namespace linyaps_box {
|
||||
|
||||
class disabled_cgroup_manager : public virtual cgroup_manager
|
||||
{
|
||||
public:
|
||||
[[nodiscard]] auto type() const -> cgroup_manager_t override;
|
||||
|
||||
auto create_cgroup([[maybe_unused]] const cgroup_options &options) -> cgroup_status override;
|
||||
|
||||
void precreate_cgroup([[maybe_unused]] const cgroup_options &options,
|
||||
[[maybe_unused]] utils::file_descriptor &dirfd) override;
|
||||
|
||||
void destroy_cgroup([[maybe_unused]] const cgroup_status &status) override;
|
||||
};
|
||||
|
||||
} // namespace linyaps_box
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/impl/json_printer.h"
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void linyaps_box::impl::json_printer::print_statuses(const std::vector<container_status_t> &status)
|
||||
{
|
||||
auto j = nlohmann::json::array();
|
||||
for (const auto &s : status) {
|
||||
j += status_to_json(s);
|
||||
}
|
||||
|
||||
std::cout << j.dump(4) << std::endl;
|
||||
}
|
||||
|
||||
void linyaps_box::impl::json_printer::print_status(const container_status_t &status)
|
||||
{
|
||||
auto j = status_to_json(status);
|
||||
std::cout << j.dump(4) << std::endl;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "linyaps_box/container_status.h"
|
||||
#include "linyaps_box/printer.h"
|
||||
|
||||
namespace linyaps_box::impl {
|
||||
|
||||
class json_printer final : public virtual linyaps_box::printer
|
||||
{
|
||||
public:
|
||||
void print_status(const container_status_t &status) final;
|
||||
void print_statuses(const std::vector<container_status_t> &status) final;
|
||||
};
|
||||
|
||||
static_assert(!std::is_abstract_v<json_printer>);
|
||||
|
||||
} // namespace linyaps_box::impl
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/impl/status_directory.h"
|
||||
|
||||
#include "linyaps_box/container_status.h"
|
||||
#include "linyaps_box/utils/atomic_write.h"
|
||||
#include "linyaps_box/utils/log.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
#include <csignal> // IWYU pragma: keep
|
||||
#include <fstream>
|
||||
#include <utility>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
namespace {
|
||||
|
||||
auto read_status(const std::filesystem::path &path) -> linyaps_box::container_status_t
|
||||
{
|
||||
nlohmann::json j;
|
||||
{
|
||||
std::ifstream istrm(path);
|
||||
if (istrm.fail()) {
|
||||
throw std::runtime_error("failed to open status file:" + path.string());
|
||||
}
|
||||
|
||||
istrm >> j;
|
||||
}
|
||||
linyaps_box::container_status_t ret{};
|
||||
|
||||
ret.oci_version = j["ociVersion"];
|
||||
ret.PID = j["pid"];
|
||||
ret.ID = j["id"];
|
||||
ret.status = linyaps_box::from_string(j["status"].get<std::string>());
|
||||
if (::kill(ret.PID, 0) != 0) {
|
||||
ret.status = linyaps_box::container_status_t::runtime_status::STOPPED;
|
||||
}
|
||||
ret.bundle = std::string(j["bundle"]);
|
||||
ret.created = j["created"];
|
||||
ret.owner = j["owner"];
|
||||
ret.annotations = j["annotations"];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void linyaps_box::impl::status_directory::write(const container_status_t &status) const
|
||||
{
|
||||
nlohmann::json j = nlohmann::json::object({ { "id", status.ID },
|
||||
{ "pid", status.PID },
|
||||
{ "status", to_string(status.status) },
|
||||
{ "bundle", status.bundle },
|
||||
{ "created", status.created },
|
||||
{ "owner", status.owner },
|
||||
{ "annotations", status.annotations },
|
||||
{ "ociVersion", status.oci_version } });
|
||||
|
||||
utils::atomic_write(this->path / (status.ID + ".json"), j.dump());
|
||||
}
|
||||
|
||||
auto linyaps_box::impl::status_directory::read(const std::string &id) const
|
||||
-> linyaps_box::container_status_t
|
||||
{
|
||||
return read_status(this->path / (id + ".json"));
|
||||
}
|
||||
|
||||
void linyaps_box::impl::status_directory::remove(const std::string &id) const
|
||||
{
|
||||
auto file_path = this->path / (id + ".json");
|
||||
LINYAPS_BOX_DEBUG() << "Remove " << file_path;
|
||||
if (!std::filesystem::remove(file_path)) {
|
||||
LINYAPS_BOX_WARNING() << "Failed to remove " << file_path;
|
||||
}
|
||||
}
|
||||
|
||||
auto linyaps_box::impl::status_directory::list() const -> std::vector<std::string>
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
for (const auto &entry : std::filesystem::directory_iterator(this->path)) {
|
||||
try {
|
||||
if (entry.is_regular_file() && entry.path().extension() != ".json") {
|
||||
throw std::runtime_error("invalid extension");
|
||||
}
|
||||
auto status = read_status(entry);
|
||||
ret.push_back(status.ID);
|
||||
} catch (const std::exception &e) {
|
||||
LINYAPS_BOX_WARNING() << "Skip " << entry.path() << ": " << e.what();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
linyaps_box::impl::status_directory::status_directory(std::filesystem::path dir)
|
||||
: path(std::move(dir))
|
||||
{
|
||||
if (std::filesystem::is_directory(path) || std::filesystem::create_directories(path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw std::runtime_error("failed to create status directory");
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "linyaps_box/status_directory.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
namespace linyaps_box::impl {
|
||||
class status_directory : public virtual linyaps_box::status_directory
|
||||
{
|
||||
public:
|
||||
void write(const container_status_t &status) const override;
|
||||
[[nodiscard]] auto read(const std::string &id) const -> container_status_t override;
|
||||
void remove(const std::string &id) const override;
|
||||
[[nodiscard]] auto list() const -> std::vector<std::string> override;
|
||||
|
||||
explicit status_directory(std::filesystem::path dir);
|
||||
|
||||
private:
|
||||
std::filesystem::path path;
|
||||
};
|
||||
|
||||
static_assert(!std::is_abstract_v<status_directory>);
|
||||
|
||||
} // namespace linyaps_box::impl
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/impl/table_printer.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace {
|
||||
auto get_status_string(const linyaps_box::container_status_t::runtime_status &status) -> std::string
|
||||
{
|
||||
switch (status) {
|
||||
case linyaps_box::container_status_t::runtime_status::CREATING:
|
||||
return "creating";
|
||||
case linyaps_box::container_status_t::runtime_status::CREATED:
|
||||
return "created";
|
||||
case linyaps_box::container_status_t::runtime_status::RUNNING:
|
||||
return "running";
|
||||
case linyaps_box::container_status_t::runtime_status::STOPPED:
|
||||
return "stopped";
|
||||
default:
|
||||
throw std::logic_error("unknown status");
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void linyaps_box::impl::table_printer::print_statuses(const std::vector<container_status_t> &status)
|
||||
{
|
||||
int max_length = 4;
|
||||
for (const auto &s : status) {
|
||||
max_length = std::max(max_length, static_cast<int>(s.ID.length()));
|
||||
}
|
||||
|
||||
std::cout << std::left << std::setw(max_length + 1) << "NAME" << std::setw(10) << "PID"
|
||||
<< std::setw(9) << "STATUS" << std::setw(40) << "BUNDLE PATH" << std::setw(31)
|
||||
<< "CREATED" << std::setw(0) << "OWNER" << '\n';
|
||||
for (const auto &s : status) {
|
||||
std::cout << std::left << std::setw(max_length) << s.ID << std::setw(10) << s.PID
|
||||
<< std::setw(9) << get_status_string(s.status) << std::setw(40) << s.bundle
|
||||
<< std::setw(31) << s.created << std::setw(0) << s.owner << '\n';
|
||||
}
|
||||
|
||||
std::cout.flush();
|
||||
}
|
||||
|
||||
void linyaps_box::impl::table_printer::print_status(const container_status_t &status)
|
||||
{
|
||||
std::cout << "ociVersion\t" << status.oci_version << '\n';
|
||||
std::cout << "ID\t" << status.ID << '\n';
|
||||
std::cout << "PID\t" << status.PID << '\n';
|
||||
std::cout << "status\t" << get_status_string(status.status) << '\n';
|
||||
std::cout << "bundle\t" << status.bundle << '\n';
|
||||
std::cout << "created\t" << status.created << '\n';
|
||||
std::cout << "owner\t" << status.owner << '\n';
|
||||
std::cout << "annotations" << '\n';
|
||||
for (const auto &a : status.annotations) {
|
||||
std::cout << "\t" << a.first << "\t" << a.second << '\n';
|
||||
}
|
||||
|
||||
std::cout.flush();
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "linyaps_box/printer.h"
|
||||
|
||||
namespace linyaps_box::impl {
|
||||
|
||||
class table_printer final : public virtual linyaps_box::printer
|
||||
{
|
||||
public:
|
||||
void print_status(const container_status_t &status) final;
|
||||
void print_statuses(const std::vector<container_status_t> &status) final;
|
||||
};
|
||||
|
||||
static_assert(!std::is_abstract_v<table_printer>);
|
||||
|
||||
} // namespace linyaps_box::impl
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/interface.h"
|
||||
|
||||
namespace linyaps_box {
|
||||
|
||||
// ensure vtable only here
|
||||
interface::~interface() = default;
|
||||
|
||||
} // namespace linyaps_box
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace linyaps_box {
|
||||
|
||||
// prevent object slicing
|
||||
class interface
|
||||
{
|
||||
public:
|
||||
interface() = default;
|
||||
virtual ~interface();
|
||||
interface(const interface &) = delete;
|
||||
auto operator=(const interface &) -> interface & = delete;
|
||||
interface(interface &&) = delete;
|
||||
auto operator=(interface &&) -> interface & = delete;
|
||||
};
|
||||
} // namespace linyaps_box
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/printer.h"
|
||||
|
||||
namespace linyaps_box {
|
||||
|
||||
printer::~printer() = default;
|
||||
|
||||
} // namespace linyaps_box
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "linyaps_box/container_status.h"
|
||||
#include "linyaps_box/interface.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace linyaps_box {
|
||||
class printer : public virtual interface
|
||||
{
|
||||
protected:
|
||||
printer() = default;
|
||||
|
||||
public:
|
||||
~printer() override;
|
||||
|
||||
printer(const printer &) = delete;
|
||||
auto operator=(const printer &) -> printer & = delete;
|
||||
printer(printer &&) = delete;
|
||||
auto operator=(printer &&) -> printer & = delete;
|
||||
|
||||
virtual void print_status(const container_status_t &status) = 0;
|
||||
virtual void print_statuses(const std::vector<container_status_t> &status) = 0;
|
||||
};
|
||||
} // namespace linyaps_box
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/runtime.h"
|
||||
|
||||
linyaps_box::runtime_t::runtime_t(std::unique_ptr<linyaps_box::status_directory> &&status_dir)
|
||||
: status_dir_{ std::move(status_dir) }
|
||||
{
|
||||
if (!this->status_dir_) {
|
||||
throw std::invalid_argument("status_dir is nullptr");
|
||||
}
|
||||
}
|
||||
|
||||
auto linyaps_box::runtime_t::containers()
|
||||
-> std::unordered_map<std::string, linyaps_box::container_ref>
|
||||
{
|
||||
auto container_ids = this->status_dir_->list();
|
||||
|
||||
std::unordered_map<std::string, container_ref> containers;
|
||||
for (const auto &container_id : container_ids) {
|
||||
containers.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(container_id),
|
||||
std::forward_as_tuple(*this->status_dir_, container_id));
|
||||
}
|
||||
|
||||
return containers;
|
||||
}
|
||||
|
||||
auto linyaps_box::runtime_t::create_container(const create_container_options_t &options)
|
||||
-> linyaps_box::container
|
||||
{
|
||||
return { *this->status_dir_, options };
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "linyaps_box/container.h"
|
||||
#include "linyaps_box/container_ref.h"
|
||||
#include "linyaps_box/status_directory.h"
|
||||
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace linyaps_box {
|
||||
|
||||
class runtime_t
|
||||
{
|
||||
public:
|
||||
explicit runtime_t(std::unique_ptr<status_directory> &&status_dir);
|
||||
auto containers() -> std::unordered_map<std::string, container_ref>;
|
||||
|
||||
auto create_container(const create_container_options_t &options) -> container;
|
||||
|
||||
private:
|
||||
std::unique_ptr<status_directory> status_dir_;
|
||||
};
|
||||
|
||||
} // namespace linyaps_box
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/status_directory.h"
|
||||
|
||||
namespace linyaps_box {
|
||||
status_directory::~status_directory() = default;
|
||||
} // namespace linyaps_box
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "linyaps_box/container_status.h"
|
||||
#include "linyaps_box/interface.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace linyaps_box {
|
||||
class status_directory : public virtual interface
|
||||
{
|
||||
protected:
|
||||
status_directory() = default;
|
||||
|
||||
public:
|
||||
~status_directory() override;
|
||||
|
||||
status_directory(const status_directory &) = delete;
|
||||
auto operator=(const status_directory &) -> status_directory & = delete;
|
||||
status_directory(status_directory &&) = delete;
|
||||
auto operator=(status_directory &&) -> status_directory & = delete;
|
||||
|
||||
virtual void write(const container_status_t &status) const = 0;
|
||||
[[nodiscard]] virtual auto read(const std::string &id) const -> container_status_t = 0;
|
||||
virtual void remove(const std::string &id) const = 0;
|
||||
[[nodiscard]] virtual auto list() const -> std::vector<std::string> = 0;
|
||||
};
|
||||
} // namespace linyaps_box
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/utils/atomic_write.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
void linyaps_box::utils::atomic_write(const std::filesystem::path &path, const std::string &content)
|
||||
{
|
||||
std::filesystem::path temp_path = path;
|
||||
temp_path += ".tmp";
|
||||
std::ofstream temp_file(temp_path);
|
||||
if (!temp_file.is_open()) {
|
||||
throw std::runtime_error("failed to open temporary file");
|
||||
}
|
||||
temp_file << content;
|
||||
temp_file.close();
|
||||
|
||||
std::filesystem::rename(temp_path, path);
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// SPDX-FileCopyrightText: 2022-2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace linyaps_box::utils {
|
||||
|
||||
void atomic_write(const std::filesystem::path &path, const std::string &content);
|
||||
|
||||
} // namespace linyaps_box::utils
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include <linux/magic.h>
|
||||
#include <linyaps_box/utils/cgroups.h>
|
||||
#include <sys/statfs.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <system_error>
|
||||
|
||||
constexpr auto cgroup_root = "/sys/fs/cgroups";
|
||||
|
||||
auto linyaps_box::utils::get_cgroup_type() -> linyaps_box::utils::cgroup_t
|
||||
{
|
||||
static auto cgroup_type = []() -> cgroup_t {
|
||||
struct statfs stat{};
|
||||
auto ret = statfs(cgroup_root, &stat);
|
||||
if (ret < 0) {
|
||||
throw std::system_error(errno,
|
||||
std::system_category(),
|
||||
std::string{ "statfs " } + cgroup_root);
|
||||
}
|
||||
|
||||
// for cgroup v2, filesystem type is cgroups2
|
||||
if (stat.f_type == CGROUP2_SUPER_MAGIC) {
|
||||
return cgroup_t::unified;
|
||||
}
|
||||
|
||||
// for cgroup v1, filesystem type is tmpfs
|
||||
if (stat.f_type != TMPFS_MAGIC) {
|
||||
throw std::system_error(-1,
|
||||
std::system_category(),
|
||||
std::string{ "invalid file system type on " } + cgroup_root);
|
||||
}
|
||||
|
||||
// https://man7.org/linux/man-pages/man7/cgroups.7.html
|
||||
auto unified = std::filesystem::path{ cgroup_root } / "unified";
|
||||
ret = statfs(unified.c_str(), &stat);
|
||||
if (ret < 0) {
|
||||
if (errno != ENOENT) {
|
||||
throw std::system_error(errno,
|
||||
std::system_category(),
|
||||
"statfs " + unified.string());
|
||||
}
|
||||
|
||||
return cgroup_t::legacy;
|
||||
}
|
||||
|
||||
return stat.f_type == CGROUP2_SUPER_MAGIC ? cgroup_t::hybrid : cgroup_t::legacy;
|
||||
}();
|
||||
|
||||
return cgroup_type;
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace linyaps_box::utils {
|
||||
|
||||
enum class cgroup_t : std::uint8_t { unified, legacy, hybrid };
|
||||
|
||||
auto get_cgroup_type() -> cgroup_t;
|
||||
|
||||
} // namespace linyaps_box::utils
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "linyaps_box/utils/close_range.h"
|
||||
|
||||
#include "linyaps_box/utils/defer.h"
|
||||
#include "linyaps_box/utils/log.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <system_error>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
namespace {
|
||||
void syscall_close_range(uint fd, uint max_fd, int flags)
|
||||
{
|
||||
auto ret = syscall(__NR_close_range, fd, max_fd, flags);
|
||||
if (ret < 0) {
|
||||
throw std::system_error(errno, std::generic_category(), "close_range");
|
||||
}
|
||||
}
|
||||
|
||||
void close_range_fallback(uint first, uint last, int flags)
|
||||
{
|
||||
if ((static_cast<uint>(flags) & CLOSE_RANGE_UNSHARE) != 0) {
|
||||
// not support CLOSE_RANGE_UNSHARE
|
||||
// it request to create a new file descriptor table
|
||||
// we can't do that in user space
|
||||
throw std::runtime_error("the fallback implementation of close_range dose not support flag "
|
||||
"'CLOSE_RANGE_UNSHARE'");
|
||||
}
|
||||
|
||||
auto *dir = opendir("/proc/self/fd");
|
||||
if (dir == nullptr) {
|
||||
throw std::system_error(errno, std::generic_category(), "opendir /proc/self/fd");
|
||||
}
|
||||
|
||||
auto close_dir = make_defer([dir]() noexcept {
|
||||
if (closedir(dir) < 0) {
|
||||
LINYAPS_BOX_WARNING() << "closedir /proc/self/fd failed: " << strerror(errno)
|
||||
<< ", but this may not be a problem";
|
||||
}
|
||||
});
|
||||
|
||||
// except self fd
|
||||
// use opendir instead of std::filesystem::directory_iterator
|
||||
// because we should skip the file descriptor which is opened by opendir
|
||||
auto self_fd = dirfd(dir);
|
||||
if (self_fd < 0) {
|
||||
throw std::system_error(errno, std::generic_category(), "dirfd");
|
||||
}
|
||||
|
||||
struct dirent *next{ nullptr };
|
||||
while ((next = ::readdir(dir)) != nullptr) {
|
||||
const std::string name{ next->d_name[0] };
|
||||
if (name == "." || name == "..") { // skip "." and ".."
|
||||
continue;
|
||||
}
|
||||
|
||||
auto fd = std::stoi(name);
|
||||
if (fd == self_fd) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (static_cast<uint>(fd) < first || static_cast<uint>(fd) > last) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((static_cast<uint>(flags) & CLOSE_RANGE_CLOEXEC) != 0) {
|
||||
if (::fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) {
|
||||
throw std::system_error(errno,
|
||||
std::generic_category(),
|
||||
"failed to set up close-on-exec to " + name);
|
||||
}
|
||||
} else {
|
||||
if (::close(fd) < 0) {
|
||||
throw std::system_error(errno, std::generic_category(), "failed to close " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void linyaps_box::utils::close_range(uint first, uint last, int flags)
|
||||
{
|
||||
LINYAPS_BOX_DEBUG() << "close_range (" << first << ", " << last << ")" << "with flags "
|
||||
<< [flags]() -> std::string {
|
||||
std::stringstream ss;
|
||||
ss << '[';
|
||||
if ((static_cast<uint>(flags) & CLOSE_RANGE_CLOEXEC) != 0) {
|
||||
ss << "CLOSE_RANGE_CLOEXEC ";
|
||||
}
|
||||
if ((static_cast<uint>(flags) & CLOSE_RANGE_UNSHARE) != 0) {
|
||||
ss << "CLOSE_RANGE_UNSHARE ";
|
||||
}
|
||||
ss << ']';
|
||||
return ss.str();
|
||||
}();
|
||||
|
||||
static bool support_close_range{ true };
|
||||
if (!support_close_range) {
|
||||
close_range_fallback(first, last, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
syscall_close_range(first, last, flags);
|
||||
} catch (const std::system_error &e) {
|
||||
auto code = e.code().value();
|
||||
if (code != ENOSYS) {
|
||||
throw;
|
||||
}
|
||||
|
||||
support_close_range = false;
|
||||
close_range_fallback(first, last, flags);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
// NOTE:
|
||||
// close_range is support since Linux 5.9, glibc 2.34
|
||||
// but we need to support older kernels and glibc
|
||||
// so we need to implement it ourselves
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// from linux/close_range.h
|
||||
#ifndef CLOSE_RANGE_UNSHARE
|
||||
#define CLOSE_RANGE_UNSHARE (1U << 1)
|
||||
#endif
|
||||
|
||||
#ifndef CLOSE_RANGE_CLOEXEC
|
||||
#define CLOSE_RANGE_CLOEXEC (1U << 2) // after linux 5.11
|
||||
#endif
|
||||
|
||||
// use __NR_* instead of SYS_*
|
||||
// https://man7.org/linux/man-pages/man2/syscalls.2.html
|
||||
#ifndef __NR_close_range
|
||||
#define __NR_close_range 436
|
||||
#endif
|
||||
|
||||
namespace linyaps_box::utils {
|
||||
|
||||
void close_range(uint first, uint last, int flags);
|
||||
|
||||
} // namespace linyaps_box::utils
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
// SPDX-FileCopyrightText: 2025 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
// Type constraints for defer, the cleanup function should not throw exceptions
|
||||
template<typename Fn>
|
||||
constexpr bool compatible_defer = std::is_nothrow_invocable_r_v<void, Fn>;
|
||||
|
||||
// Execution policies for defer
|
||||
enum class defer_policy : std::uint8_t {
|
||||
always, // Always execute the cleanup function
|
||||
on_error // Execute the cleanup function only when an exception is active
|
||||
};
|
||||
|
||||
// defer executes the function based on the specified policy when the object is destroyed
|
||||
template<typename Fn,
|
||||
defer_policy Policy = defer_policy::always,
|
||||
std::enable_if_t<compatible_defer<Fn>, bool> = true>
|
||||
struct defer
|
||||
{
|
||||
explicit defer(Fn &&fn) noexcept
|
||||
: fn_(std::move(fn))
|
||||
{
|
||||
}
|
||||
|
||||
defer(const defer &) = delete;
|
||||
auto operator=(const defer &) -> defer & = delete;
|
||||
|
||||
defer(defer &&other) noexcept
|
||||
: fn_(std::move(other.fn_))
|
||||
, cancelled(other.cancelled)
|
||||
{
|
||||
other.cancelled = true;
|
||||
}
|
||||
|
||||
defer &operator=(defer &&other) noexcept
|
||||
{
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
if (!cancelled) {
|
||||
execute();
|
||||
}
|
||||
|
||||
fn_ = std::move(other.fn_);
|
||||
cancelled = other.cancelled;
|
||||
other.cancelled = true;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~defer() noexcept
|
||||
{
|
||||
if (!cancelled) {
|
||||
execute();
|
||||
}
|
||||
}
|
||||
|
||||
void cancel() noexcept { cancelled = true; }
|
||||
|
||||
[[nodiscard]] auto is_cancelled() const noexcept -> bool { return cancelled; }
|
||||
|
||||
private:
|
||||
void execute() noexcept
|
||||
{
|
||||
if constexpr (Policy == defer_policy::always) {
|
||||
fn_();
|
||||
} else if constexpr (Policy == defer_policy::on_error) {
|
||||
if (std::uncaught_exceptions() > 0) {
|
||||
fn_();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Fn fn_;
|
||||
bool cancelled{ false };
|
||||
};
|
||||
|
||||
// Helper functions to create defer objects
|
||||
template<typename Fn>
|
||||
auto make_defer(Fn &&fn) noexcept
|
||||
{
|
||||
return defer<std::decay_t<Fn>>(std::forward<Fn>(fn));
|
||||
}
|
||||
|
||||
// This project use exception to indicate the failure of a function, so we provide a way to create
|
||||
// a defer object that executes the cleanup function only when an exception is active during
|
||||
// destruction
|
||||
template<typename Fn>
|
||||
auto make_errdefer(Fn &&fn) noexcept
|
||||
{
|
||||
return defer<std::decay_t<Fn>, defer_policy::on_error>(std::forward<Fn>(fn));
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue