CommandListener.cpp revision edf7adf21e1c210e5954b1128efb61b62f6da274
1/*
2 * Copyright (C) 2008 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#include <stdlib.h>
18#include <sys/socket.h>
19#include <sys/types.h>
20#include <netinet/in.h>
21#include <arpa/inet.h>
22#include <dirent.h>
23#include <errno.h>
24#include <fcntl.h>
25#include <string.h>
26
27#define LOG_TAG "VoldCmdListener"
28#include <cutils/log.h>
29
30#include <sysutils/SocketClient.h>
31#include <private/android_filesystem_config.h>
32
33#include "CommandListener.h"
34#include "VolumeManager.h"
35#include "ResponseCode.h"
36#include "Process.h"
37#include "Xwarp.h"
38#include "Loop.h"
39#include "Devmapper.h"
40#include "cryptfs.h"
41#include "fstrim.h"
42
43#define DUMP_ARGS 0
44
45CommandListener::CommandListener() :
46                 FrameworkListener("vold", true) {
47    registerCmd(new DumpCmd());
48    registerCmd(new VolumeCmd());
49    registerCmd(new AsecCmd());
50    registerCmd(new ObbCmd());
51    registerCmd(new StorageCmd());
52    registerCmd(new XwarpCmd());
53    registerCmd(new CryptfsCmd());
54    registerCmd(new FstrimCmd());
55}
56
57#if DUMP_ARGS
58void CommandListener::dumpArgs(int argc, char **argv, int argObscure) {
59    char buffer[4096];
60    char *p = buffer;
61
62    memset(buffer, 0, sizeof(buffer));
63    int i;
64    for (i = 0; i < argc; i++) {
65        unsigned int len = strlen(argv[i]) + 1; // Account for space
66        if (i == argObscure) {
67            len += 2; // Account for {}
68        }
69        if (((p - buffer) + len) < (sizeof(buffer)-1)) {
70            if (i == argObscure) {
71                *p++ = '{';
72                *p++ = '}';
73                *p++ = ' ';
74                continue;
75            }
76            strcpy(p, argv[i]);
77            p+= strlen(argv[i]);
78            if (i != (argc -1)) {
79                *p++ = ' ';
80            }
81        }
82    }
83    SLOGD("%s", buffer);
84}
85#else
86void CommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
87#endif
88
89CommandListener::DumpCmd::DumpCmd() :
90                 VoldCommand("dump") {
91}
92
93int CommandListener::DumpCmd::runCommand(SocketClient *cli,
94                                         int /*argc*/, char ** /*argv*/) {
95    cli->sendMsg(0, "Dumping loop status", false);
96    if (Loop::dumpState(cli)) {
97        cli->sendMsg(ResponseCode::CommandOkay, "Loop dump failed", true);
98    }
99    cli->sendMsg(0, "Dumping DM status", false);
100    if (Devmapper::dumpState(cli)) {
101        cli->sendMsg(ResponseCode::CommandOkay, "Devmapper dump failed", true);
102    }
103    cli->sendMsg(0, "Dumping mounted filesystems", false);
104    FILE *fp = fopen("/proc/mounts", "r");
105    if (fp) {
106        char line[1024];
107        while (fgets(line, sizeof(line), fp)) {
108            line[strlen(line)-1] = '\0';
109            cli->sendMsg(0, line, false);;
110        }
111        fclose(fp);
112    }
113
114    cli->sendMsg(ResponseCode::CommandOkay, "dump complete", false);
115    return 0;
116}
117
118
119CommandListener::VolumeCmd::VolumeCmd() :
120                 VoldCommand("volume") {
121}
122
123int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
124                                                      int argc, char **argv) {
125    dumpArgs(argc, argv, -1);
126
127    if (argc < 2) {
128        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
129        return 0;
130    }
131
132    VolumeManager *vm = VolumeManager::Instance();
133    int rc = 0;
134
135    if (!strcmp(argv[1], "list")) {
136        return vm->listVolumes(cli);
137    } else if (!strcmp(argv[1], "debug")) {
138        if (argc != 3 || (argc == 3 && (strcmp(argv[2], "off") && strcmp(argv[2], "on")))) {
139            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume debug <off/on>", false);
140            return 0;
141        }
142        vm->setDebug(!strcmp(argv[2], "on") ? true : false);
143    } else if (!strcmp(argv[1], "mount")) {
144        if (argc != 3) {
145            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false);
146            return 0;
147        }
148        rc = vm->mountVolume(argv[2]);
149    } else if (!strcmp(argv[1], "unmount")) {
150        if (argc < 3 || argc > 4 ||
151           ((argc == 4 && strcmp(argv[3], "force")) &&
152            (argc == 4 && strcmp(argv[3], "force_and_revert")))) {
153            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume unmount <path> [force|force_and_revert]", false);
154            return 0;
155        }
156
157        bool force = false;
158        bool revert = false;
159        if (argc >= 4 && !strcmp(argv[3], "force")) {
160            force = true;
161        } else if (argc >= 4 && !strcmp(argv[3], "force_and_revert")) {
162            force = true;
163            revert = true;
164        }
165        rc = vm->unmountVolume(argv[2], force, revert);
166    } else if (!strcmp(argv[1], "format")) {
167        if (argc < 3 || argc > 4 ||
168            (argc == 4 && strcmp(argv[3], "wipe"))) {
169            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume format <path> [wipe]", false);
170            return 0;
171        }
172        bool wipe = false;
173        if (argc >= 4 && !strcmp(argv[3], "wipe")) {
174            wipe = true;
175        }
176        rc = vm->formatVolume(argv[2], wipe);
177    } else if (!strcmp(argv[1], "share")) {
178        if (argc != 4) {
179            cli->sendMsg(ResponseCode::CommandSyntaxError,
180                    "Usage: volume share <path> <method>", false);
181            return 0;
182        }
183        rc = vm->shareVolume(argv[2], argv[3]);
184    } else if (!strcmp(argv[1], "unshare")) {
185        if (argc != 4) {
186            cli->sendMsg(ResponseCode::CommandSyntaxError,
187                    "Usage: volume unshare <path> <method>", false);
188            return 0;
189        }
190        rc = vm->unshareVolume(argv[2], argv[3]);
191    } else if (!strcmp(argv[1], "shared")) {
192        bool enabled = false;
193        if (argc != 4) {
194            cli->sendMsg(ResponseCode::CommandSyntaxError,
195                    "Usage: volume shared <path> <method>", false);
196            return 0;
197        }
198
199        if (vm->shareEnabled(argv[2], argv[3], &enabled)) {
200            cli->sendMsg(
201                    ResponseCode::OperationFailed, "Failed to determine share enable state", true);
202        } else {
203            cli->sendMsg(ResponseCode::ShareEnabledResult,
204                    (enabled ? "Share enabled" : "Share disabled"), false);
205        }
206        return 0;
207    } else if (!strcmp(argv[1], "mkdirs")) {
208        if (argc != 3) {
209            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mkdirs <path>", false);
210            return 0;
211        }
212        rc = vm->mkdirs(argv[2]);
213    } else {
214        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false);
215    }
216
217    if (!rc) {
218        cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);
219    } else {
220        int erno = errno;
221        rc = ResponseCode::convertFromErrno();
222        cli->sendMsg(rc, "volume operation failed", true);
223    }
224
225    return 0;
226}
227
228CommandListener::StorageCmd::StorageCmd() :
229                 VoldCommand("storage") {
230}
231
232int CommandListener::StorageCmd::runCommand(SocketClient *cli,
233                                                      int argc, char **argv) {
234    dumpArgs(argc, argv, -1);
235
236    if (argc < 2) {
237        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
238        return 0;
239    }
240
241    if (!strcmp(argv[1], "users")) {
242        DIR *dir;
243        struct dirent *de;
244
245        if (argc < 3) {
246            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument: user <mountpoint>", false);
247            return 0;
248        }
249        if (!(dir = opendir("/proc"))) {
250            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open /proc", true);
251            return 0;
252        }
253
254        while ((de = readdir(dir))) {
255            int pid = Process::getPid(de->d_name);
256
257            if (pid < 0) {
258                continue;
259            }
260
261            char processName[255];
262            Process::getProcessName(pid, processName, sizeof(processName));
263
264            if (Process::checkFileDescriptorSymLinks(pid, argv[2]) ||
265                Process::checkFileMaps(pid, argv[2]) ||
266                Process::checkSymLink(pid, argv[2], "cwd") ||
267                Process::checkSymLink(pid, argv[2], "root") ||
268                Process::checkSymLink(pid, argv[2], "exe")) {
269
270                char msg[1024];
271                snprintf(msg, sizeof(msg), "%d %s", pid, processName);
272                cli->sendMsg(ResponseCode::StorageUsersListResult, msg, false);
273            }
274        }
275        closedir(dir);
276        cli->sendMsg(ResponseCode::CommandOkay, "Storage user list complete", false);
277    } else {
278        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
279    }
280    return 0;
281}
282
283CommandListener::AsecCmd::AsecCmd() :
284                 VoldCommand("asec") {
285}
286
287void CommandListener::AsecCmd::listAsecsInDirectory(SocketClient *cli, const char *directory) {
288    DIR *d = opendir(directory);
289
290    if (!d) {
291        cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
292        return;
293    }
294
295    size_t dirent_len = offsetof(struct dirent, d_name) +
296            fpathconf(dirfd(d), _PC_NAME_MAX) + 1;
297
298    struct dirent *dent = (struct dirent *) malloc(dirent_len);
299    if (dent == NULL) {
300        cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", true);
301        return;
302    }
303
304    struct dirent *result;
305
306    while (!readdir_r(d, dent, &result) && result != NULL) {
307        if (dent->d_name[0] == '.')
308            continue;
309        if (dent->d_type != DT_REG)
310            continue;
311        size_t name_len = strlen(dent->d_name);
312        if (name_len > 5 && name_len < 260 &&
313                !strcmp(&dent->d_name[name_len - 5], ".asec")) {
314            char id[255];
315            memset(id, 0, sizeof(id));
316            strlcpy(id, dent->d_name, name_len - 4);
317            cli->sendMsg(ResponseCode::AsecListResult, id, false);
318        }
319    }
320    closedir(d);
321
322    free(dent);
323}
324
325int CommandListener::AsecCmd::runCommand(SocketClient *cli,
326                                                      int argc, char **argv) {
327    if (argc < 2) {
328        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
329        return 0;
330    }
331
332    VolumeManager *vm = VolumeManager::Instance();
333    int rc = 0;
334
335    if (!strcmp(argv[1], "list")) {
336        dumpArgs(argc, argv, -1);
337
338        listAsecsInDirectory(cli, Volume::SEC_ASECDIR_EXT);
339        listAsecsInDirectory(cli, Volume::SEC_ASECDIR_INT);
340    } else if (!strcmp(argv[1], "create")) {
341        dumpArgs(argc, argv, 5);
342        if (argc != 8) {
343            cli->sendMsg(ResponseCode::CommandSyntaxError,
344                    "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid> "
345                    "<isExternal>", false);
346            return 0;
347        }
348
349        unsigned int numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
350        const bool isExternal = (atoi(argv[7]) == 1);
351        rc = vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]), isExternal);
352    } else if (!strcmp(argv[1], "finalize")) {
353        dumpArgs(argc, argv, -1);
354        if (argc != 3) {
355            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec finalize <container-id>", false);
356            return 0;
357        }
358        rc = vm->finalizeAsec(argv[2]);
359    } else if (!strcmp(argv[1], "fixperms")) {
360        dumpArgs(argc, argv, -1);
361        if  (argc != 5) {
362            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false);
363            return 0;
364        }
365
366        char *endptr;
367        gid_t gid = (gid_t) strtoul(argv[3], &endptr, 10);
368        if (*endptr != '\0') {
369            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false);
370            return 0;
371        }
372
373        rc = vm->fixupAsecPermissions(argv[2], gid, argv[4]);
374    } else if (!strcmp(argv[1], "destroy")) {
375        dumpArgs(argc, argv, -1);
376        if (argc < 3) {
377            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec destroy <container-id> [force]", false);
378            return 0;
379        }
380        bool force = false;
381        if (argc > 3 && !strcmp(argv[3], "force")) {
382            force = true;
383        }
384        rc = vm->destroyAsec(argv[2], force);
385    } else if (!strcmp(argv[1], "mount")) {
386        dumpArgs(argc, argv, 3);
387        if (argc != 5) {
388            cli->sendMsg(ResponseCode::CommandSyntaxError,
389                    "Usage: asec mount <namespace-id> <key> <ownerUid>", false);
390            return 0;
391        }
392        rc = vm->mountAsec(argv[2], argv[3], atoi(argv[4]));
393    } else if (!strcmp(argv[1], "unmount")) {
394        dumpArgs(argc, argv, -1);
395        if (argc < 3) {
396            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec unmount <container-id> [force]", false);
397            return 0;
398        }
399        bool force = false;
400        if (argc > 3 && !strcmp(argv[3], "force")) {
401            force = true;
402        }
403        rc = vm->unmountAsec(argv[2], force);
404    } else if (!strcmp(argv[1], "rename")) {
405        dumpArgs(argc, argv, -1);
406        if (argc != 4) {
407            cli->sendMsg(ResponseCode::CommandSyntaxError,
408                    "Usage: asec rename <old_id> <new_id>", false);
409            return 0;
410        }
411        rc = vm->renameAsec(argv[2], argv[3]);
412    } else if (!strcmp(argv[1], "path")) {
413        dumpArgs(argc, argv, -1);
414        if (argc != 3) {
415            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec path <container-id>", false);
416            return 0;
417        }
418        char path[255];
419
420        if (!(rc = vm->getAsecMountPath(argv[2], path, sizeof(path)))) {
421            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
422            return 0;
423        }
424    } else if (!strcmp(argv[1], "fspath")) {
425        dumpArgs(argc, argv, -1);
426        if (argc != 3) {
427            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fspath <container-id>", false);
428            return 0;
429        }
430        char path[255];
431
432        if (!(rc = vm->getAsecFilesystemPath(argv[2], path, sizeof(path)))) {
433            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
434            return 0;
435        }
436    } else {
437        dumpArgs(argc, argv, -1);
438        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown asec cmd", false);
439    }
440
441    if (!rc) {
442        cli->sendMsg(ResponseCode::CommandOkay, "asec operation succeeded", false);
443    } else {
444        rc = ResponseCode::convertFromErrno();
445        cli->sendMsg(rc, "asec operation failed", true);
446    }
447
448    return 0;
449}
450
451CommandListener::ObbCmd::ObbCmd() :
452                 VoldCommand("obb") {
453}
454
455int CommandListener::ObbCmd::runCommand(SocketClient *cli,
456                                                      int argc, char **argv) {
457    if (argc < 2) {
458        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
459        return 0;
460    }
461
462    VolumeManager *vm = VolumeManager::Instance();
463    int rc = 0;
464
465    if (!strcmp(argv[1], "list")) {
466        dumpArgs(argc, argv, -1);
467
468        rc = vm->listMountedObbs(cli);
469    } else if (!strcmp(argv[1], "mount")) {
470            dumpArgs(argc, argv, 3);
471            if (argc != 5) {
472                cli->sendMsg(ResponseCode::CommandSyntaxError,
473                        "Usage: obb mount <filename> <key> <ownerGid>", false);
474                return 0;
475            }
476            rc = vm->mountObb(argv[2], argv[3], atoi(argv[4]));
477    } else if (!strcmp(argv[1], "unmount")) {
478        dumpArgs(argc, argv, -1);
479        if (argc < 3) {
480            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb unmount <source file> [force]", false);
481            return 0;
482        }
483        bool force = false;
484        if (argc > 3 && !strcmp(argv[3], "force")) {
485            force = true;
486        }
487        rc = vm->unmountObb(argv[2], force);
488    } else if (!strcmp(argv[1], "path")) {
489        dumpArgs(argc, argv, -1);
490        if (argc != 3) {
491            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb path <source file>", false);
492            return 0;
493        }
494        char path[255];
495
496        if (!(rc = vm->getObbMountPath(argv[2], path, sizeof(path)))) {
497            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
498            return 0;
499        }
500    } else {
501        dumpArgs(argc, argv, -1);
502        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown obb cmd", false);
503    }
504
505    if (!rc) {
506        cli->sendMsg(ResponseCode::CommandOkay, "obb operation succeeded", false);
507    } else {
508        rc = ResponseCode::convertFromErrno();
509        cli->sendMsg(rc, "obb operation failed", true);
510    }
511
512    return 0;
513}
514
515CommandListener::XwarpCmd::XwarpCmd() :
516                 VoldCommand("xwarp") {
517}
518
519int CommandListener::XwarpCmd::runCommand(SocketClient *cli,
520                                                      int argc, char **argv) {
521    if (argc < 2) {
522        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
523        return 0;
524    }
525
526    if (!strcmp(argv[1], "enable")) {
527        if (Xwarp::enable()) {
528            cli->sendMsg(ResponseCode::OperationFailed, "Failed to enable xwarp", true);
529            return 0;
530        }
531
532        cli->sendMsg(ResponseCode::CommandOkay, "Xwarp mirroring started", false);
533    } else if (!strcmp(argv[1], "disable")) {
534        if (Xwarp::disable()) {
535            cli->sendMsg(ResponseCode::OperationFailed, "Failed to disable xwarp", true);
536            return 0;
537        }
538
539        cli->sendMsg(ResponseCode::CommandOkay, "Xwarp disabled", false);
540    } else if (!strcmp(argv[1], "status")) {
541        char msg[255];
542        bool r;
543        unsigned mirrorPos, maxSize;
544
545        if (Xwarp::status(&r, &mirrorPos, &maxSize)) {
546            cli->sendMsg(ResponseCode::OperationFailed, "Failed to get xwarp status", true);
547            return 0;
548        }
549        snprintf(msg, sizeof(msg), "%s %u %u", (r ? "ready" : "not-ready"), mirrorPos, maxSize);
550        cli->sendMsg(ResponseCode::XwarpStatusResult, msg, false);
551    } else {
552        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
553    }
554
555    return 0;
556}
557
558CommandListener::CryptfsCmd::CryptfsCmd() :
559                 VoldCommand("cryptfs") {
560}
561
562int CommandListener::CryptfsCmd::runCommand(SocketClient *cli,
563                                                      int argc, char **argv) {
564    if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
565        cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run cryptfs commands", false);
566        return 0;
567    }
568
569    if (argc < 2) {
570        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
571        return 0;
572    }
573
574    int rc = 0;
575
576    if (!strcmp(argv[1], "checkpw")) {
577        if (argc != 3) {
578            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs checkpw <passwd>", false);
579            return 0;
580        }
581        dumpArgs(argc, argv, 2);
582        rc = cryptfs_check_passwd(argv[2]);
583    } else if (!strcmp(argv[1], "restart")) {
584        if (argc != 2) {
585            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs restart", false);
586            return 0;
587        }
588        dumpArgs(argc, argv, -1);
589        rc = cryptfs_restart();
590    } else if (!strcmp(argv[1], "cryptocomplete")) {
591        if (argc != 2) {
592            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs cryptocomplete", false);
593            return 0;
594        }
595        dumpArgs(argc, argv, -1);
596        rc = cryptfs_crypto_complete();
597    } else if (!strcmp(argv[1], "enablecrypto")) {
598        if ( (argc != 4) || (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace")) ) {
599            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs enablecrypto <wipe|inplace> <passwd>", false);
600            return 0;
601        }
602        dumpArgs(argc, argv, 3);
603        rc = cryptfs_enable(argv[2], argv[3]);
604    } else if (!strcmp(argv[1], "changepw")) {
605        if (argc != 3) {
606            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs changepw <newpasswd>", false);
607            return 0;
608        }
609        SLOGD("cryptfs changepw {}");
610        rc = cryptfs_changepw(argv[2]);
611    } else if (!strcmp(argv[1], "verifypw")) {
612        if (argc != 3) {
613            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs verifypw <passwd>", false);
614            return 0;
615        }
616        SLOGD("cryptfs verifypw {}");
617        rc = cryptfs_verify_passwd(argv[2]);
618    } else if (!strcmp(argv[1], "getfield")) {
619        char valbuf[PROPERTY_VALUE_MAX];
620
621        if (argc != 3) {
622            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs getfield <fieldname>", false);
623            return 0;
624        }
625        dumpArgs(argc, argv, -1);
626        rc = cryptfs_getfield(argv[2], valbuf, sizeof(valbuf));
627        if (rc == 0) {
628            cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
629        }
630    } else if (!strcmp(argv[1], "setfield")) {
631        if (argc != 4) {
632            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs setfield <fieldname> <value>", false);
633            return 0;
634        }
635        dumpArgs(argc, argv, -1);
636        rc = cryptfs_setfield(argv[2], argv[3]);
637    } else {
638        dumpArgs(argc, argv, -1);
639        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false);
640    }
641
642    // Always report that the command succeeded and return the error code.
643    // The caller will check the return value to see what the error was.
644    char msg[255];
645    snprintf(msg, sizeof(msg), "%d", rc);
646    cli->sendMsg(ResponseCode::CommandOkay, msg, false);
647
648    return 0;
649}
650
651CommandListener::FstrimCmd::FstrimCmd() :
652                 VoldCommand("fstrim") {
653}
654int CommandListener::FstrimCmd::runCommand(SocketClient *cli,
655                                                      int argc, char **argv) {
656    if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
657        cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run fstrim commands", false);
658        return 0;
659    }
660
661    if (argc < 2) {
662        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
663        return 0;
664    }
665
666    int rc = 0;
667
668    if (!strcmp(argv[1], "dotrim")) {
669        if (argc != 2) {
670            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: fstrim dotrim", false);
671            return 0;
672        }
673        dumpArgs(argc, argv, -1);
674        rc = fstrim_filesystems();
675    } else {
676        dumpArgs(argc, argv, -1);
677        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown fstrim cmd", false);
678    }
679
680    // Always report that the command succeeded and return the error code.
681    // The caller will check the return value to see what the error was.
682    char msg[255];
683    snprintf(msg, sizeof(msg), "%d", rc);
684    cli->sendMsg(ResponseCode::CommandOkay, msg, false);
685
686    return 0;
687}
688