| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <unistd.h> |
| #include <stdio.h> |
| |
| #include "sysdeps.h" |
| |
| #define TRACE_TAG TRACE_ADB |
| #include "adb.h" |
| |
| typedef struct { |
| pid_t pid; |
| int fd; |
| } backup_harvest_params; |
| |
| // socketpair but do *not* mark as close_on_exec |
| static int backup_socketpair(int sv[2]) { |
| int rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv ); |
| if (rc < 0) |
| return -1; |
| |
| return 0; |
| } |
| |
| // harvest the child process then close the read end of the socketpair |
| static void* backup_child_waiter(void* args) { |
| int status; |
| backup_harvest_params* params = (backup_harvest_params*) args; |
| |
| waitpid(params->pid, &status, 0); |
| adb_close(params->fd); |
| free(params); |
| return NULL; |
| } |
| |
| /* returns the data socket passing the backup data here for forwarding */ |
| int backup_service(BackupOperation op, char* args) { |
| pid_t pid; |
| int s[2]; |
| char* operation; |
| int socketnum; |
| |
| // Command string and choice of stdin/stdout for the pipe depend on our invocation |
| if (op == BACKUP) { |
| operation = "backup"; |
| socketnum = STDOUT_FILENO; |
| } else { |
| operation = "restore"; |
| socketnum = STDIN_FILENO; |
| } |
| |
| D("backup_service(%s, %s)\n", operation, args); |
| |
| // set up the pipe from the subprocess to here |
| // parent will read s[0]; child will write s[1] |
| if (backup_socketpair(s)) { |
| D("can't create backup/restore socketpair\n"); |
| fprintf(stderr, "unable to create backup/restore socketpair\n"); |
| return -1; |
| } |
| |
| D("Backup/restore socket pair: (send=%d, receive=%d)\n", s[1], s[0]); |
| close_on_exec(s[0]); // only the side we hold on to |
| |
| // spin off the child process to run the backup command |
| pid = fork(); |
| if (pid < 0) { |
| // failure |
| D("can't fork for %s\n", operation); |
| fprintf(stderr, "unable to fork for %s\n", operation); |
| adb_close(s[0]); |
| adb_close(s[1]); |
| return -1; |
| } |
| |
| // Great, we're off and running. |
| if (pid == 0) { |
| // child -- actually run the backup here |
| char* p; |
| int argc; |
| char portnum[16]; |
| char** bu_args; |
| |
| // fixed args: [0] is 'bu', [1] is the port number, [2] is the 'operation' string |
| argc = 3; |
| for (p = (char*)args; p && *p; ) { |
| argc++; |
| while (*p && *p != ':') p++; |
| if (*p == ':') p++; |
| } |
| |
| bu_args = (char**) alloca(argc*sizeof(char*) + 1); |
| |
| // run through again to build the argv array |
| argc = 0; |
| bu_args[argc++] = "bu"; |
| snprintf(portnum, sizeof(portnum), "%d", s[1]); |
| bu_args[argc++] = portnum; |
| bu_args[argc++] = operation; |
| for (p = (char*)args; p && *p; ) { |
| bu_args[argc++] = p; |
| while (*p && *p != ':') p++; |
| if (*p == ':') { |
| *p = 0; |
| p++; |
| } |
| } |
| bu_args[argc] = NULL; |
| |
| // Close the half of the socket that we don't care about, route 'bu's console |
| // to the output socket, and off we go |
| adb_close(s[0]); |
| |
| // off we go |
| execvp("/system/bin/bu", (char * const *)bu_args); |
| // oops error - close up shop and go home |
| fprintf(stderr, "Unable to exec 'bu', bailing\n"); |
| exit(-1); |
| } else { |
| adb_thread_t t; |
| backup_harvest_params* params; |
| |
| // parent, i.e. adbd -- close the sending half of the socket |
| D("fork() returned pid %d\n", pid); |
| adb_close(s[1]); |
| |
| // spin a thread to harvest the child process |
| params = (backup_harvest_params*) malloc(sizeof(backup_harvest_params)); |
| params->pid = pid; |
| params->fd = s[0]; |
| if (adb_thread_create(&t, backup_child_waiter, params)) { |
| adb_close(s[0]); |
| free(params); |
| D("Unable to create child harvester\n"); |
| return -1; |
| } |
| } |
| |
| // we'll be reading from s[0] as the data is sent by the child process |
| return s[0]; |
| } |