1 /*
2  * Copyright (C) 2016 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 #define LOG_TAG "nanoapp_cmd"
18 
19 #include <assert.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <inttypes.h>
23 #include <signal.h>
24 #include <stdbool.h>
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <sys/stat.h>
29 #include <sys/types.h>
30 #include <string.h>
31 #include <unistd.h>
32 
33 #include <android/log.h>
34 
35 #include <nanohub/nanohub.h>
36 #include <eventnums.h>
37 #include <sensType.h>
38 
39 #define SENSOR_RATE_ONCHANGE    0xFFFFFF01UL
40 #define SENSOR_RATE_ONESHOT     0xFFFFFF02UL
41 #define SENSOR_HZ(_hz)          ((uint32_t)((_hz) * 1024.0f))
42 #define MAX_APP_NAME_LEN        32
43 #define MAX_INSTALL_CNT         8
44 #define MAX_UNINSTALL_CNT       8
45 #define MAX_DOWNLOAD_RETRIES    4
46 #define UNINSTALL_CMD           "uninstall"
47 
48 #define NANOHUB_HAL_EXT_APPS_ON     0
49 #define NANOHUB_HAL_EXT_APPS_OFF    1
50 #define NANOHUB_HAL_EXT_APP_DELETE  2
51 
52 #define LOGE(fmt, ...) do { \
53         __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##__VA_ARGS__); \
54         printf(fmt "\n", ##__VA_ARGS__); \
55     } while (0)
56 
57 enum ConfigCmds
58 {
59     CONFIG_CMD_DISABLE      = 0,
60     CONFIG_CMD_ENABLE       = 1,
61     CONFIG_CMD_FLUSH        = 2,
62     CONFIG_CMD_CFG_DATA     = 3,
63     CONFIG_CMD_CALIBRATE    = 4,
64 };
65 
66 struct ConfigCmd
67 {
68     uint32_t evtType;
69     uint64_t latency;
70     uint32_t rate;
71     uint8_t sensorType;
72     uint8_t cmd;
73     uint16_t flags;
74     uint8_t data[];
75 } __attribute__((packed));
76 
77 struct HalCmd
78 {
79     struct HostMsgHdr hdr;
80     uint8_t cmd;
81     uint64_t appId;
82 } __attribute__((packed));
83 
84 struct App
85 {
86     uint32_t num;
87     uint64_t id;
88     uint32_t version;
89     uint32_t size;
90 };
91 
92 struct LedsCfg {
93     uint32_t led_num;
94     uint32_t value;
95 } __attribute__((packed));
96 
setType(struct ConfigCmd * cmd,char * sensor)97 static int setType(struct ConfigCmd *cmd, char *sensor)
98 {
99     if (strcmp(sensor, "accel") == 0) {
100         cmd->sensorType = SENS_TYPE_ACCEL;
101     } else if (strcmp(sensor, "gyro") == 0) {
102         cmd->sensorType = SENS_TYPE_GYRO;
103     } else if (strcmp(sensor, "mag") == 0) {
104         cmd->sensorType = SENS_TYPE_MAG;
105     } else if (strcmp(sensor, "uncal_accel") == 0) {
106         cmd->sensorType = SENS_TYPE_ACCEL;
107     } else if (strcmp(sensor, "uncal_gyro") == 0) {
108         cmd->sensorType = SENS_TYPE_GYRO;
109     } else if (strcmp(sensor, "uncal_mag") == 0) {
110         cmd->sensorType = SENS_TYPE_MAG;
111     } else if (strcmp(sensor, "als") == 0) {
112         cmd->sensorType = SENS_TYPE_ALS;
113     } else if (strcmp(sensor, "prox") == 0) {
114         cmd->sensorType = SENS_TYPE_PROX;
115     } else if (strcmp(sensor, "baro") == 0) {
116         cmd->sensorType = SENS_TYPE_BARO;
117     } else if (strcmp(sensor, "temp") == 0) {
118         cmd->sensorType = SENS_TYPE_TEMP;
119     } else if (strcmp(sensor, "ambient_temp") == 0) {
120         cmd->sensorType = SENS_TYPE_AMBIENT_TEMP;
121     } else if (strcmp(sensor, "orien") == 0) {
122         cmd->sensorType = SENS_TYPE_ORIENTATION;
123     } else if (strcmp(sensor, "gravity") == 0) {
124         cmd->sensorType = SENS_TYPE_GRAVITY;
125     } else if (strcmp(sensor, "geomag") == 0) {
126         cmd->sensorType = SENS_TYPE_GEO_MAG_ROT_VEC;
127     } else if (strcmp(sensor, "linear_acc") == 0) {
128         cmd->sensorType = SENS_TYPE_LINEAR_ACCEL;
129     } else if (strcmp(sensor, "rotation") == 0) {
130         cmd->sensorType = SENS_TYPE_ROTATION_VECTOR;
131     } else if (strcmp(sensor, "game") == 0) {
132         cmd->sensorType = SENS_TYPE_GAME_ROT_VECTOR;
133     } else if (strcmp(sensor, "win_orien") == 0) {
134         cmd->sensorType = SENS_TYPE_WIN_ORIENTATION;
135         cmd->rate = SENSOR_RATE_ONCHANGE;
136     } else if (strcmp(sensor, "tilt") == 0) {
137         cmd->sensorType = SENS_TYPE_TILT;
138         cmd->rate = SENSOR_RATE_ONCHANGE;
139     } else if (strcmp(sensor, "step_det") == 0) {
140         cmd->sensorType = SENS_TYPE_STEP_DETECT;
141         cmd->rate = SENSOR_RATE_ONCHANGE;
142     } else if (strcmp(sensor, "step_cnt") == 0) {
143         cmd->sensorType = SENS_TYPE_STEP_COUNT;
144         cmd->rate = SENSOR_RATE_ONCHANGE;
145     } else if (strcmp(sensor, "double_tap") == 0) {
146         cmd->sensorType = SENS_TYPE_DOUBLE_TAP;
147         cmd->rate = SENSOR_RATE_ONCHANGE;
148     } else if (strcmp(sensor, "flat") == 0) {
149         cmd->sensorType = SENS_TYPE_FLAT;
150         cmd->rate = SENSOR_RATE_ONCHANGE;
151     } else if (strcmp(sensor, "anymo") == 0) {
152         cmd->sensorType = SENS_TYPE_ANY_MOTION;
153         cmd->rate = SENSOR_RATE_ONCHANGE;
154     } else if (strcmp(sensor, "nomo") == 0) {
155         cmd->sensorType = SENS_TYPE_NO_MOTION;
156         cmd->rate = SENSOR_RATE_ONCHANGE;
157     } else if (strcmp(sensor, "sigmo") == 0) {
158         cmd->sensorType = SENS_TYPE_SIG_MOTION;
159         cmd->rate = SENSOR_RATE_ONESHOT;
160     } else if (strcmp(sensor, "gesture") == 0) {
161         cmd->sensorType = SENS_TYPE_GESTURE;
162         cmd->rate = SENSOR_RATE_ONESHOT;
163     } else if (strcmp(sensor, "hall") == 0) {
164         cmd->sensorType = SENS_TYPE_HALL;
165         cmd->rate = SENSOR_RATE_ONCHANGE;
166     } else if (strcmp(sensor, "vsync") == 0) {
167         cmd->sensorType = SENS_TYPE_VSYNC;
168         cmd->rate = SENSOR_RATE_ONCHANGE;
169     } else if (strcmp(sensor, "activity") == 0) {
170         cmd->sensorType = SENS_TYPE_ACTIVITY;
171         cmd->rate = SENSOR_RATE_ONCHANGE;
172     } else if (strcmp(sensor, "twist") == 0) {
173         cmd->sensorType = SENS_TYPE_DOUBLE_TWIST;
174         cmd->rate = SENSOR_RATE_ONCHANGE;
175     } else if (strcmp(sensor, "leds") == 0) {
176         cmd->sensorType = SENS_TYPE_LEDS;
177     } else if (strcmp(sensor, "leds_i2c") == 0) {
178         cmd->sensorType = SENS_TYPE_LEDS_I2C;
179     } else if (strcmp(sensor, "humidity") == 0) {
180         cmd->sensorType = SENS_TYPE_HUMIDITY;
181     } else {
182         return 1;
183     }
184 
185     return 0;
186 }
187 
188 bool drain = false;
189 bool stop = false;
190 char *buf;
191 int nread, buf_size = 2048;
192 struct App apps[32];
193 uint8_t appCount;
194 char appsToInstall[MAX_INSTALL_CNT][MAX_APP_NAME_LEN+1];
195 uint64_t appsToUninstall[MAX_UNINSTALL_CNT];
196 
sig_handle(int sig)197 void sig_handle(__attribute__((unused)) int sig)
198 {
199     assert(sig == SIGINT);
200     printf("Terminating...\n");
201     stop = true;
202 }
203 
openFile(const char * fname,const char * mode)204 FILE *openFile(const char *fname, const char *mode)
205 {
206     FILE *f = fopen(fname, mode);
207     if (f == NULL) {
208         LOGE("Failed to open %s: err=%d [%s]", fname, errno, strerror(errno));
209     }
210     return f;
211 }
212 
parseInstalledAppInfo()213 void parseInstalledAppInfo()
214 {
215     FILE *fp;
216     char *line = NULL;
217     size_t len;
218     ssize_t numRead;
219 
220     appCount = 0;
221 
222     fp = openFile("/sys/class/nanohub/nanohub/app_info", "r");
223     if (!fp)
224         return;
225 
226     while ((numRead = getline(&line, &len, fp)) != -1) {
227         struct App *currApp = &apps[appCount++];
228         sscanf(line, "app: %d id: %" PRIx64 " ver: %" PRIx32 " size: %" PRIx32 "\n", &currApp->num, &currApp->id, &currApp->version, &currApp->size);
229     }
230 
231     fclose(fp);
232 
233     if (line)
234         free(line);
235 }
236 
findApp(uint64_t appId)237 struct App *findApp(uint64_t appId)
238 {
239     uint8_t i;
240 
241     for (i = 0; i < appCount; i++) {
242         if (apps[i].id == appId) {
243             return &apps[i];
244         }
245     }
246 
247     return NULL;
248 }
249 
findAppIdByName(char * name,uint64_t * appId)250 int findAppIdByName(char *name, uint64_t *appId)
251 {
252     FILE *fp;
253     char *line = NULL;
254     size_t len;
255     ssize_t numRead;
256     int ret = 0;
257 
258     fp = openFile("/vendor/firmware/napp_list.cfg", "r");
259     if (!fp)
260         return -1;
261 
262     while ((numRead = getline(&line, &len, fp)) != -1) {
263         char entry[MAX_APP_NAME_LEN+1];
264         uint32_t appVersion;
265 
266         sscanf(line, "%" STRINGIFY(MAX_APP_NAME_LEN) "s %" PRIx64 " %" PRIx32 "\n", entry, appId, &appVersion);
267 
268         if (strncmp(entry, name, MAX_APP_NAME_LEN) == 0) {
269             ret = 1;
270             break;
271         }
272     }
273 
274     fclose(fp);
275 
276     if (line)
277         free(line);
278 
279     return ret;
280 }
281 
parseConfigAppInfo(int * installCnt,int * uninstallCnt)282 int parseConfigAppInfo(int *installCnt, int *uninstallCnt)
283 {
284     FILE *fp;
285     char *line = NULL;
286     size_t len;
287     ssize_t numRead;
288 
289     fp = openFile("/vendor/firmware/napp_list.cfg", "r");
290     if (!fp)
291         return -1;
292 
293     parseInstalledAppInfo();
294 
295     *installCnt = *uninstallCnt = 0;
296     while (((numRead = getline(&line, &len, fp)) != -1) && (*installCnt < MAX_INSTALL_CNT) && (*uninstallCnt < MAX_UNINSTALL_CNT)) {
297         uint64_t appId;
298         uint32_t appVersion;
299         struct App *installedApp;
300 
301         sscanf(line, "%" STRINGIFY(MAX_APP_NAME_LEN) "s %" PRIx64 " %" PRIx32 "\n", appsToInstall[*installCnt], &appId, &appVersion);
302 
303         installedApp = findApp(appId);
304         if (strncmp(appsToInstall[*installCnt], UNINSTALL_CMD, MAX_APP_NAME_LEN) == 0) {
305             if (installedApp) {
306                 appsToUninstall[*uninstallCnt] = appId;
307                 (*uninstallCnt)++;
308             }
309         } else if (!installedApp || (installedApp->version < appVersion)) {
310             (*installCnt)++;
311         }
312     }
313 
314     fclose(fp);
315 
316     if (line)
317         free(line);
318 
319     return *installCnt + *uninstallCnt;
320 }
321 
fileWriteData(const char * fname,const void * data,size_t size)322 bool fileWriteData(const char *fname, const void *data, size_t size)
323 {
324     int fd;
325     bool result;
326 
327     fd = open(fname, O_WRONLY);
328     if (fd < 0) {
329         LOGE("Failed to open %s: err=%d [%s]", fname, errno, strerror(errno));
330         return false;
331     }
332 
333     result = true;
334     if ((size_t)write(fd, data, size) != size) {
335         LOGE("Failed to write to %s; err=%d [%s]", fname, errno, strerror(errno));
336         result = false;
337     }
338     close(fd);
339 
340     return result;
341 }
342 
downloadNanohub()343 void downloadNanohub()
344 {
345     char c = '1';
346 
347     printf("Updating nanohub OS [if required]...");
348     fflush(stdout);
349     if (fileWriteData("/sys/class/nanohub/nanohub/download_bl", &c, sizeof(c)))
350         printf("done\n");
351 }
352 
sendCmd(uint8_t cmd,uint64_t appId)353 bool sendCmd(uint8_t cmd, uint64_t appId)
354 {
355     struct HalCmd msg;
356 
357     msg.hdr.eventId = EVT_APP_FROM_HOST;
358     msg.hdr.appId = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0);
359     msg.hdr.len = sizeof(msg) - sizeof(msg.hdr); // payload length
360     msg.cmd = cmd;
361     memcpy(&msg.appId, &appId, sizeof(uint64_t));
362 
363     return fileWriteData("/dev/nanohub", &msg, sizeof(msg));
364 }
365 
halCmd(uint8_t cmd,char * arg)366 int halCmd(uint8_t cmd, char *arg)
367 {
368     uint64_t appId;
369     char *endptr = arg + strlen(arg);
370 
371     if (strcmp(arg, UNINSTALL_CMD) == 0) {
372         printf("%s is not a valid app name\n", arg);
373         return 1;
374     }
375 
376     if ((findAppIdByName(arg, &appId) == 1) || (appId = strtoull(arg, &endptr, 16)) > 0) {
377         if (*endptr != '\0') {
378             printf("Couldn't find nanoapp '%s' in napp_list.cfg\n", arg);
379             return 1;
380         } else if (cmd == NANOHUB_HAL_EXT_APPS_ON)
381             printf("Loading ");
382         else if (cmd == NANOHUB_HAL_EXT_APPS_OFF)
383             printf("Unloading ");
384         else if (cmd == NANOHUB_HAL_EXT_APP_DELETE)
385             printf("Deleting ");
386         else {
387             printf("Unrecognized cmd: %d\n", cmd);
388             return 1;
389         }
390         printf("\"0x%016" PRIx64 "\"...", appId);
391         fflush(stdout);
392         if (sendCmd(cmd, appId))
393             printf("done\n");
394         return 0;
395     } else {
396         printf("Couldn't find nanoapp '%s' in napp_list.cfg\n", arg);
397         return 1;
398     }
399 }
400 
removeApps(int updateCnt)401 void removeApps(int updateCnt)
402 {
403     int i;
404 
405     for (i = 0; i < updateCnt; i++) {
406         printf("Deleting \"0x%016" PRIx64 "\"...", appsToUninstall[i]);
407         fflush(stdout);
408         if (sendCmd(NANOHUB_HAL_EXT_APP_DELETE, appsToUninstall[i]))
409             printf("done\n");
410     }
411 }
412 
downloadApps(int updateCnt)413 void downloadApps(int updateCnt)
414 {
415     int i;
416 
417     for (i = 0; i < updateCnt; i++) {
418         printf("Downloading \"%s.napp\"...", appsToInstall[i]);
419         fflush(stdout);
420         if (fileWriteData("/sys/class/nanohub/nanohub/download_app", appsToInstall[i], strlen(appsToInstall[i])))
421             printf("done\n");
422     }
423 }
424 
eraseSharedArea()425 void eraseSharedArea()
426 {
427     char c = '1';
428 
429     printf("Erasing entire nanohub shared area...");
430     fflush(stdout);
431     if (fileWriteData("/sys/class/nanohub/nanohub/erase_shared", &c, sizeof(c)))
432         printf("done\n");
433 }
434 
resetHub()435 void resetHub()
436 {
437     char c = '1';
438 
439     printf("Resetting nanohub...");
440     fflush(stdout);
441     if (fileWriteData("/sys/class/nanohub/nanohub/reset", &c, sizeof(c)))
442         printf("done\n");
443 }
444 
main(int argc,char * argv[])445 int main(int argc, char *argv[])
446 {
447     struct ConfigCmd mConfigCmd;
448     struct ConfigCmd *pConfigCmd = &mConfigCmd;
449     size_t length = sizeof(mConfigCmd);
450     int fd;
451     int i;
452 
453     if (argc < 3 && (argc < 2 || strcmp(argv[1], "download") != 0)) {
454         printf("usage: %s <action> <sensor> <data> -d\n", argv[0]);
455         printf("       action: config|cfgdata|calibrate|flush\n");
456         printf("       sensor: (uncal_)accel|(uncal_)gyro|(uncal_)mag|als|prox|baro|temp|orien\n");
457         printf("               gravity|geomag|linear_acc|rotation|game\n");
458         printf("               win_orien|tilt|step_det|step_cnt|double_tap\n");
459         printf("               flat|anymo|nomo|sigmo|gesture|hall|vsync\n");
460         printf("               activity|twist|leds|leds_i2c|humidity|ambient_temp\n");
461         printf("       data: config: <true|false> <rate in Hz> <latency in u-sec>\n");
462         printf("             cfgdata: leds: led_num value\n");
463         printf("             calibrate: [N.A.]\n");
464         printf("             flush: [N.A.]\n");
465         printf("       -d: if specified, %s will keep draining /dev/nanohub until cancelled.\n", argv[0]);
466         printf("usage: %s <cmd> [app]\n", argv[0]);
467         printf("       cmd: download|load|unload|delete\n");
468         printf("       app: appId or name from napp_list.cfg\n");
469 
470         return 1;
471     }
472 
473     if (strcmp(argv[1], "config") == 0) {
474         if (argc != 6 && argc != 7) {
475             printf("Wrong arg number\n");
476             return 1;
477         }
478         if (argc == 7) {
479             if(strcmp(argv[6], "-d") == 0) {
480                 drain = true;
481             } else {
482                 printf("Last arg unsupported, ignored.\n");
483             }
484         }
485         if (strcmp(argv[3], "true") == 0)
486             mConfigCmd.cmd = CONFIG_CMD_ENABLE;
487         else if (strcmp(argv[3], "false") == 0) {
488             mConfigCmd.cmd = CONFIG_CMD_DISABLE;
489         } else {
490             printf("Unsupported data: %s For action: %s\n", argv[3], argv[1]);
491             return 1;
492         }
493         mConfigCmd.evtType = EVT_NO_SENSOR_CONFIG_EVENT;
494         mConfigCmd.rate = SENSOR_HZ((float)atoi(argv[4]));
495         mConfigCmd.latency = atoi(argv[5]) * 1000ull;
496         if (setType(&mConfigCmd, argv[2])) {
497             printf("Unsupported sensor: %s For action: %s\n", argv[2], argv[1]);
498             return 1;
499         }
500     } else if (strcmp(argv[1], "cfgdata") == 0) {
501         mConfigCmd.evtType = EVT_NO_SENSOR_CONFIG_EVENT;
502         mConfigCmd.rate = 0;
503         mConfigCmd.latency = 0;
504         mConfigCmd.cmd = CONFIG_CMD_CFG_DATA;
505         if (setType(&mConfigCmd, argv[2])) {
506             printf("Unsupported sensor: %s For action: %s\n", argv[2], argv[1]);
507             return 1;
508         }
509         if (mConfigCmd.sensorType == SENS_TYPE_LEDS ||
510             mConfigCmd.sensorType == SENS_TYPE_LEDS_I2C) {
511             struct LedsCfg mLedsCfg;
512 
513             if (argc != 5) {
514                 printf("Wrong arg number\n");
515                 return 1;
516             }
517             length = sizeof(struct ConfigCmd) + sizeof(struct LedsCfg *);
518             pConfigCmd = (struct ConfigCmd *)malloc(length);
519             if (!pConfigCmd)
520                 return 1;
521             mLedsCfg.led_num = atoi(argv[3]);
522             mLedsCfg.value = atoi(argv[4]);
523             memcpy(pConfigCmd, &mConfigCmd, sizeof(mConfigCmd));
524             memcpy(pConfigCmd->data, &mLedsCfg, sizeof(mLedsCfg));
525         } else {
526             printf("Unsupported sensor: %s For action: %s\n", argv[2], argv[1]);
527             return 1;
528         }
529     } else if (strcmp(argv[1], "calibrate") == 0) {
530         if (argc != 3) {
531             printf("Wrong arg number\n");
532             return 1;
533         }
534         mConfigCmd.evtType = EVT_NO_SENSOR_CONFIG_EVENT;
535         mConfigCmd.rate = 0;
536         mConfigCmd.latency = 0;
537         mConfigCmd.cmd = CONFIG_CMD_CALIBRATE;
538         if (setType(&mConfigCmd, argv[2])) {
539             printf("Unsupported sensor: %s For action: %s\n", argv[2], argv[1]);
540             return 1;
541         }
542     } else if (strcmp(argv[1], "flush") == 0) {
543         if (argc != 3) {
544             printf("Wrong arg number\n");
545             return 1;
546         }
547         mConfigCmd.evtType = EVT_NO_SENSOR_CONFIG_EVENT;
548         mConfigCmd.rate = 0;
549         mConfigCmd.latency = 0;
550         mConfigCmd.cmd = CONFIG_CMD_FLUSH;
551         if (setType(&mConfigCmd, argv[2])) {
552             printf("Unsupported sensor: %s For action: %s\n", argv[2], argv[1]);
553             return 1;
554         }
555     } else if (strcmp(argv[1], "load") == 0) {
556         if (argc != 3) {
557             printf("Wrong arg number\n");
558             return 1;
559         }
560 
561         return halCmd(NANOHUB_HAL_EXT_APPS_ON, argv[2]);
562     } else if (strcmp(argv[1], "unload") == 0) {
563         if (argc != 3) {
564             printf("Wrong arg number\n");
565             return 1;
566         }
567 
568         return halCmd(NANOHUB_HAL_EXT_APPS_OFF, argv[2]);
569     } else if (strcmp(argv[1], "delete") == 0) {
570         if (argc != 3) {
571             printf("Wrong arg number\n");
572             return 1;
573         }
574 
575         return halCmd(NANOHUB_HAL_EXT_APP_DELETE, argv[2]);
576     } else if (strcmp(argv[1], "download") == 0) {
577         int installCnt, uninstallCnt;
578 
579         if (argc != 2) {
580             printf("Wrong arg number\n");
581             return 1;
582         }
583         downloadNanohub();
584         for (i = 0; i < MAX_DOWNLOAD_RETRIES; i++) {
585             int updateCnt = parseConfigAppInfo(&installCnt, &uninstallCnt);
586             if (updateCnt > 0) {
587                 if (i == MAX_DOWNLOAD_RETRIES - 1) {
588                     LOGE("Download failed after %d retries; erasing all apps "
589                          "before final attempt", i);
590                     eraseSharedArea();
591                     parseConfigAppInfo(&installCnt, &uninstallCnt);
592                 }
593                 removeApps(uninstallCnt);
594                 downloadApps(installCnt);
595                 resetHub();
596             } else if (!updateCnt){
597                 return 0;
598             }
599         }
600 
601         if (parseConfigAppInfo(&installCnt, &uninstallCnt) != 0) {
602             LOGE("Failed to download all apps!");
603             return 1;
604         }
605         return 0;
606     } else {
607         printf("Unsupported action: %s\n", argv[1]);
608         return 1;
609     }
610 
611     while (!fileWriteData("/dev/nanohub", pConfigCmd, length))
612         continue;
613 
614     if (pConfigCmd != &mConfigCmd)
615         free(pConfigCmd);
616 
617     if (drain) {
618         signal(SIGINT, sig_handle);
619         fd = open("/dev/nanohub", O_RDONLY);
620         while (!stop) {
621             (void) read(fd, buf, buf_size);
622         }
623         close(fd);
624     }
625     return 0;
626 }
627