-
-
Notifications
You must be signed in to change notification settings - Fork 11k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
check adb runnable before starting scrcpy #236
Conversation
I agree, this is a good idea to show a better error message than:
However, I think the detection should not rely on the existence of the binary (iterating over Instead, we can report this problem properly if In this case, Then it would report this information back to the caller in some way (its signature should be changed). |
Hi, @rom1v I agree that it's just an heuristic method. However, I think the Sincerely. |
Then, this is a good reason to use the result of |
Thank you for your advice. I will write a prototype these days. |
Hi, @rom1v I have modified the commit base on your advice. The result will look like:
Thanks. |
861b5e7
to
ebc5eba
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job 👍
I added my remarks inline, mainly:
- finally replace
pipe2()
bypipe()
+fcntl()
because it's not portable - no need to change the signature of
cmd_execute()
if the error is not reported to the caller ofadb_execute()
return cmd_execute(cmd[0], cmd); | ||
r = cmd_execute(cmd[0], cmd, &process); | ||
if (r != 0) { | ||
show_err_msg(r); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the error is not reported to the caller of adb_execute()
(I'm ok with this), the relevant error message can be printed directly in the specific implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion, the cmd_exectue
is a general function. That is, it can execute any cmd. When it errors, problem should be handled by caller or propagate to the caller's caller. In this case, caller adb_execute
handles the problem and stop propagating the failure. The error is handeled by showing error msg in adb_execute
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, yes, of course. I confused adb_execute()
and cmd_execute()
(initially, I thought that even adb_execute()
would report error to the caller). Whatever. It's better like that.
@@ -32,7 +32,7 @@ | |||
#endif | |||
# define NO_EXIT_CODE -1 | |||
|
|||
process_t cmd_execute(const char *path, const char *const argv[]); | |||
int cmd_execute(const char *path, const char *const argv[], process_t *process); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(and if the error message is printed directly in the specific implementation, there is no need to change this signature: PROCESS_NONE
will report the error)
app/src/sys/unix/command.c
Outdated
@@ -1,24 +1,66 @@ | |||
#define _GNU_SOURCE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I didn't realize that pipe2()
required this. This would make scrcpy non portable (it would not compile on some platforms, possibly including Mac OS X (?)).
So we need pipe()
+fcntl()
instead (cf below).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do.
app/src/sys/unix/command.c
Outdated
} else if (*pid == 0) { | ||
/* child close read side. */ | ||
close(fd[0]); | ||
fd[0] = -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not necessary, you exec or _exit()
before the end of the block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Close all fds before exiting is a good habit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
close(fd[0])
, yes.
fd[0] = -1
is not necessary.
return pid; | ||
|
||
END: | ||
if (fd[0] != -1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
may never happen
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a possible path will need it, that is if we create pipe successfully but fork failed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes 👍
close(fd[0]); | ||
} | ||
if (fd[1] != -1) { | ||
close(fd[1]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can be moved to the parent block
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a possible path will need it, that is if we create pipe successfully but fork failed. I remain it in this position.
app/src/sys/unix/command.c
Outdated
} else if (*pid == 0) { | ||
/* child close read side. */ | ||
close(fd[0]); | ||
fd[0] = -1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To enable CLOEXEC without pipe2()
, add:
if (fcntl(fd[1], F_SETFD, FD_CLOEXEC) == -1) {
perror("fcntl");
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will do
app/src/sys/unix/command.c
Outdated
fd[1] = -1; | ||
/* and blocking read until child exec or write some fail | ||
* reason in fd. */ | ||
if (0 > read(fd[0], &ret, sizeof(int))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(please reverse the operands)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do
@@ -4,7 +4,7 @@ | |||
#include "log.h" | |||
#include "str_util.h" | |||
|
|||
HANDLE cmd_execute(const char *path, const char *const argv[]) { | |||
int cmd_execute(const char *path, const char *const argv[], HANDLE *handle) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(same here)
There are many user who encounters missing adb. To stop things happens again, we check it and show sexy response to user. Signed-off-by: yuchenlin <[email protected]>
Hi, @rom1v I have modified commit based on our discussion. v2 -> v3
Thanks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job! 👍 Thank you.
I commented inline, mostly nitpicking/codestyle.
The only important things are:
- replace
-1
byPROCESS_NONE
(for Windows) - send error on
fcntl()
failure
One remaining thing: could we detect missing adb
on Windows like on *nux?
Please find my suggestions (as a diff) below. I took the liberty to rewrite some comments and error messages. Please tell if you disagree with them.
diff --git a/app/src/command.c b/app/src/command.c
index 4f3e8d4..10e5ef9 100644
--- a/app/src/command.c
+++ b/app/src/command.c
@@ -1,8 +1,7 @@
#include "command.h"
-#ifdef __WINDOWS__
-#else
-#include <errno.h>
+#ifndef __WINDOWS__
+# include <errno.h>
#endif
#include <stdio.h>
#include <stdlib.h>
@@ -24,27 +23,27 @@ static inline const char *get_adb_command() {
static void show_err_msg(int err) {
#ifdef __WINDOWS__
- LOGE("Failed to execute adb.\n");
+ (void) err; // unused
+ LOGE("Failed to execute adb");
#else
switch (err) {
- case 0:
- break;
- case -1:
- LOGE("Failed to execute adb.\n");
- break;
- case ENOENT:
- LOGE("Missing adb. You need adb, accessible from your PATH to execute scrcpy.\n");
- break;
- default:
- LOGE("Failed to execute adb, errno: [%d].\n", err);
- break;
+ case -1:
+ LOGE("Failed to execute adb");
+ break;
+ case ENOENT:
+ LOGE("'adb' command not found (make it accessible from your PATH "
+ "or define its full path in the ADB environment variable)");
+ break;
+ default:
+ LOGE("Failed to execute adb: %s", strerror(err));
+ break;
}
#endif
}
process_t adb_execute(const char *serial, const char *const adb_cmd[], int len) {
const char *cmd[len + 4];
- int i, r;
+ int i;
process_t process;
cmd[0] = get_adb_command();
if (serial) {
@@ -57,10 +56,10 @@ process_t adb_execute(const char *serial, const char *const adb_cmd[], int len)
memcpy(&cmd[i], adb_cmd, len * sizeof(const char *));
cmd[len + i] = NULL;
- r = cmd_execute(cmd[0], cmd, &process);
+ int r = cmd_execute(cmd[0], cmd, &process);
if (r != 0) {
show_err_msg(r);
- return -1;
+ return PROCESS_NONE;
}
return process;
}
diff --git a/app/src/sys/unix/command.c b/app/src/sys/unix/command.c
index 53d0bb1..20218cb 100644
--- a/app/src/sys/unix/command.c
+++ b/app/src/sys/unix/command.c
@@ -13,7 +13,7 @@ int cmd_execute(const char *path, const char *const argv[], pid_t *pid) {
int fd[2];
int ret = 0;
- if (0 > pipe(fd)) {
+ if (pipe(fd) == -1) {
perror("pipe");
return -1;
}
@@ -22,42 +22,38 @@ int cmd_execute(const char *path, const char *const argv[], pid_t *pid) {
if (*pid == -1) {
perror("fork");
ret = -1;
- goto END;
+ goto end;
}
if (*pid > 0) {
- /* parent close write side. */
+ // parent close write side
close(fd[1]);
fd[1] = -1;
- /* and blocking read until child exec or write some fail
- * reason in fd. */
+ // wait for EOF or receive errno from child
if (read(fd[0], &ret, sizeof(int)) == -1) {
perror("read");
ret = -1;
- goto END;
+ goto end;
}
} else if (*pid == 0) {
- /* child close read side. */
+ // child close read side
close(fd[0]);
- if (fcntl(fd[1], F_SETFD, FD_CLOEXEC) == -1) {
+ if (fcntl(fd[1], F_SETFD, FD_CLOEXEC) == 0) {
+ execvp(path, (char *const *)argv);
+ } else {
perror("fcntl");
- /* To prevent parent hang in read, we should exit when error. */
- close(fd[1]);
- _exit(1);
}
- execvp(path, (char *const *)argv);
- /* if child execvp failed, before exit, we should write
- * reason into the pipe. */
+ // send errno to the parent
ret = errno;
if (write(fd[1], &ret, sizeof(int)) == -1) {
perror("write");
}
- /* close write side before exiting. */
+ // close write side before exiting
close(fd[1]);
_exit(1);
}
-END:
+end:
if (fd[0] != -1) {
close(fd[0]);
}
@@ -1,5 +1,9 @@ | |||
#include "command.h" | |||
|
|||
#ifdef __WINDOWS__ | |||
#else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#ifndef __WINDOWS__
LOGE("Failed to execute adb.\n"); | ||
#else | ||
switch (err) { | ||
case 0: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
may not happen
@@ -18,9 +22,30 @@ static inline const char *get_adb_command() { | |||
return adb_command; | |||
} | |||
|
|||
static void show_err_msg(int err) { | |||
#ifdef __WINDOWS__ | |||
LOGE("Failed to execute adb.\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly windows users are lost with adb
, isn't it possible to know when the problem is a missing adb?
LOGE("Failed to execute adb.\n"); | ||
break; | ||
case ENOENT: | ||
LOGE("Missing adb. You need adb, accessible from your PATH to execute scrcpy.\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest:
'adb' command not found (make it accessible from your PATH or define its absolute path in the ADB environment variable)
case 0: | ||
break; | ||
case -1: | ||
LOGE("Failed to execute adb.\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(for consistency, don't end with a .
, and \n
is not needed)
int fd[2]; | ||
int ret = 0; | ||
|
||
if (0 > pipe(fd)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (pipe(fd) == -1) {
close(fd[0]); | ||
if (fcntl(fd[1], F_SETFD, FD_CLOEXEC) == -1) { | ||
perror("fcntl"); | ||
/* To prevent parent hang in read, we should exit when error. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wrong indent (tab vs space)
goto END; | ||
} | ||
} else if (*pid == 0) { | ||
/* child close read side. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(for consistency, use //
for comments, and no ending .
)
#ifdef __WINDOWS__ | ||
LOGE("Failed to execute adb.\n"); | ||
#else | ||
switch (err) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(indent cases for consistency, it makes it more readable when cases have blocks)
if (fcntl(fd[1], F_SETFD, FD_CLOEXEC) == -1) { | ||
perror("fcntl"); | ||
/* To prevent parent hang in read, we should exit when error. */ | ||
close(fd[1]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
must send a failure to the parent (e.g. errno
set by fcntl
), otherwise the parent will consider that the child has execed successfully
Hi, @rom1v Thank you for your effort and time. All look good to me. btw, I am not familiar with coding in Windows. I will take a look to survey how to detect it in Windows related system recently. Sincerely, |
check adb runnable before starting scrcpy
There are many user who encounters missing adb.
To stop things happens again, we check it and show
sexy response to user.
In the first version, I only check in linux. If you like this idea, I will continue to finish windows part.
Thanks.
Signed-off-by: yuchenlin [email protected]