Alpine Linux 包管理工具 apk 中的彩蛋
经常用Docker
的朋友都不陌生Alpine Linux
这个发行版。ARM64
下的Alpine Linux v3.17
镜像,体积只有惊人的7.46MB
。 Alpine Linux
提供了apk
命令用于管理软件包。此apk(Alpine Package Keeper)
非彼apk(Android Package)
,是Alpine Linux
自带的包管理工具。
在终端中输入apk
:
bash
$ apk
apk-tools 2.12.10, compiled for aarch64.
usage: apk [<OPTIONS>...] COMMAND [<ARGUMENTS>...]
Package installation and removal:
add Add packages to WORLD and commit changes
del Remove packages from WORLD and commit changes
System maintenance:
fix Fix, reinstall or upgrade packages without modifying WORLD
update Update repository indexes
upgrade Install upgrades available from repositories
cache Manage the local package cache
Querying package information:
info Give detailed information about packages or repositories
list List packages matching a pattern or other criteria
dot Render dependencies as graphviz graphs
policy Show repository policy for packages
search Search for packages by name or description
Repository maintenance:
index Create repository index file from packages
fetch Download packages from global repositories to a local directory
manifest Show checksums of package contents
verify Verify package integrity and signature
Miscellaneous:
audit Audit system for changes
stats Show statistics about repositories and installations
version Compare package versions or perform tests on version strings
This apk has coffee making abilities.
For more information: man 8 apk
倒数第二行有句话:This apk has coffee making abilities.(本 apk 有泡咖啡的能力。)
熟悉Debian
的朋友可能知道,apt
包管理工具也有这样一行字:This APT has Super Cow Powers.(本 APT 具有超级牛力)
。输入apt moo
即可触发这一彩蛋:
bash
$ apt moo
(__)
(oo)
/------\/
/ | ||
* /\---/\
~~ ~~
..."Have you mooed today?"...
但是在Alpine Linux
中,apk coffee
并不会为我们端上一杯咖啡:
bash
ERROR: 'coffee' is not an apk command. See 'apk --help'.
所以这个彩蛋的正确触发方式是什么呢?
查看apk
工具的源码src/app_fetch.c
,可以看见有一个神秘的函数:
c
static int cup(void)
{
/* compressed/uncompressed size is 259/1213 */
static unsigned char z[] = {
0x78,0x9c,0x9d,0x94,0x3d,0x8e,0xc4,0x20,0x0c,0x85,0xfb,0x9c,
0xc2,0x72,0x43,0x46,0x8a,0x4d,0x3f,0x67,0x89,0x64,0x77,0x2b,
0x6d,0xbb,0x6d,0x0e,0x3f,0xc6,0x84,0x4d,0x08,0x84,0x55,0xd6,
0xa2,0xe0,0xef,0x7b,0x36,0xe1,0x11,0x80,0x6e,0xcc,0x53,0x7f,
0x3e,0xc5,0xeb,0xcf,0x1d,0x20,0x22,0xcc,0x3c,0x53,0x8e,0x17,
0xd9,0x80,0x6d,0xee,0x0e,0x61,0x42,0x3c,0x8b,0xcf,0xc7,0x12,
0x22,0x71,0x8b,0x31,0x05,0xd5,0xb0,0x11,0x4b,0xa7,0x32,0x2f,
0x80,0x69,0x6b,0xb0,0x98,0x40,0xe2,0xcd,0xba,0x6a,0xba,0xe4,
0x65,0xed,0x61,0x23,0x44,0xb5,0x95,0x06,0x8b,0xde,0x6c,0x61,
0x70,0xde,0x0e,0xb6,0xed,0xc4,0x43,0x0c,0x56,0x6f,0x8f,0x31,
0xd0,0x35,0xb5,0xc7,0x58,0x06,0xff,0x81,0x49,0x84,0xb8,0x0e,
0xb1,0xd8,0xc1,0x66,0x31,0x0e,0x46,0x5c,0x43,0xc9,0xef,0xe5,
0xdc,0x63,0xb1,0xdc,0x67,0x6d,0x31,0xb3,0xc9,0x69,0x74,0x87,
0xc7,0xa3,0x1b,0x6a,0xb3,0xbd,0x2f,0x3b,0xd5,0x0c,0x57,0x3b,
0xce,0x7c,0x5e,0xe5,0x48,0xd0,0x48,0x01,0x92,0x49,0x8b,0xf7,
0xfc,0x58,0x67,0xb3,0xf7,0x14,0x20,0x5c,0x4c,0x9e,0xcc,0xeb,
0x78,0x7e,0x64,0xa6,0xa1,0xf5,0xb2,0x70,0x38,0x09,0x7c,0x7f,
0xfd,0xc0,0x8a,0x4e,0xc8,0x55,0xe8,0x12,0xe2,0x9f,0x1a,0xb1,
0xb9,0x82,0x52,0x02,0x7a,0xe5,0xf9,0xd9,0x88,0x47,0x79,0x3b,
0x46,0x61,0x27,0xf9,0x51,0xb1,0x17,0xb0,0x2c,0x0e,0xd5,0x39,
0x2d,0x96,0x25,0x27,0xd6,0xd1,0x3f,0xa5,0x08,0xe1,0x9e,0x4e,
0xa7,0xe9,0x03,0xb1,0x0a,0xb6,0x75
};
unsigned char buf[1213];
unsigned long len = sizeof(buf);
uncompress(buf, &len, z, sizeof(z));
return write(STDOUT_FILENO, buf, len) != len;
}
根据笔者丰富的开(瞎)发(猜)经验,这一大串十六进制值一定是某种图像。结合函数名为cup
,总不能是罩杯吧这肯定是个杯子,没跑了。
再往下面看,感觉很快就能喝到咖啡了:
c
static int fetch_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *args)
{
struct apk_out *out = &ac->out;
struct apk_database *db = ac->db;
struct fetch_ctx *ctx = (struct fetch_ctx *) pctx;
struct apk_dependency *dep;
ctx->db = db;
ctx->prog = db->ctx->progress;
if (ctx->flags & FETCH_STDOUT) {
db->ctx->progress.out = 0;
db->ctx->out.verbosity = 0;
}
if (ctx->outdir_fd == 0)
ctx->outdir_fd = AT_FDCWD;
if ((args->num == 1) && (strcmp(args->item[0], "coffee") == 0)) {
if (db->ctx->force) return cup();
apk_msg(out, "Go and fetch your own coffee.");
return 0;
}
if (ctx->flags & FETCH_RECURSIVE) {
apk_dependency_array_init(&ctx->world);
foreach_array_item(dep, db->world)
mark_dep_flags(ctx, dep);
if (args->num)
apk_db_foreach_matching_name(db, args, mark_name_flags, ctx);
if (ctx->errors == 0)
mark_names_recursive(db, args, ctx);
apk_dependency_array_free(&ctx->world);
} else {
if (args->num)
apk_db_foreach_matching_name(db, args, mark_name, ctx);
}
if (!ctx->errors)
apk_db_foreach_sorted_package(db, NULL, fetch_package, ctx);
/* Remove packages not matching download spec from the output directory */
if (!ctx->errors && (db->ctx->flags & APK_PURGE) &&
!(ctx->flags & FETCH_STDOUT) && ctx->outdir_fd > 0)
apk_dir_foreach_file(ctx->outdir_fd, purge_package, ctx);
return ctx->errors;
}
执行apk fetch coffee
:
bash
$ apk fetch coffee
Go and fetch your own coffee.
什么,居然要自己泡咖啡,那要你干啥捏,加个-f
参数强制泡上一杯:
bash
$ apk fetch -f coffee
(
) (
___...(-------)-....___
.-"" ) ( ""-.
.-'``'|-._ ) _.-|
/ .--.| `""---...........---""` |
/ / | |
| | | |
\ \ | |
`\ `\ | |
`\ `| |
_/ /\ /
(__/ \ /
_..---""` \ /`""---.._
.-' \ / '-.
: `-.__ __.-' :
: ) ""---...---"" ( :
'._ `"--...___...--"` _.'
jgs \""--..__ __..--""/
'._ """----.....______.....----""" _.'
`""--..,,_____ _____,,..--""`
`"""----"""`
OK,现在可以享受一杯基于musl libc
的 coffee 了。