Home | History | Annotate | Download | only in uncrypt
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 // This program takes a file on an ext4 filesystem and produces a list
     18 // of the blocks that file occupies, which enables the file contents
     19 // to be read directly from the block device without mounting the
     20 // filesystem.
     21 //
     22 // If the filesystem is using an encrypted block device, it will also
     23 // read the file and rewrite it to the same blocks of the underlying
     24 // (unencrypted) block device, so the file contents can be read
     25 // without the need for the decryption key.
     26 //
     27 // The output of this program is a "block map" which looks like this:
     28 //
     29 //     /dev/block/platform/msm_sdcc.1/by-name/userdata     # block device
     30 //     49652 4096                        # file size in bytes, block size
     31 //     3                                 # count of block ranges
     32 //     1000 1008                         # block range 0
     33 //     2100 2102                         # ... block range 1
     34 //     30 33                             # ... block range 2
     35 //
     36 // Each block range represents a half-open interval; the line "30 33"
     37 // reprents the blocks [30, 31, 32].
     38 //
     39 // Recovery can take this block map file and retrieve the underlying
     40 // file data to use as an update package.
     41 
     42 /**
     43  * In addition to the uncrypt work, uncrypt also takes care of setting and
     44  * clearing the bootloader control block (BCB) at /misc partition.
     45  *
     46  * uncrypt is triggered as init services on demand. It uses socket to
     47  * communicate with its caller (i.e. system_server). The socket is managed by
     48  * init (i.e. created prior to the service starts, and destroyed when uncrypt
     49  * exits).
     50  *
     51  * Below is the uncrypt protocol.
     52  *
     53  *    a. caller                 b. init                    c. uncrypt
     54  * ---------------            ------------               --------------
     55  *  a1. ctl.start:
     56  *    setup-bcb /
     57  *    clear-bcb /
     58  *    uncrypt
     59  *
     60  *                         b2. create socket at
     61  *                           /dev/socket/uncrypt
     62  *
     63  *                                                   c3. listen and accept
     64  *
     65  *  a4. send a 4-byte int
     66  *    (message length)
     67  *                                                   c5. receive message length
     68  *  a6. send message
     69  *                                                   c7. receive message
     70  *                                                   c8. <do the work; may send
     71  *                                                      the progress>
     72  *  a9. <may handle progress>
     73  *                                                   c10. <upon finishing>
     74  *                                                     send "100" or "-1"
     75  *
     76  *  a11. receive status code
     77  *  a12. send a 4-byte int to
     78  *    ack the receive of the
     79  *    final status code
     80  *                                                   c13. receive and exit
     81  *
     82  *                          b14. destroy the socket
     83  *
     84  * Note that a12 and c13 are necessary to ensure a11 happens before the socket
     85  * gets destroyed in b14.
     86  */
     87 
     88 #include <arpa/inet.h>
     89 #include <errno.h>
     90 #include <fcntl.h>
     91 #include <inttypes.h>
     92 #include <libgen.h>
     93 #include <linux/fs.h>
     94 #include <stdarg.h>
     95 #include <stdio.h>
     96 #include <stdlib.h>
     97 #include <string.h>
     98 #include <sys/mman.h>
     99 #include <sys/socket.h>
    100 #include <sys/stat.h>
    101 #include <sys/types.h>
    102 #include <unistd.h>
    103 
    104 #include <algorithm>
    105 #include <memory>
    106 #include <vector>
    107 
    108 #include <android-base/file.h>
    109 #include <android-base/logging.h>
    110 #include <android-base/properties.h>
    111 #include <android-base/stringprintf.h>
    112 #include <android-base/strings.h>
    113 #include <android-base/unique_fd.h>
    114 #include <bootloader_message/bootloader_message.h>
    115 #include <cutils/android_reboot.h>
    116 #include <cutils/sockets.h>
    117 #include <fs_mgr.h>
    118 
    119 #include "error_code.h"
    120 
    121 static constexpr int WINDOW_SIZE = 5;
    122 static constexpr int FIBMAP_RETRY_LIMIT = 3;
    123 
    124 // uncrypt provides three services: SETUP_BCB, CLEAR_BCB and UNCRYPT.
    125 //
    126 // SETUP_BCB and CLEAR_BCB services use socket communication and do not rely
    127 // on /cache partitions. They will handle requests to reboot into recovery
    128 // (for applying updates for non-A/B devices, or factory resets for all
    129 // devices).
    130 //
    131 // UNCRYPT service still needs files on /cache partition (UNCRYPT_PATH_FILE
    132 // and CACHE_BLOCK_MAP). It will be working (and needed) only for non-A/B
    133 // devices, on which /cache partitions always exist.
    134 static const std::string CACHE_BLOCK_MAP = "/cache/recovery/block.map";
    135 static const std::string UNCRYPT_PATH_FILE = "/cache/recovery/uncrypt_file";
    136 static const std::string UNCRYPT_STATUS = "/cache/recovery/uncrypt_status";
    137 static const std::string UNCRYPT_SOCKET = "uncrypt";
    138 
    139 static struct fstab* fstab = nullptr;
    140 
    141 static int write_at_offset(unsigned char* buffer, size_t size, int wfd, off64_t offset) {
    142     if (TEMP_FAILURE_RETRY(lseek64(wfd, offset, SEEK_SET)) == -1) {
    143         PLOG(ERROR) << "error seeking to offset " << offset;
    144         return -1;
    145     }
    146     if (!android::base::WriteFully(wfd, buffer, size)) {
    147         PLOG(ERROR) << "error writing offset " << offset;
    148         return -1;
    149     }
    150     return 0;
    151 }
    152 
    153 static void add_block_to_ranges(std::vector<int>& ranges, int new_block) {
    154     if (!ranges.empty() && new_block == ranges.back()) {
    155         // If the new block comes immediately after the current range,
    156         // all we have to do is extend the current range.
    157         ++ranges.back();
    158     } else {
    159         // We need to start a new range.
    160         ranges.push_back(new_block);
    161         ranges.push_back(new_block + 1);
    162     }
    163 }
    164 
    165 static struct fstab* read_fstab() {
    166     fstab = fs_mgr_read_fstab_default();
    167     if (!fstab) {
    168         LOG(ERROR) << "failed to read default fstab";
    169         return NULL;
    170     }
    171 
    172     return fstab;
    173 }
    174 
    175 static const char* find_block_device(const char* path, bool* encryptable, bool* encrypted) {
    176     // Look for a volume whose mount point is the prefix of path and
    177     // return its block device.  Set encrypted if it's currently
    178     // encrypted.
    179     for (int i = 0; i < fstab->num_entries; ++i) {
    180         struct fstab_rec* v = &fstab->recs[i];
    181         if (!v->mount_point) {
    182             continue;
    183         }
    184         int len = strlen(v->mount_point);
    185         if (strncmp(path, v->mount_point, len) == 0 &&
    186             (path[len] == '/' || path[len] == 0)) {
    187             *encrypted = false;
    188             *encryptable = false;
    189             if (fs_mgr_is_encryptable(v) || fs_mgr_is_file_encrypted(v)) {
    190                 *encryptable = true;
    191                 if (android::base::GetProperty("ro.crypto.state", "") == "encrypted") {
    192                     *encrypted = true;
    193                 }
    194             }
    195             return v->blk_device;
    196         }
    197     }
    198 
    199     return NULL;
    200 }
    201 
    202 static bool write_status_to_socket(int status, int socket) {
    203     // If socket equals -1, uncrypt is in debug mode without socket communication.
    204     // Skip writing and return success.
    205     if (socket == -1) {
    206         return true;
    207     }
    208     int status_out = htonl(status);
    209     return android::base::WriteFully(socket, &status_out, sizeof(int));
    210 }
    211 
    212 // Parse uncrypt_file to find the update package name.
    213 static bool find_uncrypt_package(const std::string& uncrypt_path_file, std::string* package_name) {
    214     CHECK(package_name != nullptr);
    215     std::string uncrypt_path;
    216     if (!android::base::ReadFileToString(uncrypt_path_file, &uncrypt_path)) {
    217         PLOG(ERROR) << "failed to open \"" << uncrypt_path_file << "\"";
    218         return false;
    219     }
    220 
    221     // Remove the trailing '\n' if present.
    222     *package_name = android::base::Trim(uncrypt_path);
    223     return true;
    224 }
    225 
    226 static int retry_fibmap(const int fd, const char* name, int* block, const int head_block) {
    227     CHECK(block != nullptr);
    228     for (size_t i = 0; i < FIBMAP_RETRY_LIMIT; i++) {
    229         if (fsync(fd) == -1) {
    230             PLOG(ERROR) << "failed to fsync \"" << name << "\"";
    231             return kUncryptFileSyncError;
    232         }
    233         if (ioctl(fd, FIBMAP, block) != 0) {
    234             PLOG(ERROR) << "failed to find block " << head_block;
    235             return kUncryptIoctlError;
    236         }
    237         if (*block != 0) {
    238             return kUncryptNoError;
    239         }
    240         sleep(1);
    241     }
    242     LOG(ERROR) << "fibmap of " << head_block << "always returns 0";
    243     return kUncryptIoctlError;
    244 }
    245 
    246 static int produce_block_map(const char* path, const char* map_file, const char* blk_dev,
    247                              bool encrypted, int socket) {
    248     std::string err;
    249     if (!android::base::RemoveFileIfExists(map_file, &err)) {
    250         LOG(ERROR) << "failed to remove the existing map file " << map_file << ": " << err;
    251         return kUncryptFileRemoveError;
    252     }
    253     std::string tmp_map_file = std::string(map_file) + ".tmp";
    254     android::base::unique_fd mapfd(open(tmp_map_file.c_str(),
    255                                         O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR));
    256     if (mapfd == -1) {
    257         PLOG(ERROR) << "failed to open " << tmp_map_file;
    258         return kUncryptFileOpenError;
    259     }
    260 
    261     // Make sure we can write to the socket.
    262     if (!write_status_to_socket(0, socket)) {
    263         LOG(ERROR) << "failed to write to socket " << socket;
    264         return kUncryptSocketWriteError;
    265     }
    266 
    267     struct stat sb;
    268     if (stat(path, &sb) != 0) {
    269         LOG(ERROR) << "failed to stat " << path;
    270         return kUncryptFileStatError;
    271     }
    272 
    273     LOG(INFO) << " block size: " << sb.st_blksize << " bytes";
    274 
    275     int blocks = ((sb.st_size-1) / sb.st_blksize) + 1;
    276     LOG(INFO) << "  file size: " << sb.st_size << " bytes, " << blocks << " blocks";
    277 
    278     std::vector<int> ranges;
    279 
    280     std::string s = android::base::StringPrintf("%s\n%" PRId64 " %" PRId64 "\n",
    281                        blk_dev, static_cast<int64_t>(sb.st_size),
    282                        static_cast<int64_t>(sb.st_blksize));
    283     if (!android::base::WriteStringToFd(s, mapfd)) {
    284         PLOG(ERROR) << "failed to write " << tmp_map_file;
    285         return kUncryptWriteError;
    286     }
    287 
    288     std::vector<std::vector<unsigned char>> buffers;
    289     if (encrypted) {
    290         buffers.resize(WINDOW_SIZE, std::vector<unsigned char>(sb.st_blksize));
    291     }
    292     int head_block = 0;
    293     int head = 0, tail = 0;
    294 
    295     android::base::unique_fd fd(open(path, O_RDONLY));
    296     if (fd == -1) {
    297         PLOG(ERROR) << "failed to open " << path << " for reading";
    298         return kUncryptFileOpenError;
    299     }
    300 
    301     android::base::unique_fd wfd;
    302     if (encrypted) {
    303         wfd.reset(open(blk_dev, O_WRONLY));
    304         if (wfd == -1) {
    305             PLOG(ERROR) << "failed to open " << blk_dev << " for writing";
    306             return kUncryptBlockOpenError;
    307         }
    308     }
    309 
    310     off64_t pos = 0;
    311     int last_progress = 0;
    312     while (pos < sb.st_size) {
    313         // Update the status file, progress must be between [0, 99].
    314         int progress = static_cast<int>(100 * (double(pos) / double(sb.st_size)));
    315         if (progress > last_progress) {
    316             last_progress = progress;
    317             write_status_to_socket(progress, socket);
    318         }
    319 
    320         if ((tail+1) % WINDOW_SIZE == head) {
    321             // write out head buffer
    322             int block = head_block;
    323             if (ioctl(fd, FIBMAP, &block) != 0) {
    324                 PLOG(ERROR) << "failed to find block " << head_block;
    325                 return kUncryptIoctlError;
    326             }
    327 
    328             if (block == 0) {
    329                 LOG(ERROR) << "failed to find block " << head_block << ", retrying";
    330                 int error = retry_fibmap(fd, path, &block, head_block);
    331                 if (error != kUncryptNoError) {
    332                     return error;
    333                 }
    334             }
    335 
    336             add_block_to_ranges(ranges, block);
    337             if (encrypted) {
    338                 if (write_at_offset(buffers[head].data(), sb.st_blksize, wfd,
    339                                     static_cast<off64_t>(sb.st_blksize) * block) != 0) {
    340                     return kUncryptWriteError;
    341                 }
    342             }
    343             head = (head + 1) % WINDOW_SIZE;
    344             ++head_block;
    345         }
    346 
    347         // read next block to tail
    348         if (encrypted) {
    349             size_t to_read = static_cast<size_t>(
    350                     std::min(static_cast<off64_t>(sb.st_blksize), sb.st_size - pos));
    351             if (!android::base::ReadFully(fd, buffers[tail].data(), to_read)) {
    352                 PLOG(ERROR) << "failed to read " << path;
    353                 return kUncryptReadError;
    354             }
    355             pos += to_read;
    356         } else {
    357             // If we're not encrypting; we don't need to actually read
    358             // anything, just skip pos forward as if we'd read a
    359             // block.
    360             pos += sb.st_blksize;
    361         }
    362         tail = (tail+1) % WINDOW_SIZE;
    363     }
    364 
    365     while (head != tail) {
    366         // write out head buffer
    367         int block = head_block;
    368         if (ioctl(fd, FIBMAP, &block) != 0) {
    369             PLOG(ERROR) << "failed to find block " << head_block;
    370             return kUncryptIoctlError;
    371         }
    372 
    373         if (block == 0) {
    374             LOG(ERROR) << "failed to find block " << head_block << ", retrying";
    375             int error = retry_fibmap(fd, path, &block, head_block);
    376             if (error != kUncryptNoError) {
    377                 return error;
    378             }
    379         }
    380 
    381         add_block_to_ranges(ranges, block);
    382         if (encrypted) {
    383             if (write_at_offset(buffers[head].data(), sb.st_blksize, wfd,
    384                                 static_cast<off64_t>(sb.st_blksize) * block) != 0) {
    385                 return kUncryptWriteError;
    386             }
    387         }
    388         head = (head + 1) % WINDOW_SIZE;
    389         ++head_block;
    390     }
    391 
    392     if (!android::base::WriteStringToFd(
    393             android::base::StringPrintf("%zu\n", ranges.size() / 2), mapfd)) {
    394         PLOG(ERROR) << "failed to write " << tmp_map_file;
    395         return kUncryptWriteError;
    396     }
    397     for (size_t i = 0; i < ranges.size(); i += 2) {
    398         if (!android::base::WriteStringToFd(
    399                 android::base::StringPrintf("%d %d\n", ranges[i], ranges[i+1]), mapfd)) {
    400             PLOG(ERROR) << "failed to write " << tmp_map_file;
    401             return kUncryptWriteError;
    402         }
    403     }
    404 
    405     if (fsync(mapfd) == -1) {
    406         PLOG(ERROR) << "failed to fsync \"" << tmp_map_file << "\"";
    407         return kUncryptFileSyncError;
    408     }
    409     if (close(mapfd.release()) == -1) {
    410         PLOG(ERROR) << "failed to close " << tmp_map_file;
    411         return kUncryptFileCloseError;
    412     }
    413 
    414     if (encrypted) {
    415         if (fsync(wfd) == -1) {
    416             PLOG(ERROR) << "failed to fsync \"" << blk_dev << "\"";
    417             return kUncryptFileSyncError;
    418         }
    419         if (close(wfd.release()) == -1) {
    420             PLOG(ERROR) << "failed to close " << blk_dev;
    421             return kUncryptFileCloseError;
    422         }
    423     }
    424 
    425     if (rename(tmp_map_file.c_str(), map_file) == -1) {
    426         PLOG(ERROR) << "failed to rename " << tmp_map_file << " to " << map_file;
    427         return kUncryptFileRenameError;
    428     }
    429     // Sync dir to make rename() result written to disk.
    430     std::string file_name = map_file;
    431     std::string dir_name = dirname(&file_name[0]);
    432     android::base::unique_fd dfd(open(dir_name.c_str(), O_RDONLY | O_DIRECTORY));
    433     if (dfd == -1) {
    434         PLOG(ERROR) << "failed to open dir " << dir_name;
    435         return kUncryptFileOpenError;
    436     }
    437     if (fsync(dfd) == -1) {
    438         PLOG(ERROR) << "failed to fsync " << dir_name;
    439         return kUncryptFileSyncError;
    440     }
    441     if (close(dfd.release()) == -1) {
    442         PLOG(ERROR) << "failed to close " << dir_name;
    443         return kUncryptFileCloseError;
    444     }
    445     return 0;
    446 }
    447 
    448 static int uncrypt(const char* input_path, const char* map_file, const int socket) {
    449     LOG(INFO) << "update package is \"" << input_path << "\"";
    450 
    451     // Turn the name of the file we're supposed to convert into an
    452     // absolute path, so we can find what filesystem it's on.
    453     char path[PATH_MAX+1];
    454     if (realpath(input_path, path) == NULL) {
    455         PLOG(ERROR) << "failed to convert \"" << input_path << "\" to absolute path";
    456         return 1;
    457     }
    458 
    459     bool encryptable;
    460     bool encrypted;
    461     const char* blk_dev = find_block_device(path, &encryptable, &encrypted);
    462     if (blk_dev == NULL) {
    463         LOG(ERROR) << "failed to find block device for " << path;
    464         return 1;
    465     }
    466 
    467     // If the filesystem it's on isn't encrypted, we only produce the
    468     // block map, we don't rewrite the file contents (it would be
    469     // pointless to do so).
    470     LOG(INFO) << "encryptable: " << (encryptable ? "yes" : "no");
    471     LOG(INFO) << "  encrypted: " << (encrypted ? "yes" : "no");
    472 
    473     // Recovery supports installing packages from 3 paths: /cache,
    474     // /data, and /sdcard.  (On a particular device, other locations
    475     // may work, but those are three we actually expect.)
    476     //
    477     // On /data we want to convert the file to a block map so that we
    478     // can read the package without mounting the partition.  On /cache
    479     // and /sdcard we leave the file alone.
    480     if (strncmp(path, "/data/", 6) == 0) {
    481         LOG(INFO) << "writing block map " << map_file;
    482         return produce_block_map(path, map_file, blk_dev, encrypted, socket);
    483     }
    484 
    485     return 0;
    486 }
    487 
    488 static void log_uncrypt_error_code(UncryptErrorCode error_code) {
    489     if (!android::base::WriteStringToFile(android::base::StringPrintf(
    490             "uncrypt_error: %d\n", error_code), UNCRYPT_STATUS)) {
    491         PLOG(WARNING) << "failed to write to " << UNCRYPT_STATUS;
    492     }
    493 }
    494 
    495 static bool uncrypt_wrapper(const char* input_path, const char* map_file, const int socket) {
    496     // Initialize the uncrypt error to kUncryptErrorPlaceholder.
    497     log_uncrypt_error_code(kUncryptErrorPlaceholder);
    498 
    499     std::string package;
    500     if (input_path == nullptr) {
    501         if (!find_uncrypt_package(UNCRYPT_PATH_FILE, &package)) {
    502             write_status_to_socket(-1, socket);
    503             // Overwrite the error message.
    504             log_uncrypt_error_code(kUncryptPackageMissingError);
    505             return false;
    506         }
    507         input_path = package.c_str();
    508     }
    509     CHECK(map_file != nullptr);
    510 
    511     auto start = std::chrono::system_clock::now();
    512     int status = uncrypt(input_path, map_file, socket);
    513     std::chrono::duration<double> duration = std::chrono::system_clock::now() - start;
    514     int count = static_cast<int>(duration.count());
    515 
    516     std::string uncrypt_message = android::base::StringPrintf("uncrypt_time: %d\n", count);
    517     if (status != 0) {
    518         // Log the time cost and error code if uncrypt fails.
    519         uncrypt_message += android::base::StringPrintf("uncrypt_error: %d\n", status);
    520         if (!android::base::WriteStringToFile(uncrypt_message, UNCRYPT_STATUS)) {
    521             PLOG(WARNING) << "failed to write to " << UNCRYPT_STATUS;
    522         }
    523 
    524         write_status_to_socket(-1, socket);
    525         return false;
    526     }
    527 
    528     if (!android::base::WriteStringToFile(uncrypt_message, UNCRYPT_STATUS)) {
    529         PLOG(WARNING) << "failed to write to " << UNCRYPT_STATUS;
    530     }
    531 
    532     write_status_to_socket(100, socket);
    533 
    534     return true;
    535 }
    536 
    537 static bool clear_bcb(const int socket) {
    538     std::string err;
    539     if (!clear_bootloader_message(&err)) {
    540         LOG(ERROR) << "failed to clear bootloader message: " << err;
    541         write_status_to_socket(-1, socket);
    542         return false;
    543     }
    544     write_status_to_socket(100, socket);
    545     return true;
    546 }
    547 
    548 static bool setup_bcb(const int socket) {
    549     // c5. receive message length
    550     int length;
    551     if (!android::base::ReadFully(socket, &length, 4)) {
    552         PLOG(ERROR) << "failed to read the length";
    553         return false;
    554     }
    555     length = ntohl(length);
    556 
    557     // c7. receive message
    558     std::string content;
    559     content.resize(length);
    560     if (!android::base::ReadFully(socket, &content[0], length)) {
    561         PLOG(ERROR) << "failed to read the message";
    562         return false;
    563     }
    564     LOG(INFO) << "  received command: [" << content << "] (" << content.size() << ")";
    565     std::vector<std::string> options = android::base::Split(content, "\n");
    566     std::string wipe_package;
    567     for (auto& option : options) {
    568         if (android::base::StartsWith(option, "--wipe_package=")) {
    569             std::string path = option.substr(strlen("--wipe_package="));
    570             if (!android::base::ReadFileToString(path, &wipe_package)) {
    571                 PLOG(ERROR) << "failed to read " << path;
    572                 return false;
    573             }
    574             option = android::base::StringPrintf("--wipe_package_size=%zu", wipe_package.size());
    575         }
    576     }
    577 
    578     // c8. setup the bcb command
    579     std::string err;
    580     if (!write_bootloader_message(options, &err)) {
    581         LOG(ERROR) << "failed to set bootloader message: " << err;
    582         write_status_to_socket(-1, socket);
    583         return false;
    584     }
    585     if (!wipe_package.empty() && !write_wipe_package(wipe_package, &err)) {
    586         PLOG(ERROR) << "failed to set wipe package: " << err;
    587         write_status_to_socket(-1, socket);
    588         return false;
    589     }
    590     // c10. send "100" status
    591     write_status_to_socket(100, socket);
    592     return true;
    593 }
    594 
    595 static void usage(const char* exename) {
    596     fprintf(stderr, "Usage of %s:\n", exename);
    597     fprintf(stderr, "%s [<package_path> <map_file>]  Uncrypt ota package.\n", exename);
    598     fprintf(stderr, "%s --clear-bcb  Clear BCB data in misc partition.\n", exename);
    599     fprintf(stderr, "%s --setup-bcb  Setup BCB data by command file.\n", exename);
    600 }
    601 
    602 int main(int argc, char** argv) {
    603     enum { UNCRYPT, SETUP_BCB, CLEAR_BCB, UNCRYPT_DEBUG } action;
    604     const char* input_path = nullptr;
    605     const char* map_file = CACHE_BLOCK_MAP.c_str();
    606 
    607     if (argc == 2 && strcmp(argv[1], "--clear-bcb") == 0) {
    608         action = CLEAR_BCB;
    609     } else if (argc == 2 && strcmp(argv[1], "--setup-bcb") == 0) {
    610         action = SETUP_BCB;
    611     } else if (argc == 1) {
    612         action = UNCRYPT;
    613     } else if (argc == 3) {
    614         input_path = argv[1];
    615         map_file = argv[2];
    616         action = UNCRYPT_DEBUG;
    617     } else {
    618         usage(argv[0]);
    619         return 2;
    620     }
    621 
    622     if ((fstab = read_fstab()) == nullptr) {
    623         log_uncrypt_error_code(kUncryptFstabReadError);
    624         return 1;
    625     }
    626 
    627     if (action == UNCRYPT_DEBUG) {
    628         LOG(INFO) << "uncrypt called in debug mode, skip socket communication";
    629         bool success = uncrypt_wrapper(input_path, map_file, -1);
    630         if (success) {
    631             LOG(INFO) << "uncrypt succeeded";
    632         } else{
    633             LOG(INFO) << "uncrypt failed";
    634         }
    635         return success ? 0 : 1;
    636     }
    637 
    638     // c3. The socket is created by init when starting the service. uncrypt
    639     // will use the socket to communicate with its caller.
    640     android::base::unique_fd service_socket(android_get_control_socket(UNCRYPT_SOCKET.c_str()));
    641     if (service_socket == -1) {
    642         PLOG(ERROR) << "failed to open socket \"" << UNCRYPT_SOCKET << "\"";
    643         log_uncrypt_error_code(kUncryptSocketOpenError);
    644         return 1;
    645     }
    646     fcntl(service_socket, F_SETFD, FD_CLOEXEC);
    647 
    648     if (listen(service_socket, 1) == -1) {
    649         PLOG(ERROR) << "failed to listen on socket " << service_socket.get();
    650         log_uncrypt_error_code(kUncryptSocketListenError);
    651         return 1;
    652     }
    653 
    654     android::base::unique_fd socket_fd(accept4(service_socket, nullptr, nullptr, SOCK_CLOEXEC));
    655     if (socket_fd == -1) {
    656         PLOG(ERROR) << "failed to accept on socket " << service_socket.get();
    657         log_uncrypt_error_code(kUncryptSocketAcceptError);
    658         return 1;
    659     }
    660 
    661     bool success = false;
    662     switch (action) {
    663         case UNCRYPT:
    664             success = uncrypt_wrapper(input_path, map_file, socket_fd);
    665             break;
    666         case SETUP_BCB:
    667             success = setup_bcb(socket_fd);
    668             break;
    669         case CLEAR_BCB:
    670             success = clear_bcb(socket_fd);
    671             break;
    672         default:  // Should never happen.
    673             LOG(ERROR) << "Invalid uncrypt action code: " << action;
    674             return 1;
    675     }
    676 
    677     // c13. Read a 4-byte code from the client before uncrypt exits. This is to
    678     // ensure the client to receive the last status code before the socket gets
    679     // destroyed.
    680     int code;
    681     if (android::base::ReadFully(socket_fd, &code, 4)) {
    682         LOG(INFO) << "  received " << code << ", exiting now";
    683     } else {
    684         PLOG(ERROR) << "failed to read the code";
    685     }
    686     return success ? 0 : 1;
    687 }
    688