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