Initial commit for Android 11, syncing up to v300.f
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
From ddbe45ddd09f30beab8980d14c506f48ca1f8399 Mon Sep 17 00:00:00 2001
|
||||
From: Pierre-Hugues Husson <phh@phh.me>
|
||||
Date: Fri, 2 Mar 2018 22:49:55 +0100
|
||||
Subject: [PATCH 01/10] Enable multipl_decls by default. This is needed because
|
||||
8.0 init doesn't add -m
|
||||
|
||||
Change-Id: I43dc661d519f7b8576d72a828d8cbd444592bf5e
|
||||
---
|
||||
secilc/secilc.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/secilc/secilc.c b/secilc/secilc.c
|
||||
index 186c5a73..b422175e 100644
|
||||
--- a/secilc/secilc.c
|
||||
+++ b/secilc/secilc.c
|
||||
@@ -91,7 +91,7 @@ int main(int argc, char *argv[])
|
||||
int target = SEPOL_TARGET_SELINUX;
|
||||
int mls = -1;
|
||||
int disable_dontaudit = 0;
|
||||
- int multiple_decls = 0;
|
||||
+ int multiple_decls = 1;
|
||||
int disable_neverallow = 0;
|
||||
int preserve_tunables = 0;
|
||||
int handle_unknown = -1;
|
||||
--
|
||||
2.17.1
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
From ff296de7912209e6fa20e1b28db93c395cc0bb75 Mon Sep 17 00:00:00 2001
|
||||
From: Pierre-Hugues Husson <phh@phh.me>
|
||||
Date: Mon, 9 Apr 2018 00:19:49 +0200
|
||||
Subject: [PATCH 02/10] Increase default log_level to get actual selinux error
|
||||
in kmsg
|
||||
|
||||
---
|
||||
secilc/secilc.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/secilc/secilc.c b/secilc/secilc.c
|
||||
index b422175e..1e550ab4 100644
|
||||
--- a/secilc/secilc.c
|
||||
+++ b/secilc/secilc.c
|
||||
@@ -103,7 +103,7 @@ int main(int argc, char *argv[])
|
||||
int opt_index = 0;
|
||||
char *fc_buf = NULL;
|
||||
size_t fc_size;
|
||||
- enum cil_log_level log_level = CIL_ERR;
|
||||
+ enum cil_log_level log_level = CIL_WARN;
|
||||
static struct option long_opts[] = {
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
--
|
||||
2.17.1
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
From ecb4746fb8ba4e97cc53e6290dfa7a75495d19a8 Mon Sep 17 00:00:00 2001
|
||||
From: Pierre-Hugues Husson <phh@phh.me>
|
||||
Date: Mon, 3 Dec 2018 20:54:54 +0100
|
||||
Subject: [PATCH 03/10] ::Kirin:: Workaround some conflicting Kirin tether
|
||||
SELinux context
|
||||
|
||||
Some Kirin devices declared some android.hardware.tetheroffload HALs,
|
||||
but they didn't use AOSP contexts.
|
||||
This leads to libselinux aborting when loading hwservice_contexts.
|
||||
|
||||
Workaround it the ugly way, by making them match.
|
||||
This most likely kills tetheroffload for those devices.
|
||||
---
|
||||
libselinux/src/label_backends_android.c | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
diff --git a/libselinux/src/label_backends_android.c b/libselinux/src/label_backends_android.c
|
||||
index eaca5947..ab92985b 100644
|
||||
--- a/libselinux/src/label_backends_android.c
|
||||
+++ b/libselinux/src/label_backends_android.c
|
||||
@@ -62,6 +62,16 @@ static int nodups_specs(struct saved_data *data)
|
||||
curr_spec->property_key)) {
|
||||
if (strcmp(spec_arr[jj].lr.ctx_raw,
|
||||
curr_spec->lr.ctx_raw)) {
|
||||
+ if(strcmp(spec_arr[jj].lr.ctx_raw, "u:object_r:hal_ipacm_hwservice:s0") == 0) {
|
||||
+ free(spec_arr[jj].lr.ctx_raw);
|
||||
+ spec_arr[jj].lr.ctx_raw = strdup("u:object_r:hal_tetheroffload_hwservice:s0");
|
||||
+ continue;
|
||||
+ }
|
||||
+ if(strcmp(curr_spec->lr.ctx_raw, "u:object_r:hal_ipacm_hwservice:s0") == 0) {
|
||||
+ free(curr_spec->lr.ctx_raw);
|
||||
+ curr_spec->lr.ctx_raw = strdup("u:object_r:hal_tetheroffload_hwservice:s0");
|
||||
+ continue;
|
||||
+ }
|
||||
rc = -1;
|
||||
errno = EINVAL;
|
||||
selinux_log
|
||||
--
|
||||
2.17.1
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
From f014cf6460159f820fc0d72c6d0bece2851f9873 Mon Sep 17 00:00:00 2001
|
||||
From: Pierre-Hugues Husson <phh@phh.me>
|
||||
Date: Fri, 6 Sep 2019 15:07:25 +0200
|
||||
Subject: [PATCH 04/10] Allow /devices/virtual/block/ genfscon conflict (seen
|
||||
on Xiaomi Mi 9)
|
||||
|
||||
Change-Id: I06e4e9d5b82d61a8aeab595b47e2589249675895
|
||||
---
|
||||
libsepol/cil/src/cil_post.c | 18 +++++++++++++++++-
|
||||
1 file changed, 17 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c
|
||||
index a0cadfde..68c0318e 100644
|
||||
--- a/libsepol/cil/src/cil_post.c
|
||||
+++ b/libsepol/cil/src/cil_post.c
|
||||
@@ -477,7 +477,23 @@ int cil_post_genfscon_context_compare(const void *a, const void *b)
|
||||
{
|
||||
struct cil_genfscon *a_genfscon = *(struct cil_genfscon**)a;
|
||||
struct cil_genfscon *b_genfscon = *(struct cil_genfscon**)b;
|
||||
- return context_compare(a_genfscon->context, b_genfscon->context);
|
||||
+ int rc = context_compare(a_genfscon->context, b_genfscon->context);
|
||||
+ if(rc) {
|
||||
+ fprintf(stderr, "hello %s\n", a_genfscon->fs_str);
|
||||
+ int bypass = 0;
|
||||
+ /*
|
||||
+ * This conflict has been seen on Xiaomi Mi 9:
|
||||
+ * - AOSP Q says (genfscon sysfs /devices/virtual/block/ (u object_r sysfs_devices_block ((s0) (s0))))
|
||||
+ * - stock rom says (genfscon sysfs /devices/virtual/block/ (u object_r sysfs_ufs_target ((s0) (s0))))
|
||||
+ */
|
||||
+ if(strcmp(a_genfscon->path_str, "/devices/virtual/block/") == 0)
|
||||
+ bypass = 1;
|
||||
+ if(bypass == 1) {
|
||||
+ fprintf(stderr, "Received conflicting %s vs %s but ignore\n", a_genfscon->path_str, b_genfscon->path_str);
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+ return rc;
|
||||
}
|
||||
|
||||
int cil_post_netifcon_context_compare(const void *a, const void *b)
|
||||
--
|
||||
2.17.1
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
From 37d5e860031c84803c2533d940847dc214cb2597 Mon Sep 17 00:00:00 2001
|
||||
From: Pierre-Hugues Husson <phh@phh.me>
|
||||
Date: Thu, 12 Sep 2019 20:34:28 +0200
|
||||
Subject: [PATCH 05/10] Most horrific: Remove ramdisk's zygote init scripts
|
||||
|
||||
This is needed because:
|
||||
- only secilc is run soon enough in /system to
|
||||
remove it
|
||||
- placing an init.zygote in system won't have init replace it, it's the
|
||||
first that appears that wins
|
||||
|
||||
Change-Id: I8be31ceb9ef2124d04994d9fb08fc8012a2f819e
|
||||
---
|
||||
secilc/secilc.c | 7 +++++++
|
||||
1 file changed, 7 insertions(+)
|
||||
|
||||
diff --git a/secilc/secilc.c b/secilc/secilc.c
|
||||
index 1e550ab4..375320e6 100644
|
||||
--- a/secilc/secilc.c
|
||||
+++ b/secilc/secilc.c
|
||||
@@ -34,6 +34,8 @@
|
||||
#include <getopt.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
+#include <unistd.h>
|
||||
+
|
||||
#ifdef ANDROID
|
||||
#include <cil/cil.h>
|
||||
#else
|
||||
@@ -124,6 +126,11 @@ int main(int argc, char *argv[])
|
||||
};
|
||||
int i;
|
||||
|
||||
+ unlink("/init.zygote32.rc");
|
||||
+ unlink("/init.zygote64_32.rc");
|
||||
+ unlink("/init.zygote64.rc");
|
||||
+ unlink("/init.zygote32_64.rc");
|
||||
+
|
||||
while (1) {
|
||||
opt_char = getopt_long(argc, argv, "o:f:U:hvt:M:PDmNOc:GX:n", long_opts, &opt_index);
|
||||
if (opt_char == -1) {
|
||||
--
|
||||
2.17.1
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
From 04fdf9096557accdea52b8b66665717f6c8a454a Mon Sep 17 00:00:00 2001
|
||||
From: Pierre-Hugues Husson <phh@phh.me>
|
||||
Date: Thu, 12 Sep 2019 20:37:04 +0200
|
||||
Subject: [PATCH 06/10] if service is "rcs", accept conflict. Seen on Moto E5
|
||||
|
||||
Change-Id: I0cc2d0fad83f403f2b5d7458039b1564ce5ed9dd
|
||||
---
|
||||
libselinux/src/label_backends_android.c | 14 ++++++++++++--
|
||||
1 file changed, 12 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libselinux/src/label_backends_android.c b/libselinux/src/label_backends_android.c
|
||||
index ab92985b..ca16327c 100644
|
||||
--- a/libselinux/src/label_backends_android.c
|
||||
+++ b/libselinux/src/label_backends_android.c
|
||||
@@ -72,14 +72,24 @@ static int nodups_specs(struct saved_data *data)
|
||||
curr_spec->lr.ctx_raw = strdup("u:object_r:hal_tetheroffload_hwservice:s0");
|
||||
continue;
|
||||
}
|
||||
- rc = -1;
|
||||
- errno = EINVAL;
|
||||
selinux_log
|
||||
(SELINUX_ERROR,
|
||||
"Multiple different specifications for %s (%s and %s).\n",
|
||||
curr_spec->property_key,
|
||||
spec_arr[jj].lr.ctx_raw,
|
||||
curr_spec->lr.ctx_raw);
|
||||
+ int ignore = 0;
|
||||
+ /*
|
||||
+ * This issue has been found on Moto E5
|
||||
+ * E SELinux : Multiple different specifications for rcs (u:object_r:radio_service:s0 and u:object_r:mot_rcs_service:s0).
|
||||
+ */
|
||||
+ if(!strcmp(curr_spec->property_key, "rcs"))
|
||||
+ ignore = 1;
|
||||
+
|
||||
+ if(!ignore) {
|
||||
+ rc = -1;
|
||||
+ errno = EINVAL;
|
||||
+ }
|
||||
} else {
|
||||
selinux_log
|
||||
(SELINUX_WARNING,
|
||||
--
|
||||
2.17.1
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
From ef94ddbd76328611893ace7870c0d3137fd26cdd Mon Sep 17 00:00:00 2001
|
||||
From: Pierre-Hugues Husson <phh@phh.me>
|
||||
Date: Fri, 25 Oct 2019 13:29:20 +0200
|
||||
Subject: [PATCH 07/10] Fix boot on Moto devices using unknown class
|
||||
|
||||
vendor sepolicy never contains new class or classorder, and are not
|
||||
allowed to.
|
||||
Though this is not tested, and it turns out Moto did it anyway.
|
||||
This raises an issue, because class need to be ordered, and thus the cil
|
||||
contains the ordering. This ordering needs to be merged.
|
||||
Android 10 added new classes, so the ordering can no longer be merged,
|
||||
and secilc fails on those devices, preventing boot.
|
||||
|
||||
Considering vendor are not supposed to declare new class (and thus
|
||||
declare classorder), this fix ignores class-es/classorder in vendor
|
||||
SELinux policy.
|
||||
|
||||
Since the vendor selinux policy has allows rules based on this context,
|
||||
those allows will fail since the class doesn't exist.
|
||||
Workaround this by ignoring rules with the problematic class
|
||||
( keystore_moto_key )
|
||||
|
||||
Lucky us, this new class `keystore_moto_key` is used by Moto for
|
||||
framework to framework (more accurately priv app to keymaster), since
|
||||
our own framework doesn't use this class, simply ignoring it fixes the
|
||||
issue.
|
||||
|
||||
Change-Id: I66339857634ebfdba359f12a99dfd0bff709d80b
|
||||
---
|
||||
libsepol/cil/src/cil_build_ast.c | 24 ++++++++++++++++++++++++
|
||||
1 file changed, 24 insertions(+)
|
||||
|
||||
diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c
|
||||
index 307b1ee3..02cdcc65 100644
|
||||
--- a/libsepol/cil/src/cil_build_ast.c
|
||||
+++ b/libsepol/cil/src/cil_build_ast.c
|
||||
@@ -386,6 +386,14 @@ int cil_gen_class(struct cil_db *db, struct cil_tree_node *parse_current, struct
|
||||
struct cil_tree_node *perms = NULL;
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
+ {
|
||||
+ const char* path = cil_tree_get_cil_path(parse_current);
|
||||
+ if(strstr(path, "vendor")) {
|
||||
+ cil_clear_node(ast_node);
|
||||
+ return SEPOL_OK;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
rc = __cil_verify_syntax(parse_current, syntax, syntax_len);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
@@ -452,6 +460,14 @@ int cil_gen_classorder(struct cil_db *db, struct cil_tree_node *parse_current, s
|
||||
struct cil_list_item *head = NULL;
|
||||
int rc = SEPOL_ERR;
|
||||
|
||||
+ {
|
||||
+ const char* path = cil_tree_get_cil_path(parse_current);
|
||||
+ if(strstr(path, "vendor")) {
|
||||
+ cil_clear_node(ast_node);
|
||||
+ return SEPOL_OK;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
if (db == NULL || parse_current == NULL || ast_node == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
@@ -2050,6 +2066,14 @@ int cil_gen_avrule(struct cil_tree_node *parse_current, struct cil_tree_node *as
|
||||
rule->src_str = parse_current->next->data;
|
||||
rule->tgt_str = parse_current->next->next->data;
|
||||
|
||||
+ {
|
||||
+ const char *classname = parse_current->next->next->next->cl_head->data;
|
||||
+ if(strcmp(classname, "keystore_moto_key") == 0) {
|
||||
+ cil_clear_node(ast_node);
|
||||
+ return SEPOL_OK;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
rc = cil_fill_classperms_list(parse_current->next->next->next, &rule->perms.classperms);
|
||||
if (rc != SEPOL_OK) {
|
||||
goto exit;
|
||||
--
|
||||
2.17.1
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
From 3d356da4654b5ae9eb2207f824555f0219687763 Mon Sep 17 00:00:00 2001
|
||||
From: Pierre-Hugues Husson <phh@phh.me>
|
||||
Date: Sun, 24 May 2020 17:22:22 +0200
|
||||
Subject: [PATCH 08/10] Allow mismatches of exfat genfscon
|
||||
|
||||
---
|
||||
libsepol/cil/src/cil_post.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c
|
||||
index 68c0318e..75e5128c 100644
|
||||
--- a/libsepol/cil/src/cil_post.c
|
||||
+++ b/libsepol/cil/src/cil_post.c
|
||||
@@ -488,6 +488,10 @@ int cil_post_genfscon_context_compare(const void *a, const void *b)
|
||||
*/
|
||||
if(strcmp(a_genfscon->path_str, "/devices/virtual/block/") == 0)
|
||||
bypass = 1;
|
||||
+ if(strcmp(a_genfscon->fs_str, "exfat") == 0 || strcmp(a_genfscon->fs_str, "esdfs") == 0) {
|
||||
+ if(strcmp(a_genfscon->path_str, "/") == 0)
|
||||
+ bypass = 1;
|
||||
+ }
|
||||
if(bypass == 1) {
|
||||
fprintf(stderr, "Received conflicting %s vs %s but ignore\n", a_genfscon->path_str, b_genfscon->path_str);
|
||||
return 0;
|
||||
--
|
||||
2.17.1
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
From f3d5e2eb212ebd4189428d6adb915880573962f9 Mon Sep 17 00:00:00 2001
|
||||
From: Pierre-Hugues Husson <phh@phh.me>
|
||||
Date: Wed, 9 Sep 2020 22:36:42 +0200
|
||||
Subject: [PATCH 09/10] Revert "libsepol: Make an unknown permission an error
|
||||
in CIL"
|
||||
|
||||
This reverts commit dc4e54126bf25dea4d51820922ccd1959be68fbc.
|
||||
|
||||
This is required because some targets calls undefined permissions:
|
||||
- Realme X2 Pro calls sigcont
|
||||
- Honor 7X calls perf_event
|
||||
---
|
||||
libsepol/cil/src/cil_resolve_ast.c | 12 ++++++++----
|
||||
1 file changed, 8 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c
|
||||
index 87575860..e72abdeb 100644
|
||||
--- a/libsepol/cil/src/cil_resolve_ast.c
|
||||
+++ b/libsepol/cil/src/cil_resolve_ast.c
|
||||
@@ -131,14 +131,18 @@ static int __cil_resolve_perms(symtab_t *class_symtab, symtab_t *common_symtab,
|
||||
}
|
||||
}
|
||||
if (rc != SEPOL_OK) {
|
||||
+ struct cil_list *empty_list;
|
||||
if (class_flavor == CIL_MAP_CLASS) {
|
||||
cil_log(CIL_ERR, "Failed to resolve permission %s for map class\n", (char*)curr->data);
|
||||
- } else {
|
||||
- cil_log(CIL_ERR, "Failed to resolve permission %s\n", (char*)curr->data);
|
||||
+ goto exit;
|
||||
}
|
||||
- goto exit;
|
||||
+ cil_log(CIL_WARN, "Failed to resolve permission %s\n", (char*)curr->data);
|
||||
+ /* Use an empty list to represent unknown perm */
|
||||
+ cil_list_init(&empty_list, perm_strs->flavor);
|
||||
+ cil_list_append(*perm_datums, CIL_LIST, empty_list);
|
||||
+ } else {
|
||||
+ cil_list_append(*perm_datums, CIL_DATUM, perm_datum);
|
||||
}
|
||||
- cil_list_append(*perm_datums, CIL_DATUM, perm_datum);
|
||||
} else {
|
||||
cil_list_append(*perm_datums, curr->flavor, curr->data);
|
||||
}
|
||||
--
|
||||
2.17.1
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
From 00f7989d79ad8e219dae29de8e8f20e4dbab008a Mon Sep 17 00:00:00 2001
|
||||
From: Pierre-Hugues Husson <phh@phh.me>
|
||||
Date: Sun, 27 Sep 2020 20:20:35 +0200
|
||||
Subject: [PATCH 10/10] [HACK] For System-as-System devices, init won't call us
|
||||
with /system_ext sepolicy
|
||||
|
||||
So add system_ext sepolicy ourselves
|
||||
---
|
||||
secilc/secilc.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 44 insertions(+)
|
||||
|
||||
diff --git a/secilc/secilc.c b/secilc/secilc.c
|
||||
index 375320e6..162b87fb 100644
|
||||
--- a/secilc/secilc.c
|
||||
+++ b/secilc/secilc.c
|
||||
@@ -233,6 +233,7 @@ int main(int argc, char *argv[])
|
||||
usage(argv[0]);
|
||||
}
|
||||
}
|
||||
+
|
||||
if (optind >= argc) {
|
||||
fprintf(stderr, "No cil files specified\n");
|
||||
usage(argv[0]);
|
||||
@@ -240,6 +241,11 @@ int main(int argc, char *argv[])
|
||||
|
||||
cil_set_log_level(log_level);
|
||||
|
||||
+ int needSystemExt = 1;
|
||||
+ for (i = optind; i < argc; i++) {
|
||||
+ if(strstr(argv[i], "system_ext")) needSystemExt = 0;
|
||||
+ }
|
||||
+
|
||||
cil_db_init(&db);
|
||||
cil_set_disable_dontaudit(db, disable_dontaudit);
|
||||
cil_set_multiple_decls(db, multiple_decls);
|
||||
@@ -261,6 +267,44 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
for (i = optind; i < argc; i++) {
|
||||
+ fprintf(stderr, "Hello, parsing %s\n", argv[i]);
|
||||
+ if(needSystemExt && strstr(argv[i], "/etc/selinux/")) {
|
||||
+ fprintf(stderr, "Hello, I'm adding system_ext to the mix!\n");
|
||||
+ char *path = "/system/system_ext/etc/selinux/system_ext_sepolicy.cil";
|
||||
+ file = fopen(path, "r");
|
||||
+ if (!file) {
|
||||
+ fprintf(stderr, "Could not open file: %s\n", path);
|
||||
+ rc = SEPOL_ERR;
|
||||
+ goto exit;
|
||||
+ }
|
||||
+ rc = stat(path, &filedata);
|
||||
+ if (rc == -1) {
|
||||
+ fprintf(stderr, "Could not stat file: %s\n", path);
|
||||
+ rc = SEPOL_ERR;
|
||||
+ goto exit;
|
||||
+ }
|
||||
+ file_size = filedata.st_size;
|
||||
+
|
||||
+ buffer = malloc(file_size);
|
||||
+ rc = fread(buffer, file_size, 1, file);
|
||||
+ if (rc != 1) {
|
||||
+ fprintf(stderr, "Failure reading file: %s\n", path);
|
||||
+ rc = SEPOL_ERR;
|
||||
+ goto exit;
|
||||
+ }
|
||||
+ fclose(file);
|
||||
+ file = NULL;
|
||||
+
|
||||
+ rc = cil_add_file(db, path, buffer, file_size);
|
||||
+ if (rc != SEPOL_OK) {
|
||||
+ fprintf(stderr, "Failure adding %s\n", path);
|
||||
+ goto exit;
|
||||
+ }
|
||||
+
|
||||
+ free(buffer);
|
||||
+ buffer = NULL;
|
||||
+
|
||||
+ }
|
||||
file = fopen(argv[i], "r");
|
||||
if (!file) {
|
||||
fprintf(stderr, "Could not open file: %s\n", argv[i]);
|
||||
--
|
||||
2.17.1
|
||||
|
||||
Reference in New Issue
Block a user