static int ui_cmd_msetenv(ui_cmdline_t *cmd,int argc,char *argv[]) { char *varname; char *value; int roflag = ENV_FLG_NORMAL; int res; varname = cmd_getarg(cmd,0); if (!varname) { return ui_showusage(cmd); } value = cmd_getarg(cmd,1); if (!value) { return ui_showusage(cmd); } if (!cmd_sw_isset(cmd,"-p")) { roflag = ENV_FLG_BUILTIN; /* just in memory, not NVRAM */ } if ((res = carmel_setenv(varname,value,roflag)) == 0) { if (roflag != ENV_FLG_BUILTIN) carmel_saveenv(); } else { return ui_showerror(res,"Could not set Monterey environment variable '%s'", varname); } return 0; }
static int ui_cmd_readnvram(ui_cmdline_t *cmd,int argc,char *argv[]) { char *dev; char *tok; int fd; int offset = 0; int res; uint8_t buf[512]; int idx; dev = cmd_getarg(cmd,0); if (!dev) return ui_showusage(cmd); tok = cmd_getarg(cmd,1); if (tok) offset = xtoi(tok); else offset = 0; fd = cfe_open(dev); if (fd < 0) { ui_showerror(fd,"could not open NVRAM"); return fd; } res = cfe_readblk(fd,offset,buf,512); printf("Offset %d Result %d\n",offset,res); for (idx = 0; idx < 512; idx++) { if ((idx % 16) == 0) printf("\n"); printf("%02X ",buf[idx]); } printf("\n"); cfe_close(fd); return 0; }
static int ui_cmd_erasenvram(ui_cmdline_t *cmd,int argc,char *argv[]) { char *dev; int fd; uint8_t buffer[2048]; int res; char *tok; int offset; int length; uint8_t data; dev = cmd_getarg(cmd,0); if (!dev) return ui_showusage(cmd); offset = 0; if ((tok = cmd_getarg(cmd,1))) offset = xtoi(tok); length = 512; if ((tok = cmd_getarg(cmd,2))) length = xtoi(tok); if (length > 2048) length = 2048; data = 0xFF; if ((tok = cmd_getarg(cmd,3))) data = xtoi(tok); fd = cfe_open(dev); if (fd < 0) { ui_showerror(fd,"could not open NVRAM"); return fd; } if (cmd_sw_isset(cmd,"-pattern")) { memset(buffer,0,sizeof(buffer)); for (res = 0; res < 2048; res++) { buffer[res] = res & 0xFF; } } else memset(buffer,data,sizeof(buffer)); printf("Fill offset %04X length %04X\n",offset,length); res = cfe_writeblk(fd,offset,buffer,length); printf("write returned %d\n",res); cfe_close(fd); return 0; }
static int ui_cmd_settime(ui_cmdline_t *cmd,int argc,char *argv[]) { char *line; char *p; int hr,min,sec; int fd; uint8_t buf[12]; int res=0; if ((line = cmd_getarg(cmd,0)) == NULL) { return ui_showusage(cmd); } /* convert colons to spaces for the gettoken routine */ while ((p = strchr(line,':'))) *p = ' '; /* parse and check command-line args */ hr = -1; min = -1; sec = -1; p = gettoken(&line); if (p) hr = atoi(p); p = gettoken(&line); if (p) min = atoi(p); p = gettoken(&line); if (p) sec = atoi(p); if ((hr < 0) || (hr > 23) || (min < 0) || (min >= 60) || (sec < 0) || (sec >= 60)) { return ui_showusage(cmd); } /* * hour-minute-second-month-day-year1-year2-(time/date flag) * time/date flag (offset 7) is used to let device know what * is being set. */ buf[0] = hr; buf[1] = min; buf[2] = sec; buf[7] = 0x00; /*SET_TIME = 0x00, SET_DATE = 0x01*/ fd = cfe_open("clock0"); if (fd < 0) { ui_showerror(fd,"could not open clock device"); return fd; } res = cfe_write(fd,buf,8); if (res < 0) { ui_showerror(res,"could not set time"); } cfe_close(fd); return 0; }
static int ui_cmd_bootcommon(ui_cmdline_t *cmd,int argc,char *argv[],int flags) { int res; char *arg; cfe_loadargs_t *la = &cfe_loadargs; char copy[200]; la->la_flags = flags; arg = cmd_getarg(cmd,0); strncpy(copy,arg,sizeof(copy)); if (!arg) { xprintf("No program name specified\n"); return -1; } res = ui_process_url(arg,cmd,la); if (res < 0) return res; /* * Pick up the remaining command line parameters for use as * arguments to the loaded program. */ la->la_options = cmd_getarg(cmd,1); /* * Note: we might not come back here if we really launch the program. */ xprintf("Loader:%s Filesys:%s Dev:%s File:%s Options:%s\n", la->la_loader,la->la_filesys,la->la_device,la->la_filename,la->la_options); res = cfe_boot(la->la_loader,la); /* * Give the bad news. */ if (res < 0) xprintf("Could not load %s: %s\n",copy,cfe_errortext(res)); return res; }
static int ui_cmd_autoboot(ui_cmdline_t *cmd,int argc,char *argv[]) { int res; char *x; int flags = 0; if (cmd_sw_isset(cmd,"-forever")) flags |= CFE_AUTOFLG_TRYFOREVER; if (cmd_sw_isset(cmd,"-interruptible")) flags |= CFE_AUTOFLG_POLLCONSOLE; x = cmd_getarg(cmd,0); res = cfe_autoboot(x,flags); return res; }
static int ui_cmd_save(ui_cmdline_t *cmd,int argc,char *argv[]) { char *x; uint8_t *start,*end; int len; char *fname; int res; fname = cmd_getarg(cmd,0); if ((x = cmd_getarg(cmd,1))) { start = (uint8_t *) getaddr(x); } else { return ui_showusage(cmd); } if ((x = cmd_getarg(cmd,2))) { len = xtoi(x); } else { return ui_showusage(cmd); } end = start+len; res = cfe_savedata("tftp","",fname,start,end); if (res < 0) { return ui_showerror(res,"Could not dump data to network"); } else { xprintf("%d bytes written to %s\n",res,fname); } return 0; }
static int ui_cmd_cpu1(ui_cmdline_t *cmd,int argc,char *argv[]) { cfe_iocb_t iocb; int res = 0; char *a; char *x; a = cmd_getarg(cmd,0); if (!a) a = ""; iocb.iocb_fcode = CFE_CMD_FW_CPUCTL; iocb.iocb_status = 0; iocb.iocb_handle = 0; iocb.iocb_flags = 0; iocb.iocb_psize = sizeof(iocb_cpuctl_t); if (strcmp(a,"start") == 0) { iocb.plist.iocb_cpuctl.cpu_number = 1; iocb.plist.iocb_cpuctl.cpu_command = CFE_CPU_CMD_START; if (cmd_sw_value(cmd,"-a1",&x)) iocb.plist.iocb_cpuctl.gp_val = (cfe_uint_t) xtoq(x); else iocb.plist.iocb_cpuctl.gp_val = 0xFEEDFACE; if (cmd_sw_value(cmd,"-sp",&x)) iocb.plist.iocb_cpuctl.sp_val = (cfe_uint_t) xtoq(x); iocb.plist.iocb_cpuctl.sp_val = 0x12345678; if (cmd_sw_value(cmd,"-addr",&x)) iocb.plist.iocb_cpuctl.start_addr = (cfe_uint_t) xtoq(x); iocb.plist.iocb_cpuctl.start_addr = (cfe_uint_t) cpu1proc; xprintf("Starting CPU 1 at %p\n",iocb.plist.iocb_cpuctl.start_addr); res = cfe_iocb_dispatch(&iocb); } else if (strcmp(a,"stop") == 0) { iocb.plist.iocb_cpuctl.cpu_number = 1; iocb.plist.iocb_cpuctl.cpu_command = CFE_CPU_CMD_STOP; iocb.plist.iocb_cpuctl.start_addr = 0; xprintf("Stopping CPU 1\n"); res = cfe_iocb_dispatch(&iocb); } else { xprintf("Invalid CPU1 command: use 'cpu1 stop' or 'cpu1 start'\n"); return -1; } printf("Result %d\n",res); return res; }
static int ui_cmd_go(ui_cmdline_t *cmd,int argc,char *argv[]) { char *arg; arg = cmd_getarg(cmd,0); if (arg) { cfe_loadargs.la_entrypt = getaddr(arg); } if (cmd_sw_isset(cmd,"-noclose")) { cfe_loadargs.la_flags |= LOADFLG_NOCLOSE; } cfe_go(&cfe_loadargs); return 0; }
static int ui_cmd_munsetenv(ui_cmdline_t *cmd,int argc,char *argv[]) { char *varname; int res; int type; varname = cmd_getarg(cmd,0); if (!varname) { return ui_showusage(cmd); } type = carmel_envtype(varname); if ((res = carmel_delenv(varname)) == 0) { if ((type >= 0) && (type != ENV_FLG_BUILTIN)) carmel_saveenv(); } else { return ui_showerror(res,"Could not delete Monterey environment variable '%s'", varname); } return 0; }
static int ui_cmd_mreset(ui_cmdline_t *cmd,int argc,char *argv[]) { char *x; int val; if ((x = cmd_getarg(cmd,0))) { val = atoi(x); if (val) { SBWRITECSR(A_GPIO_PIN_SET,M_GPIO_MONTEREY_RESET); } else { SBWRITECSR(A_GPIO_PIN_CLR,M_GPIO_MONTEREY_RESET); } printf("Monterey reset pin set to %d\n",val ? 1 : 0); } else { SBWRITECSR(A_GPIO_PIN_CLR,M_GPIO_MONTEREY_RESET); cfe_sleep(2); SBWRITECSR(A_GPIO_PIN_SET,M_GPIO_MONTEREY_RESET); printf("Monterey has been reset.\n"); } return 0; }
static int ui_cmd_flashtest(ui_cmdline_t *cmd,int argc,char *argv[]) { flash_info_t info; int fd; int retlen; int res = 0; int idx; flash_sector_t sector; nvram_info_t nvraminfo; char *devname; int showsectors; devname = cmd_getarg(cmd,0); if (!devname) return ui_showusage(cmd); showsectors = cmd_sw_isset(cmd,"-sectors"); fd = cfe_open(devname); if (fd < 0) { ui_showerror(fd,"Could not open flash device %s",devname); return fd; } res = cfe_ioctl(fd,IOCTL_FLASH_GETINFO,(uint8_t *) &info,sizeof(flash_info_t),&retlen,0); if (res == 0) { printf("FLASH: Base %016llX size %08X type %02X(%s) flags %08X\n", info.flash_base,info.flash_size,info.flash_type,flashtypes[info.flash_type], info.flash_flags); } else { printf("FLASH: Could not determine flash information\n"); } res = cfe_ioctl(fd,IOCTL_NVRAM_GETINFO,(uint8_t *) &nvraminfo,sizeof(nvram_info_t),&retlen,0); if (res == 0) { printf("NVRAM: Offset %08X Size %08X EraseFlg %d\n", nvraminfo.nvram_offset,nvraminfo.nvram_size,nvraminfo.nvram_eraseflg); } else { printf("NVRAM: Not supported by this flash\n"); } if (showsectors && (info.flash_type == FLASH_TYPE_FLASH)) { printf("Flash sector information:\n"); idx = 0; for (;;) { sector.flash_sector_idx = idx; res = cfe_ioctl(fd,IOCTL_FLASH_GETSECTORS,(uint8_t *) §or,sizeof(flash_sector_t),&retlen,0); if (res != 0) { printf("ioctl error\n"); break; } if (sector.flash_sector_status == FLASH_SECTOR_INVALID) break; printf(" Sector %d offset %08X size %d\n", sector.flash_sector_idx, sector.flash_sector_offset, sector.flash_sector_size); idx++; } } cfe_close(fd); return 0; }
static int ui_cmd_config1250(ui_cmdline_t *cmd,int argc,char *argv[]) { char *tok; int fh; uint8_t *base; int len; int res; tok = cmd_getarg(cmd, 0); if (!tok) { return ui_showusage(cmd); } if (argc > 1) { char *fname; cfe_loadargs_t *la = &cfe_loadargs; int res; fname = cmd_getarg(cmd, 1); if (!fname) { return ui_showusage(cmd); } /* Get the file using tftp and read it into a known location. */ /* (From ui_flash.c): * We can't allocate the space from the heap to store the * file to download, because the heap may not be big enough. * So, grab some unallocated memory at the 1MB line (we could * also calculate something, but this will do for now). * We assume the downloadable file will be no bigger than 4MB. */ /* Fill out the loadargs */ la->la_flags = LOADFLG_NOISY; la->la_device = (char *) net_getparam(NET_DEVNAME); la->la_filesys = "tftp"; la->la_filename = fname; /* Temporary: use a fixed memory buffer. */ la->la_address = KERNADDR(FILE_STAGING_BUFFER); la->la_maxsize = FILE_STAGING_BUFFER_SIZE;; la->la_flags |= LOADFLG_SPECADDR; la->la_options = NULL; xprintf("Loader:raw Filesys:%s Dev:%s File:%s Options:%s\n", la->la_filesys, la->la_device, la->la_filename, la->la_options); res = cfe_load_program("raw", la); if (res < 0) { xprintf("Could not load %s\n", fname); return res; } base = (uint8_t *)(la->la_address); len = res; } else { /* This code casts a function pointer to a byte pointer, which is suspect in ANSI C but appears to work with the gnu MIPS tool chain. Changing the externs to, e.g., uint8_t * does not work with PIC code (generates relocation errors). */ base = (uint8_t *)download_start; len = (uint8_t *)download_end - (uint8_t *)download_start; } xprintf("PCI download: base %p len %d\n", base, len); fh = cfe_open(tok); if (fh < 0) { xprintf("Could not open device: %s\n", cfe_errortext(fh)); return fh; } res = cfe_write(fh, base, len); if (res != 0) { xprintf("Could not download device: %s\n", cfe_errortext(res)); } cfe_close(fh); return res; }
static int ui_cmd_setdate(ui_cmdline_t *cmd,int argc,char *argv[]) { char *line; char *p; int dt,mo,yr,y2k; int fd; uint8_t buf[12]; int res=0; if ((line = cmd_getarg(cmd,0)) == NULL) { return ui_showusage(cmd); } /* convert colons to spaces for the gettoken routine */ while ((p = strchr(line,'/'))) *p = ' '; /* parse and check command-line args */ dt = -1; mo = -1; yr = -1; p = gettoken(&line); if (p) mo = atoi(p); p = gettoken(&line); if (p) dt = atoi(p); p = gettoken(&line); if (p) yr = atoi(p); if ((mo <= 0) || (mo > 12) || (dt <= 0) || (dt > 31) || (yr < 1900) || (yr > 2099)) { return ui_showusage(cmd); } y2k = (yr >= 2000) ? 0x20 : 0x19; yr %= 100; /* * hour-minute-second-month-day-year1-year2-(time/date flag) * time/date flag (offset 7) is used to let device know what * is being set. */ buf[3] = mo; buf[4] = dt; buf[5] = yr; buf[6] = y2k; buf[7] = 0x01; /*SET_TIME = 0x00, SET_DATE = 0x01*/ fd = cfe_open("clock0"); if (fd < 0) { ui_showerror(fd,"could not open clock device"); return fd; } res = cfe_write(fd,buf,8); if (res < 0) { ui_showerror(res,"could not set date"); } cfe_close(fd); return 0; }
static int ui_cmd_memedit(ui_cmdline_t *cmd,int argc,char *argv[]) { uint8_t b; uint16_t h; uint32_t w; uint64_t q; long addr; char *vtext; int wlen; int count; int idx = 1; int stuffed = 0; int res = 0; getaddrargs(cmd,&prev_wtype,&prev_addr,NULL); wlen = prev_wtype & ATYPE_SIZE_MASK; vtext = cmd_getarg(cmd,idx++); addr = prev_addr; while (vtext) { count = stuffmem(addr,wlen,vtext); if (count < 0) { ui_showerror(count,"Could not modify memory"); return count; /* error */ } addr += count*wlen; prev_addr += count*wlen; stuffed += count; vtext = cmd_getarg(cmd,idx++); } if (stuffed == 0) { char line[256]; char prompt[32]; xprintf("Type '.' to exit, '-' to back up, '=' to dump memory.\n"); for (;;) { addr = prev_addr; if ((prev_wtype & ATYPE_TYPE_MASK) == ATYPE_TYPE_PHYS) { addr = UNCADDR(addr); } xprintf("%P%c ",prev_addr,(addr != prev_addr) ? '%' : ':'); switch (wlen) { default: case 1: if ((res = mem_peek(&b, addr, MEM_BYTE))) { return res; } xsprintf(prompt,"[%02X]: ", b); break; case 2: if ((res = mem_peek(&h, addr, MEM_HALFWORD))) { return res; } xsprintf(prompt,"[%04X]: ",h); break; case 4: if ((res = mem_peek(&w, addr, MEM_WORD))) { return res; } xsprintf(prompt,"[%08X]: ",w); break; case 8: if ((res = mem_peek(&q, addr, MEM_QUADWORD))) { return res; } xsprintf(prompt,"[%016llX]: ",q); break; } console_readline(prompt,line,sizeof(line)); if (line[0] == '-') { prev_addr -= wlen; continue; } if (line[0] == '=') { dumpmem(prev_addr,prev_addr,16,wlen); continue; } if (line[0] == '.') { break; } if (line[0] == '\0') { prev_addr += wlen; continue; } count = stuffmem(addr,wlen,line); if (count < 0) return count; if (count == 0) break; prev_addr += count*wlen; } } return 0; }
static int ui_cmd_memfill(ui_cmdline_t *cmd,int argc,char *argv[]) { long addr; char *atext; int wlen; int idx = 2; int len; uint64_t pattern; uint8_t *b_ptr; uint16_t *h_ptr; uint32_t *w_ptr; uint64_t *q_ptr; int res; getaddrargs(cmd,&prev_wtype,&prev_addr,&len); atext = cmd_getarg(cmd,idx++); if (!atext) return ui_showusage(cmd); pattern = xtoq(atext); addr = prev_addr; if ((prev_wtype & ATYPE_TYPE_MASK) == ATYPE_TYPE_PHYS) { addr = UNCADDR(addr); } wlen = prev_wtype & ATYPE_SIZE_MASK; switch (wlen) { case 1: b_ptr = (uint8_t *) addr; while (len > 0) { if ((res = mem_poke( ((long)(b_ptr)), pattern, MEM_BYTE))) { /*Did not edit*/ return 0; } b_ptr++; len--; } break; case 2: h_ptr = (uint16_t *) addr; while (len > 0) { if ((res = mem_poke( ((long)(h_ptr)), pattern, MEM_HALFWORD))) { return 0; } h_ptr++; len--; } break; case 4: w_ptr = (uint32_t *) addr; while (len > 0) { if ((res = mem_poke( ((long)(w_ptr)), pattern, MEM_WORD))) { return -1; } w_ptr++; len--; } break; case 8: q_ptr = (uint64_t *) addr; while (len > 0) { if ((res = mem_poke( ((long)(q_ptr)), pattern, MEM_QUADWORD))) { return 0; } q_ptr++; len--; } break; } return 0; }
/* ********************************************************************* * ui_cmd_flashop(cmd,argc,argv) * * The 'flashop' command lives here. This command does a variety * of flash operations over a range of bytes: * * erase, protect, unprotect * * Input parameters: * cmd - command table entry * argc,argv - parameters * * Return value: * 0 if ok * else error ********************************************************************* */ static int ui_cmd_flashop(ui_cmdline_t *cmd,int argc,char *argv[]) { int fd; int res; char *flashdev; int devtype; flash_info_t flashinfo; int erase; int protect; int unprotect; int retlen; unsigned int startaddr = 0; unsigned int endaddr = 0; char *x; int all; flash_range_t range; flashdev = cmd_getarg(cmd,0); if (!flashdev) flashdev = "flash0"; /* * Make sure it's a flash device. */ res = cfe_getdevinfo(flashdev); if (res < 0) { return ui_showerror(CFE_ERR_DEVNOTFOUND,flashdev); } devtype = res & CFE_DEV_MASK; if (res != CFE_DEV_FLASH) { xprintf("Device '%s' is not a flash device.\n",flashdev); return CFE_ERR_INV_PARAM; } protect = cmd_sw_isset(cmd,"-protect"); unprotect = cmd_sw_isset(cmd,"-unprotect"); erase = cmd_sw_isset(cmd,"-erase"); if (protect == 1) { if (erase || unprotect) { xprintf("Conflicting options\n"); return CFE_ERR_INV_PARAM; } } if (unprotect == 1) { if (erase || protect) { xprintf("Conflicting options\n"); return CFE_ERR_INV_PARAM; } } if (erase == 1) { if (unprotect || protect) { xprintf("Conflicting options\n"); return CFE_ERR_INV_PARAM; } } if (erase == 0 && protect == 0 && unprotect == 0) { xprintf("Need one of following options: -erase -protect -unprotect\n"); return CFE_ERR_INV_PARAM; } fd = cfe_open(flashdev); if (fd < 0) { xprintf("Could not open device '%s'\n",flashdev); return CFE_ERR_DEVNOTFOUND; } res = cfe_ioctl(fd,IOCTL_FLASH_GETINFO,(uint8_t *) &flashinfo,sizeof(flash_info_t),&retlen,0); if (res != 0) { cfe_close (fd); return CFE_ERR_IOERR; } all = cmd_sw_isset(cmd,"-all"); if (all == 0) { if (cmd_sw_value(cmd,"-startaddr",&x)) { startaddr = XTOI(x); } else { xprintf("Need option: -startaddr\n"); cfe_close (fd); return CFE_ERR_INV_PARAM; } if (cmd_sw_value(cmd,"-endaddr",&x)) { endaddr = XTOI(x); } else { xprintf("Need option: -endaddr\n"); cfe_close (fd); return CFE_ERR_INV_PARAM; } if (startaddr > endaddr) { xprintf("Final offset (endaddr) must not be less than startaddr \n"); cfe_close (fd); return CFE_ERR_INV_PARAM; } /* Make sure endaddr is within flash */ if (endaddr >= flashinfo.flash_size) { xprintf("Final offset (endaddr) must less than 0x%x\n", flashinfo.flash_size); cfe_close (fd); return CFE_ERR_INV_PARAM; } /* We got here, so params are OK */ range.range_base = startaddr; range.range_length = endaddr-startaddr; } else { range.range_base = 0; range.range_length = flashinfo.flash_size; } if (erase) { res = cfe_ioctl(fd, IOCTL_FLASH_ERASE_RANGE, (void *) &range, NULL, NULL, NULL); } else if (protect) { res = cfe_ioctl(fd, IOCTL_FLASH_PROTECT_RANGE, (void *) &range, NULL, NULL, NULL); } else if (unprotect) { res = cfe_ioctl(fd, IOCTL_FLASH_UNPROTECT_RANGE, (void *) &range, NULL, NULL, NULL); } if (res != 0) { printf("ioctl error\n"); } cfe_close (fd); return 0; }
static int getaddrargs(ui_cmdline_t *cmd,int *curtype,long *addr,int *length) { int atype = *curtype; long newaddr; int newlen; char *x; long wlen; if (cmd_sw_isset(cmd,"-b")) { atype &= ~ATYPE_SIZE_MASK; atype |= ATYPE_SIZE_BYTE; } else if (cmd_sw_isset(cmd,"-h")) { atype &= ~ATYPE_SIZE_MASK; atype |= ATYPE_SIZE_HALF; } else if (cmd_sw_isset(cmd,"-w")) { atype &= ~ATYPE_SIZE_MASK; atype |= ATYPE_SIZE_WORD; } else if (cmd_sw_isset(cmd,"-q")) { atype &= ~ATYPE_SIZE_MASK; atype |= ATYPE_SIZE_QUAD; } wlen = atype & ATYPE_SIZE_MASK; if (wlen == 0) wlen = 1; /* bytes are the default */ if (cmd_sw_isset(cmd,"-p")) { atype &= ~ATYPE_TYPE_MASK; atype |= ATYPE_TYPE_PHYS; } else if (cmd_sw_isset(cmd,"-v")) { atype &= ~ATYPE_TYPE_MASK; atype |= ATYPE_TYPE_KERN; } *curtype = atype; if (addr) { x = cmd_getarg(cmd,0); if (x) { if (strcmp(x,".") == 0) newaddr = *addr; else { /* * hold on to your lunch, this is really, really bad! * Make 64-bit addresses expressed as 8-digit numbers * sign extend automagically. Saves typing, but is very * gross. */ int longaddr = 0; longaddr = strlen(x); if (memcmp(x,"0x",2) == 0) longaddr -= 2; longaddr = (longaddr > 8) ? 1 : 0; if (longaddr) newaddr = (long) xtoq(x); else newaddr = (long) xtoi(x); } *addr = newaddr & ~(wlen - 1); /* align to natural boundary */ } } if (length) { x = cmd_getarg(cmd,1); if (x) { newlen = (long) xtoi(x); *length = newlen; } } return 0; }