/*------------------------------------------------------------------------ * xsh_nvram - shell command to list all items in NVRAM (Flash) or to * display one item *------------------------------------------------------------------------ */ shellcmd xsh_nvram(int nargs, char *args[]) { char *value; /* value to print */ uint16 n; /* iterates through items */ uint16 count; /* counts items found */ struct nvram_tuple *tuple; /* insure nvram can be initialized */ if (nvramInit() == SYSERR) { fprintf(stderr, "error: device does not appear to have nvram.\n"); return 1; } /* For argument '--help', emit help about the 'nvram' command */ if (nargs == 2 && strncmp(args[1], "--help", 7) == 0) { printf("Use: %s OPTION \n\n", args[0]); printf("Description:\n"); printf("%s,%s\n", "\tDisplays a list of items in NVRAM ", "or the value of an item"); printf("Options:\n"); printf("\tlist\t\t\tdisplay all <NAME>=<VALUE> tuples\n"); printf("\tget <NAME>\t\tdisplay the value of <NAME>\n"); printf("\t--help\t display this help and exit\n"); return 0; } if ( (nargs==2) && (strncmp(args[1], "list", 5)==0) ) { count = 0; for (n = 0; n < NVRAM_NHASH; n++) { tuple = nvram_tuples[n]; if (tuple == NULL) { continue; } do { printf("%s\n", tuple->pair); count++; } while ((tuple = tuple->next) != NULL); } printf("%d pairs occupt %d bytes (%d bytes remain unused)\n", count, nvram_header->length, NVRAM_SIZE - nvram_header->length); return 0; } else if ( (nargs == 3) && (strncmp(args[1], "get", 4) == 0) ) { value = nvramGet(args[2]); if (value != 0) { printf("%s\n", nvramGet(args[2])); return 0; } else { fprintf(stderr, "error: no NVRAM binding\n"); return 1; } } fprintf(stderr, "%s: incorrect arguments\n", args[0]); fprintf(stderr, "Try '%s --help' for more information\n", args[0]); return 1; }
/** * Initialize virtual ethernet device structures. * @param devptr TTY device table entry * @return OK if device is intialized successfully */ devcall vlanInit(device *devptr) { struct ether *ethptr; /* Initialize structure pointers */ ethptr = ðertab[devptr->minor]; bzero(ethptr, sizeof(struct ether)); ethptr->dev = devptr; ethptr->csr = (struct bcm4713 *)devptr->csr; /* Physical ethernet device to which the VLAN attaches */ ethptr->phy = (device *)&devtab[ETH0]; ethptr->errors = 0; ethptr->state = ETH_STATE_DOWN; ethptr->rxRingSize = ETH_RX_RING_ENTRIES; ethptr->txRingSize = ETH_TX_RING_ENTRIES; ethptr->mtu = ETH_MTU; ethptr->isema = semcreate(0); ethptr->istart = 0; ethptr->icount = 0; ethptr->ovrrun = 0; ethptr->rxOffset = sizeof(struct rxHeader); /* Lookup MAC in NVRAM, and store it in ether dev struct. */ /* Modify first octet with device minor and set local admin bit */ colon2mac(nvramGet("et0macaddr"), ethptr->devAddress); ethptr->devAddress[0] |= ((uchar)devptr->minor << 2) | ETH_LOCAL_MAC; ethptr->interruptMask = IMASK_DEF; /* As there is only one DMA ring for the physical ethernet, and * none for virtual interfaces, certain values in the ether struct * are set to invalid */ ethptr->rxBufs = (struct ethPktBuffer **)ETH_INVALID; ethptr->txBufs = (struct ethPktBuffer **)ETH_INVALID; ethptr->rxRing = (struct dmaDescriptor *)ETH_INVALID; ethptr->txRing = (struct dmaDescriptor *)ETH_INVALID; return OK; }
/** * Change the variable name to value. If name does not exist, create it, * otherwise replace the old value with the new. * @param *name name to modify * @param *value value to set name * @return OK on successful change, SYSERR on failure */ devcall nvramSet(char *name, char *value) { struct nvram_tuple *tuple; ulong length, offset; if (OK != nvramInit()) { return SYSERR; } length = sizeof(struct nvram_tuple) + strnlen(name, NVRAM_STRMAX) + 1 + strnlen(value, NVRAM_STRMAX); /* check if name is already defined somewhere */ /* if so unset, so we can reset */ if (nvramGet(name) != NULL) { nvramUnset(name); } /* get enough space for both to be rounded up with \0 stored */ if (NULL == (tuple = (struct nvram_tuple *)memget(length))) { return SYSERR; } /* copy name into memory */ offset = 0; strncpy(tuple->pair, name, strnlen(name, NVRAM_STRMAX)); offset += strnlen(name, NVRAM_STRMAX); strncpy(tuple->pair + offset, "=", 1); offset += 1; strncpy(tuple->pair + offset, value, strnlen(value, NVRAM_STRMAX)); offset += strnlen(value, NVRAM_STRMAX); strncpy(tuple->pair + offset, "\0", 1); /* store pointer to name in nvram_tuple struct */ nvramInsert(tuple); return OK; }
/** * Shell command (netup) to start a network interface. * @param nargs number of arguments in args array * @param args array of arguments * @return OK for success, SYSERR for syntax error */ shellcmd xsh_netup(int nargs, char *args[]) { int descrp; struct netaddr ip; struct netaddr mask; struct netaddr gateway; char *str_ip, *str_mask, *str_gateway; char nvramLookup[DEVMAXNAME + NVRAM_STRMAX]; /* Enable interrupts */ enable(); /* Help */ if ((2 == nargs) && (0 == strncmp(args[1], "--help", 7))) { usage(args[0]); return SHELL_OK; } /* Parse device */ if (nargs > 1) { descrp = getdev(args[1]); if (SYSERR == descrp) { fprintf(stderr, "%s is not a valid device.\n", args[1]); return SHELL_ERROR; } } else { /* assume first ethernet interface */ descrp = (ethertab[0].dev)->num; } if (5 == nargs) { /* grab string data */ str_ip = args[2]; str_mask = args[3]; str_gateway = args[4]; } else if (nargs < 3) { /* lookup information in nvram */ bzero(nvramLookup, DEVMAXNAME + NVRAM_STRMAX); sprintf(nvramLookup, "%s_%s", (ethertab[0].dev)->name, NET_LAN_IPADDR); #if NVRAM str_ip = nvramGet(nvramLookup); if (NULL == str_ip) { str_ip = nvramGet("lan_ipaddr"); } #else str_ip = NULL; #endif /* NVRAM */ bzero(nvramLookup, DEVMAXNAME + NVRAM_STRMAX); sprintf(nvramLookup, "%s_%s", (ethertab[0].dev)->name, NET_SUBNET_MASK); #if NVRAM str_mask = nvramGet(nvramLookup); if (NULL == str_mask) { str_mask = nvramGet("lan_netmask"); } #else str_mask = NULL; #endif /* NVRAM */ #if NVRAM str_gateway = nvramGet(NET_GATEWAY); if (NULL == str_gateway) { str_gateway = nvramGet("lan_gateway"); } #else str_gateway = NULL; #endif /* NVRAM */ } else { fprintf(stderr, "Invalid number of arguments\n"); return SHELL_ERROR; } /* Make sure we have valid IPv4 style parameters */ if (NULL == str_ip) { str_ip = "0.0.0.0"; } if (NULL == str_mask) { str_mask = "0.0.0.0"; } if (NULL == str_gateway) { str_gateway = "0.0.0.0"; } /* Parse IP */ if (SYSERR == dot2ipv4(str_ip, &ip)) { fprintf(stderr, "%s is not a valid IPv4 address.\n", str_ip); return SHELL_ERROR; } /* Parse Mask */ if (SYSERR == dot2ipv4(str_mask, &mask)) { fprintf(stderr, "%s is not a valid IPv4 address mask.\n", str_mask); return SHELL_ERROR; } /* Parse Gateway */ if (SYSERR == dot2ipv4(str_gateway, &gateway)) { fprintf(stderr, "%s is not a valid IPv4 address.\n", str_gateway); return SHELL_ERROR; } if (SYSERR == netUp(descrp, &ip, &mask, &gateway)) { fprintf(stderr, "Failed to start network interface on %s\n", args[1]); return SHELL_ERROR; } printf("%s is %s with netmask %s (gateway: %s)\n", devtab[descrp].name, str_ip, str_mask, str_gateway); return SHELL_OK; }
/** * Interpret ond act on an HTTP POST request of the config.html page. * @param webptr pointer to the HTTP device */ int postConfig(struct http *webptr) { int cntr, curlen, valuelen; bool nvram_altered; char *name; char *value, *curval; /* Set flag to false initially */ nvram_altered = FALSE; /* Check the content of the POST */ if (*webptr->content != NULL) { /* Find the name and value for each variable */ name = NULL; value = NULL; for (cntr = 0; cntr < webptr->contentlen; cntr++) { /* Setup name pointer if not set */ if (NULL == name) { name = (webptr->content + cntr); } /* Replace all plus symbols with spaces */ if ('+' == *(webptr->content + cntr)) { *(webptr->content + cntr) = ' '; } /* Check for equals, signifies end of name */ else if ('=' == *(webptr->content + cntr)) { /* Change the char to terminate the string */ *(webptr->content + cntr) = '\0'; /* Setup the value pointer */ value = (webptr->content + (cntr + 1)); } /* Check for ampersand, signifies end of value */ else if ('&' == *(webptr->content + cntr)) { /* Change the char to terminate the string */ *(webptr->content + (cntr)) = '\0'; curval = nvramGet(name); if (NULL != curval) { curlen = strnlen(curval, NVRAM_STRMAX); valuelen = strnlen(value, NVRAM_STRMAX); if ((curlen != valuelen) || (0 != memcmp(curval, value, valuelen))) { nvramSet(name, value); nvram_altered = TRUE; } } else { nvramSet(name, value); nvram_altered = TRUE; } /* Reset pointers */ curval = NULL; name = NULL; value = NULL; } } /* Check for last variable found since end of buffer was reached */ curval = nvramGet(name); if (NULL != curval) { curlen = strnlen(curval, NVRAM_STRMAX); valuelen = strnlen(value, NVRAM_STRMAX); if ((curlen != valuelen) || (0 != memcmp(curval, value, valuelen))) { nvramSet(name, value); nvram_altered = TRUE; } } else { nvramSet(name, value); nvram_altered = TRUE; } } if (nvram_altered) { if (SYSERR == nvramCommit()) { return 1; } else { return 0; } } return 2; }
/** * Finalize the configuration page and output it to the HTTP device. * @param devptr pointer to the current device for httpWrite calls */ int outputConfig(device *devptr, int flashSuccess) { device *ethptr; struct http *webptr; int cntr; /* Format strings for output to underlying device */ char *oneforall, *oneper, *formsubmit, *flashReport; flashReport = NULL; /* Pointers for nvramGet() return values */ char *configDomainname, *configGatewayIP; char *configHostname, *configIP, *configSubnetMask; /* Size variables for NVRAM configuration options */ int hostname_strsz, domainname_strsz, lan_ip_strsz; int subnet_mask_strsz, gate_ip_strsz; /* Lengths of NVRAM lookup strings + null termination character */ hostname_strsz = strnlen(NET_HOSTNAME, NVRAM_STRMAX) + 1; domainname_strsz = strnlen(NET_DOMAINNAME, NVRAM_STRMAX) + 1; lan_ip_strsz = strnlen(NET_LAN_IPADDR, NVRAM_STRMAX) + 1; subnet_mask_strsz = strnlen(NET_SUBNET_MASK, NVRAM_STRMAX) + 1; gate_ip_strsz = strnlen(NET_GATEWAY, NVRAM_STRMAX) + 1; /* Setup device pointer */ webptr = &httptab[devptr->minor]; /* Setup local pointers to device character pointers */ char *hostname_str = webptr->hostname_str; char *domainname_str = webptr->domainname_str; char *lan_ip_str = webptr->lan_ip_str; char *subnet_mask_str = webptr->subnet_mask_str; char *gate_ip_str = webptr->gate_ip_str; /* Zero out the nvram string lookup buffers */ bzero(hostname_str, hostname_strsz + DEVMAXNAME); bzero(domainname_str, domainname_strsz + DEVMAXNAME); bzero(lan_ip_str, lan_ip_strsz + DEVMAXNAME); bzero(subnet_mask_str, subnet_mask_strsz + DEVMAXNAME); bzero(gate_ip_str, gate_ip_strsz + DEVMAXNAME); /* Configuration settings, 1 for all devices */ oneforall = "<form method='POST' name='configform'" " action='config.html' target='_self'>" "<table align=center>" "<tr>" "<td>Gateway IP Address:</td>" "<td>" "<input type='text' name='%s'" " value='%s' maxlength='%d' width='32' />" "</td>" "</tr>" "<tr>" "<td colspan='2'><hr></td>" "</tr>"; /* Configuration settings, 1 per device */ oneper = "<tr>" "<td colspan='2' align='left'>%s:</td>" "</tr>" "<tr>" "<td>Host Name:</td>" "<td>" "<input type='text' name='%s'" " value='%s' maxlength='%d' width='32' />" "</td>" "<tr>" "<tr>" "<td>Domain Name:</td>" "<td>" "<input type='text' name='%s'" " value='%s' maxlength='%d' width='32' />" "</td>" "<tr>" "<td>Local IP Address:</td>" "<td>" "<input type='text' name='%s'" " value='%s' maxlength='%d' width='32' />" "</td>" "</tr>" "<td>Subnet Mask:</td>" "<td>" "<input type='text' name='%s'" " value='%s' maxlength='%d' width='32' />" "</td>" "</tr>" "<tr>" "<td colspan='2'><hr></td>" "</tr>"; formsubmit = "<tr>" "<td align='center' colspan='2'>" "<input type='submit' value='Submit Changes' />" "</td>" "</table>" "</form>"; /* Report on the success of updating router configuration in NVRAM */ switch (flashSuccess) { case 0: flashReport = "<div style='color:#00ff00' align='center'>" "Updated router configuration settings, restart required." "</div>"; break; case 1: flashReport = "<div style='color:#ff0000' align='center'>" "Failed to update router configuration settings." "</div>"; break; default: flashReport = NULL; } if (NULL != flashReport) { httpWrite(devptr, flashReport, strnlen(flashReport, HTTP_STR_SM)); } /* Settings that pertain to all devices */ if (NULL == (configGatewayIP = nvramGet(NET_GATEWAY))) { configGatewayIP = "not set"; } printf(oneforall, NET_GATEWAY, configGatewayIP, IPv4_DOTDEC_MAXLEN); /* Settings that are per device */ for (cntr = 0; cntr < NETHER; cntr++) { ethptr = ethertab[cntr].dev; if (NULL == ethptr) { continue; } sprintf(hostname_str, "%s_%s", ethptr->name, NET_HOSTNAME); sprintf(domainname_str, "%s_%s", ethptr->name, NET_DOMAINNAME); sprintf(lan_ip_str, "%s_%s", ethptr->name, NET_LAN_IPADDR); sprintf(subnet_mask_str, "%s_%s", ethptr->name, NET_SUBNET_MASK); if (NULL == (configHostname = nvramGet(hostname_str))) { configHostname = "not set"; } if (NULL == (configDomainname = nvramGet(domainname_str))) { configDomainname = "not set"; } if (NULL == (configIP = nvramGet(lan_ip_str))) { configIP = "not set"; } if (NULL == (configSubnetMask = nvramGet(subnet_mask_str))) { configSubnetMask = "not set"; } printf(oneper, /* Format string for settings per device */ ethptr->name, /* Device name */ hostname_str, configHostname, NET_HOSTNM_MAXLEN, domainname_str, configDomainname, NVRAM_STRMAX, lan_ip_str, configIP, IPv4_DOTDEC_MAXLEN, subnet_mask_str, configSubnetMask, IPv4_DOTDEC_MAXLEN); } /* Output the bottom of the configuration page body */ httpWrite(devptr, formsubmit, strnlen(formsubmit, HTTP_STR_MD)); /* Free memory of configuration page strings */ if (hostname_str != NULL) { free(hostname_str); } if (domainname_str != NULL) { free(domainname_str); } if (lan_ip_str != NULL) { free(lan_ip_str); } if (subnet_mask_str != NULL) { free(subnet_mask_str); } if (gate_ip_str != NULL) { free(gate_ip_str); } return OK; }
/* Implementation of etherInit() for the ag71xx; see the documentation for this * function in ether.h. */ devcall etherInit(device *devptr) { struct ether *ethptr; struct ag71xx *nicptr; uint *rstptr; uint rstbit; /* Initialize structure pointers */ ethptr = ðertab[devptr->minor]; bzero(ethptr, sizeof(struct ether)); ethptr->dev = devptr; ethptr->csr = devptr->csr; nicptr = (struct ag71xx *)devptr->csr; rstptr = (uint *)RESET_CORE; if (0 == devptr->minor) { rstbit = RESET_E0_MAC; } else { rstbit = RESET_E1_MAC; } ethptr->state = ETH_STATE_DOWN; ethptr->rxRingSize = ETH_RX_RING_ENTRIES; ethptr->txRingSize = ETH_TX_RING_ENTRIES; ethptr->mtu = ETH_MTU; ethptr->interruptMask = IRQ_TX_PKTSENT | IRQ_TX_BUSERR | IRQ_RX_PKTRECV | IRQ_RX_OVERFLOW | IRQ_RX_BUSERR; ethptr->errors = 0; ethptr->isema = semcreate(0); ethptr->istart = 0; ethptr->icount = 0; ethptr->ovrrun = 0; ethptr->rxOffset = ETH_PKT_RESERVE; /* Lookup canonical MAC in NVRAM, and store in ether struct */ colon2mac(nvramGet("et0macaddr"), ethptr->devAddress); ethptr->addressLength = ETH_ADDR_LEN; // Reset the device. nicptr->macConfig1 |= MAC_CFG1_SOFTRESET; udelay(20); *rstptr |= rstbit; mdelay(100); *rstptr &= ~rstbit; mdelay(100); // Enable Tx and Rx. nicptr->macConfig1 = MAC_CFG1_TX | MAC_CFG1_SYNC_TX | MAC_CFG1_RX | MAC_CFG1_SYNC_RX; // Configure full duplex, auto padding CRC, and interface mode. nicptr->macConfig2 |= MAC_CFG2_FDX | MAC_CFG2_PAD | MAC_CFG2_LEN_CHECK | MAC_CFG2_IMNIBBLE; // Enable FIFO modules. nicptr->fifoConfig0 = FIFO_CFG0_WTMENREQ | FIFO_CFG0_SRFENREQ | FIFO_CFG0_FRFENREQ | FIFO_CFG0_STFENREQ | FIFO_CFG0_FTFENREQ; // FIXME // -> ag71xx_mii_ctrl_set_if(ag, pdata->mii_if); // Stores a '1' in 0x18070000 (MII mode) // Stores a '1' in 0x18070004 (RMII mode) // FRRD may be asserted only after the completion of the input frame. nicptr->fifoConfig1 = 0x0FFF0000; // Max out number of words to store in Rx RAM; nicptr->fifoConfig2 = 0x00001FFF; // Drop anything with errors in the Rx stats vector. nicptr->fifoConfig4 = 0x0003FFFF; // Drop short packets, set "don't care" on Rx stats vector bits. nicptr->fifoConfig5 = 0x0003FFFF; /* NOTE: because device initialization runs early in the system, */ /* we are assured that this stkget() call will return */ /* page-aligned (and cache-aligned) boundaries. */ ethptr->rxBufs = stkget(PAGE_SIZE); ethptr->txBufs = stkget(PAGE_SIZE); ethptr->rxRing = stkget(PAGE_SIZE); ethptr->txRing = stkget(PAGE_SIZE); if ((SYSERR == (int)ethptr->rxBufs) || (SYSERR == (int)ethptr->txBufs) || (SYSERR == (int)ethptr->rxRing) || (SYSERR == (int)ethptr->txRing)) { #ifdef DETAIL kprintf("eth%d ring buffer allocation error.\r\n", devptr->minor); #endif /* DETAIL */ return SYSERR; } /* bump buffer pointers/rings to KSEG1 */ ethptr->rxBufs = (struct ethPktBuffer **)(((ulong)ethptr->rxBufs - PAGE_SIZE + sizeof(int)) | KSEG1_BASE); ethptr->txBufs = (struct ethPktBuffer **)(((ulong)ethptr->txBufs - PAGE_SIZE + sizeof(int)) | KSEG1_BASE); ethptr->rxRing = (struct dmaDescriptor *)(((ulong)ethptr->rxRing - PAGE_SIZE + sizeof(int)) | KSEG1_BASE); ethptr->txRing = (struct dmaDescriptor *)(((ulong)ethptr->txRing - PAGE_SIZE + sizeof(int)) | KSEG1_BASE); /* Zero out the buffer pointers and rings */ bzero(ethptr->rxBufs, PAGE_SIZE); bzero(ethptr->txBufs, PAGE_SIZE); bzero(ethptr->rxRing, PAGE_SIZE); bzero(ethptr->txRing, PAGE_SIZE); interruptVector[devptr->irq] = devptr->intr; enable_irq(devptr->irq); return OK; }
/** * @ingroup shell * * The Xinu shell. Provides an interface to execute commands. * @param descrp descriptor of device on which the shell is open * @return OK for successful exit, SYSERR for unrecoverable error */ thread shell(int indescrp, int outdescrp, int errdescrp) { char buf[SHELL_BUFLEN]; /* line input buffer */ short buflen; /* length of line input */ char tokbuf[SHELL_BUFLEN + SHELL_MAXTOK]; /* token value buffer */ short ntok; /* number of tokens */ char *tok[SHELL_MAXTOK]; /* pointers to token values */ char *outname; /* name of output file */ char *inname; /* name of input file */ bool background; /* is background proccess? */ syscall child; /* pid of child thread */ ushort i, j; /* temp variables */ irqmask im; /* interrupt mask state */ char *hostptr = NULL; /* pointer to hostname */ /* Setup buffer for string for nvramGet call for hostname */ #if defined(ETH0) && NVRAM char hostnm[NET_HOSTNM_MAXLEN + 1]; /* hostname of backend */ if (!isbaddev(ETH0)) { size_t hostname_strsz; /* nvram hostname name size */ bzero(hostnm, NET_HOSTNM_MAXLEN + 1); /* Determine the hostname of the main network device */ hostname_strsz = strlen(NET_HOSTNAME); hostname_strsz += 1; hostname_strsz += DEVMAXNAME; hostname_strsz += 1; char nvramget_hostname_str[hostname_strsz]; sprintf(nvramget_hostname_str, "%s_%s", devtab[ETH0].name, NET_HOSTNAME); /* Acquire the backend's hostname */ hostptr = nvramGet(nvramget_hostname_str); if (hostptr != NULL) { strncpy(hostnm, hostptr, NET_HOSTNM_MAXLEN); hostptr = hostnm; } } #endif /* Set command devices for input, output, and error */ stdin = indescrp; stdout = outdescrp; stderr = errdescrp; /* Print shell banner to framebuffer, if exists */ #if defined(FRAMEBUF) if (indescrp == FRAMEBUF) { foreground = RASPBERRY; printf(SHELL_BANNER_NONVT100); foreground = LEAFGREEN; printf(SHELL_START); foreground = GREEN; } else #endif { printf(SHELL_BANNER); printf(SHELL_START); } /* Continually receive and handle commands */ while (TRUE) { /* Display prompt */ printf(SHELL_PROMPT); if (NULL != hostptr) { printf("@%s$ ", hostptr); } else { printf("$ "); } /* Setup proper tty modes for input and output */ control(stdin, TTY_CTRL_CLR_IFLAG, TTY_IRAW, NULL); control(stdin, TTY_CTRL_SET_IFLAG, TTY_ECHO, NULL); /* Read command */ buflen = read(stdin, buf, SHELL_BUFLEN - 1); /* Check for EOF and exit gracefully if seen */ if (EOF == buflen) { break; } /* Parse line input into tokens */ if (SYSERR == (ntok = lexan(buf, buflen, &tokbuf[0], &tok[0]))) { fprintf(stderr, SHELL_SYNTAXERR); continue; } /* Ensure parse generated tokens */ if (0 == ntok) { continue; } /* Initialize command options */ inname = NULL; outname = NULL; background = FALSE; /* Mark as background thread, if last token is '&' */ if ('&' == *tok[ntok - 1]) { ntok--; background = TRUE; } /* Check each token and perform special handling of '>' and '<' */ for (i = 0; i < ntok; i++) { /* Background '&' should have already been handled; Syntax error */ if ('&' == *tok[i]) { ntok = -1; break; } /* Setup for output redirection if token is '>' */ if ('>' == *tok[i]) { /* Syntax error */ if (outname != NULL || i >= ntok - 1) { ntok = -1; break; } outname = tok[i + 1]; ntok -= 2; /* shift tokens (not to be passed to command */ for (j = i; j < ntok; j++) { tok[j] = tok[j + 2]; } continue; } /* Setup for input redirection if token is '<' */ if ('<' == *tok[i]) { /* Syntax error */ if (inname != NULL || i >= ntok - 1) { ntok = -1; break; } inname = tok[i + 1]; ntok -= 2; /* shift tokens (not to be passed to command */ for (j = i; j < ntok; j++) { tok[j] = tok[j + 2]; } continue; } } /* Handle syntax error */ if (ntok <= 0) { fprintf(stderr, SHELL_SYNTAXERR); continue; } /* Lookup first token in the command table */ for (i = 0; i < ncommand; i++) { if (0 == strcmp(commandtab[i].name, tok[0])) { break; } } /* Handle command not found */ if (i >= ncommand) { fprintf(stderr, "%s: command not found\n", tok[0]); continue; } /* Handle command if it is built-in */ if (commandtab[i].builtin) { if (inname != NULL || outname != NULL || background) { fprintf(stderr, SHELL_SYNTAXERR); } else { (*commandtab[i].procedure) (ntok, tok); } continue; } /* Spawn child thread for non-built-in commands */ child = create(commandtab[i].procedure, SHELL_CMDSTK, SHELL_CMDPRIO, commandtab[i].name, 2, ntok, tok); /* Ensure child command thread was created successfully */ if (SYSERR == child) { fprintf(stderr, SHELL_CHILDERR); continue; } /* Set file descriptors for newly created thread */ if (NULL == inname) { thrtab[child].fdesc[0] = stdin; } else { thrtab[child].fdesc[0] = getdev(inname); } if (NULL == outname) { thrtab[child].fdesc[1] = stdout; } else { thrtab[child].fdesc[1] = getdev(outname); } thrtab[child].fdesc[2] = stderr; if (background) { /* Make background thread ready, but don't reschedule */ im = disable(); ready(child, RESCHED_NO); restore(im); } else { /* Clear waiting message; Reschedule; */ while (recvclr() != NOMSG); im = disable(); ready(child, RESCHED_YES); restore(im); /* Wait for command thread to finish */ while (receive() != child); sleep(10); } } /* Close shell */ fprintf(stdout, SHELL_EXIT); sleep(10); return OK; }
/** * The Xinu shell. Provides an interface to execute commands. * @param descrp descriptor of device on which the shell is open * @return OK for successful exit, SYSERR for unrecoverable error */ thread shell(int indescrp, int outdescrp, int errdescrp) { char buf[SHELL_BUFLEN]; /* line input buffer */ short buflen; /* length of line input */ char tokbuf[SHELL_BUFLEN + SHELL_MAXTOK]; /* token value buffer */ short ntok; /* number of tokens */ char *tok[SHELL_MAXTOK]; /* pointers to token values */ char *outname; /* name of output file */ char *inname; /* name of input file */ bool background; /* is background proccess? */ syscall child; /* pid of child thread */ ushort i, j; /* temp variables */ irqmask im; /* interrupt mask state */ /* hostname variables */ char hostnm[NET_HOSTNM_MAXLEN + 1]; /* hostname of backend */ char *hostptr; /* pointer to hostname */ int hostname_strsz; /* nvram hostname name size */ device *devptr; /* device pointer */ printf( "Welcome to the shell!\n" ); /* Enable interrupts */ enable(); hostptr = NULL; devptr = NULL; hostname_strsz = 0; bzero(hostnm, NET_HOSTNM_MAXLEN + 1); /* Setup buffer for string for nvramGet call for hostname */ #ifdef ETH0 if (!isbaddev(ETH0)) { /* Determine the hostname of the main network device */ devptr = (device *)&devtab[ETH0]; hostname_strsz = strnlen(NET_HOSTNAME, NVRAM_STRMAX) + 1; hostname_strsz += DEVMAXNAME; char nvramget_hostname_str[hostname_strsz]; sprintf(nvramget_hostname_str, "%s_%s", devptr->name, NET_HOSTNAME); /* Acquire the backend's hostname */ #if NVRAM hostptr = nvramGet(nvramget_hostname_str); #endif /* NVRAM */ if (hostptr != NULL) { memcpy(hostnm, hostptr, NET_HOSTNM_MAXLEN); hostptr = hostnm; } } #endif /* Set command devices for input, output, and error */ stdin = indescrp; stdout = outdescrp; stderr = errdescrp; /* Print shell banner */ printf(SHELL_BANNER); /* Print shell welcome message */ printf(SHELL_START); /* Continually receive and handle commands */ while (TRUE) { /* Display prompt */ printf(SHELL_PROMPT); if (NULL != hostptr) { printf("@%s$ ", hostptr); } else { printf("$ "); } /* Setup proper tty modes for input and output */ control(stdin, TTY_CTRL_CLR_IFLAG, TTY_IRAW, NULL); control(stdin, TTY_CTRL_SET_IFLAG, TTY_ECHO, NULL); /* Null out the buf and read command */ memset(buf, '\0', SHELL_BUFLEN); buflen = shellRead(stdin, buf, SHELL_BUFLEN); if(buf[0] != '!') { addHistoryItem(buf, buflen); } /* Check for EOF and exit gracefully if seen */ if (EOF == buflen) { break; } // Check for indicator of history command if (buf[0] == '!') { int index; // handler for !! (just execute most recent command) if(buf[1] == '!') { index = 0; } else { // extract the number string char indexString[buflen]; strncpy(indexString, &buf[1], buflen - 1); indexString[buflen] = '\0'; // convert number string into a valid index // calculation is done because the index numbers // are reverse of their numbers printed using 'history' index = numHistoryItems - atoi(indexString); } //replace buf and buflen with the last command strncpy(buf, history[index].command, SHELL_BUFLEN); buflen = history[index].commandLength + 1; } /* Parse line input into tokens */ if (SYSERR == (ntok = lexan(buf, buflen, &tokbuf[0], &tok[0]))) { fprintf(stderr, SHELL_SYNTAXERR); continue; } /* Ensure parse generated tokens */ if (0 == ntok) { continue; } /* Initialize command options */ inname = NULL; outname = NULL; background = FALSE; /* Mark as background thread, if last token is '&' */ if ('&' == *tok[ntok - 1]) { ntok--; background = TRUE; } /* Check each token and perform special handling of '>' and '<' */ for (i = 0; i < ntok; i++) { /* Background '&' should have already been handled; Syntax error */ if ('&' == *tok[i]) { ntok = -1; break; } /* Setup for output redirection if token is '>' */ if ('>' == *tok[i]) { /* Syntax error */ if (outname != NULL || i >= ntok - 1) { ntok = -1; break; } outname = tok[i + 1]; ntok -= 2; /* shift tokens (not to be passed to command */ for (j = i; j < ntok; j++) { tok[j] = tok[j + 2]; } continue; } /* Setup for input redirection if token is '<' */ if ('<' == *tok[i]) { /* Syntax error */ if (inname != NULL || i >= ntok - 1) { ntok = -1; break; } inname = tok[i + 1]; ntok -= 2; /* shift tokens (not to be passed to command */ for (j = i; j < ntok; j++) { tok[j] = tok[j + 2]; } continue; } } /* Handle syntax error */ if (ntok <= 0) { fprintf(stderr, SHELL_SYNTAXERR); continue; } /* Lookup first token in the command table */ for (i = 0; i < ncommand; i++) { if (0 == strncmp(commandtab[i].name, tok[0], SHELL_BUFLEN)) { break; } } /* Handle command not found */ if (i >= ncommand) { fprintf(stderr, "%s: command not found\n", tok[0]); continue; } /* Handle command if it is built-in */ if (commandtab[i].builtin) { if (inname != NULL || outname != NULL || background) { fprintf(stderr, SHELL_SYNTAXERR); } else { (*commandtab[i].procedure) (ntok, tok); } continue; } /* Spawn child thread for non-built-in commands */ child = create(commandtab[i].procedure, SHELL_CMDSTK, SHELL_CMDPRIO, commandtab[i].name, 2, ntok, tok); /* Ensure child command thread was created successfully */ if (SYSERR == child) { fprintf(stderr, SHELL_CHILDERR); continue; } /* Set file descriptors for newly created thread */ if (NULL == inname) { thrtab[child].fdesc[0] = stdin; } else { thrtab[child].fdesc[0] = getdev(inname); } if (NULL == outname) { thrtab[child].fdesc[1] = stdout; } else { thrtab[child].fdesc[1] = getdev(outname); } thrtab[child].fdesc[2] = stderr; if (background) { /* Make background thread ready, but don't reschedule */ im = disable(); ready(child, RESCHED_NO); restore(im); } else { /* Clear waiting message; Reschedule; */ while (recvclr() != NOMSG); im = disable(); ready(child, RESCHED_YES); restore(im); /* Wait for command thread to finish */ while (receive() != child); sleep(10); } } /* Close shell */ fprintf(stdout, SHELL_EXIT); sleep(10); return OK; }