Example #1
0
File: misc.c Project: adtools/abcsh
/* print variable/alias value using necessary quotes
 * (POSIX says they should be suitable for re-entry...)
 * No trailing newline is printed.
 */
void
print_value_quoted(const char *s)
{
        const char *p;
        int inquote = 0;

        /* Test if any quotes are needed */
        for (p = s; *p; p++)
                if (ctype(*p, C_QUOTE))
                        break;
        if (!*p) {
                shprintf("%s", s);
                return;
        }
        for (p = s; *p; p++) {
                if (*p == '\'') {
                        shprintf("'\\'" + 1 - inquote);
                        inquote = 0;
                } else {
                        if (!inquote) {
                                shprintf("'");
                                inquote = 1;
                        }
                        shf_putc(*p, shl_stdout);
                }
        }
        if (inquote)
                shprintf("'");
}
Example #2
0
File: misc.c Project: adtools/abcsh
static void
printoptions(int verbose)
{
        int i;

        if (verbose) {
                struct options_info oi;
                int n, len;

                /* verbose version */
                shprintf("Current option settings\n");

                for (i = n = oi.opt_width = 0; i < NELEM(options); i++)
                        if (options[i].name) {
                                len = strlen(options[i].name);
                                oi.opts[n].name = options[i].name;
                                oi.opts[n++].flag = i;
                                if (len > oi.opt_width)
                                        oi.opt_width = len;
                        }
                print_columns(shl_stdout, n, options_fmt_entry, &oi,
                        oi.opt_width + 5, 1);
        } else {
                /* short version ala ksh93 */
                shprintf("set");
                for (i = 0; i < NELEM(options); i++)
                        if (Flag(i) && options[i].name)
                                shprintf(" -o %s", options[i].name);
                shprintf(newline);
        }
}
Example #3
0
File: c_sh.c Project: tomgrean/kash
int
c_times(char **wp)
{
	struct tms all;

	(void) ksh_times(&all);
	shprintf("Shell: %8ss user ", clocktos(all.tms_utime));
	shprintf("%8ss system\n", clocktos(all.tms_stime));
	shprintf("Kids:  %8ss user ", clocktos(all.tms_cutime));
	shprintf("%8ss system\n", clocktos(all.tms_cstime));

	return 0;
}
Example #4
0
static void
print_ulimit(const struct limits *l, int how)
{
	rlim_t		val = 0;
	struct rlimit	limit;

	getrlimit(l->resource, &limit);
	if (how & SOFT)
		val = limit.rlim_cur;
	else if (how & HARD)
		val = limit.rlim_max;
	if (val == RLIM_INFINITY)
		shprintf("unlimited\n");
	else {
		val /= l->factor;
		shprintf("%ld\n", (long) val);
	}
}
Example #5
0
int
c_trap(char **wp)
{
	int i;
	char *s;
	Trap *p;

	if (ksh_getopt(wp, &builtin_opt, null) == '?')
		return 1;
	wp += builtin_opt.optind;

	if (*wp == NULL) {
		for (p = sigtraps, i = NSIG+1; --i >= 0; p++) {
			if (p->trap != NULL) {
				shprintf("trap -- ");
				print_value_quoted(p->trap);
				shprintf(" %s\n", p->name);
			}
		}
		return 0;
	}

	/*
	 * Use case sensitive lookup for first arg so the
	 * command 'exit' isn't confused with the pseudo-signal
	 * 'EXIT'.
	 */
	s = (gettrap(*wp, false) == NULL) ? *wp++ : NULL; /* get command */
	if (s != NULL && s[0] == '-' && s[1] == '\0')
		s = NULL;

	/* set/clear traps */
	while (*wp != NULL) {
		p = gettrap(*wp++, true);
		if (p == NULL) {
			bi_errorf("bad signal %s", wp[-1]);
			return 1;
		}
		settrap(p, s);
	}
	return 0;
}
Example #6
0
static void
printoptions(int verbose)
{
	unsigned int ele;

	if (verbose) {
		struct options_info oi;
		unsigned int n;
		int len;

		/* verbose version */
		shprintf("Current option settings\n");

		for (ele = n = oi.opt_width = 0; ele < NELEM(sh_options); ele++) {
			if (sh_options[ele].name) {
				len = strlen(sh_options[ele].name);
				oi.opts[n].name = sh_options[ele].name;
				oi.opts[n++].flag = ele;
				if (len > oi.opt_width)
					oi.opt_width = len;
			}
		}
		print_columns(shl_stdout, n, options_fmt_entry, &oi,
		    oi.opt_width + 5, 1);
	} else {
		/* short version ala ksh93 */
		shprintf("set");
		for (ele = 0; ele < NELEM(sh_options); ele++) {
			if (sh_options[ele].name)
				shprintf(" %co %s",
					 Flag(ele) ? '-' : '+',
					 sh_options[ele].name);
		}
		shprintf("\n");
	}
}
Example #7
0
static void
printoptions(bool verbose)
{
	int i = 0;

	if (verbose) {
		int n = 0, len, octs = 0;
		struct options_info oi;

		/* verbose version */
		shf_puts("Current option settings\n", shl_stdout);

		oi.opt_width = 0;
		while (i < (int)NELEM(options)) {
			if (options[i].name) {
				oi.opts[n++] = i;
				len = strlen(options[i].name);
				if (len > octs)
					octs = len;
				len = utf_mbswidth(options[i].name);
				if (len > oi.opt_width)
					oi.opt_width = len;
			}
			++i;
		}
		print_columns(shl_stdout, n, options_fmt_entry, &oi,
		    octs + 4, oi.opt_width + 4, true);
	} else {
		/* short version รก la AT&T ksh93 */
		shf_puts("set", shl_stdout);
		while (i < (int)NELEM(options)) {
			if (Flag(i) && options[i].name)
				shprintf(" -o %s", options[i].name);
			++i;
		}
		shf_putc('\n', shl_stdout);
	}
}
Example #8
0
static void
printoptions(bool verbose)
{
	size_t i = 0;

	if (verbose) {
		size_t n = 0, len, octs = 0;
		struct options_info oi;

		/* verbose version */
		shf_puts("Current option settings\n", shl_stdout);

		oi.opt_width = 0;
		while (i < NELEM(options)) {
			if ((len = strlen(OFN(i)))) {
				oi.opts[n++] = i;
				if (len > octs)
					octs = len;
				len = utf_mbswidth(OFN(i));
				if ((int)len > oi.opt_width)
					oi.opt_width = (int)len;
			}
			++i;
		}
		print_columns(shl_stdout, n, options_fmt_entry, &oi,
		    octs + 4, oi.opt_width + 4, true);
	} else {
		/* short version like AT&T ksh93 */
		shf_puts(Tset, shl_stdout);
		while (i < NELEM(options)) {
			if (Flag(i) && OFN(i)[0])
				shprintf(" -o %s", OFN(i));
			++i;
		}
		shf_putc('\n', shl_stdout);
	}
}
Example #9
0
int
c_ulimit(char **wp)
{
	static const struct limits limits[] = {
		/* Do not use options -H, -S or -a or change the order. */
		{ "time(cpu-seconds)", RLIMIT_CPU, 1, 't' },
		{ "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
		{ "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
		{ "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
		{ "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
		{ "lockedmem(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
		{ "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
		{ "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
		{ "processes", RLIMIT_NPROC, 1, 'p' },
#ifdef RLIMIT_VMEM
		{ "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' },
#endif /* RLIMIT_VMEM */
		{ NULL, 0, 0, 0 },
	};
	static char	_options[4 + NELEM(limits) * 2];
	int		how = SOFT | HARD;
	const struct limits	*l;
	int		optc, all = 0;

	if (!_options[0]) {
		/* build options string on first call - yuck */
		char *p = _options;

		*p++ = 'H'; *p++ = 'S'; *p++ = 'a';
		for (l = limits; l->name; l++) {
			*p++ = l->option;
			*p++ = '#';
		}
		*p = '\0';
	}
	/* First check for -a, -H and -S. */
	while ((optc = ksh_getopt(wp, &builtin_opt, _options)) != -1)
		switch (optc) {
		case 'H':
			how = HARD;
			break;
		case 'S':
			how = SOFT;
			break;
		case 'a':
			all = 1;
			break;
		case '?':
			return (1);
		default:
			break;
		}

	if (wp[builtin_opt.optind] != NULL) {
		bi_errorf("usage: ulimit [-acdfHlmnpSst] [value]");
		return (1);
	}

	/* Then parse and act on the actual limits, one at a time */
	ksh_getopt_reset(&builtin_opt, GF_ERROR);
	while ((optc = ksh_getopt(wp, &builtin_opt, _options)) != -1)
		switch (optc) {
		case 'a':
		case 'H':
		case 'S':
			break;
		case '?':
			return (1);
		default:
			for (l = limits; l->name && l->option != optc; l++)
				;
			if (!l->name) {
				internal_errorf(0, "ulimit: %c", optc);
				return (1);
			}
			if (builtin_opt.optarg) {
				if (set_ulimit(l, builtin_opt.optarg, how))
					return (1);
			} else
				print_ulimit(l, how);
			break;
		}

	wp += builtin_opt.optind;

	if (all) {
		for (l = limits; l->name; l++) {
			shprintf("%-20s ", l->name);
			print_ulimit(l, how);
		}
	} else if (builtin_opt.optind == 1) {
		/* No limit specified, use file size */
		l = &limits[1];
		if (wp[0] != NULL) {
			if (set_ulimit(l, wp[0], how))
				return (1);
			wp++;
		} else {
			print_ulimit(l, how);
		}
	}

	return (0);
}
Example #10
0
int
c_umask(char **wp)
{
	int i;
	char *cp;
	int symbolic = 0;
	mode_t old_umask;
	int optc;

	while ((optc = ksh_getopt(wp, &builtin_opt, "S")) != -1)
		switch (optc) {
		case 'S':
			symbolic = 1;
			break;
		case '?':
			return 1;
		}
	cp = wp[builtin_opt.optind];
	if (cp == NULL) {
		old_umask = umask(0);
		umask(old_umask);
		if (symbolic) {
			char buf[18];
			int j;

			old_umask = ~old_umask;
			cp = buf;
			for (i = 0; i < 3; i++) {
				*cp++ = "ugo"[i];
				*cp++ = '=';
				for (j = 0; j < 3; j++)
					if (old_umask & (1 << (8 - (3*i + j))))
						*cp++ = "rwx"[j];
				*cp++ = ',';
			}
			cp[-1] = '\0';
			shprintf("%s\n", buf);
		} else
			shprintf("%#3.3o\n", old_umask);
	} else {
		mode_t new_umask;

		if (digit(*cp)) {
			for (new_umask = 0; *cp >= '0' && *cp <= '7'; cp++)
				new_umask = new_umask * 8 + (*cp - '0');
			if (*cp) {
				bi_errorf("bad number");
				return 1;
			}
		} else {
			/* symbolic format */
			int positions, new_val;
			char op;

			old_umask = umask(0);
			umask(old_umask); /* in case of error */
			old_umask = ~old_umask;
			new_umask = old_umask;
			positions = 0;
			while (*cp) {
				while (*cp && strchr("augo", *cp))
					switch (*cp++) {
					case 'a':
						positions |= 0111;
						break;
					case 'u':
						positions |= 0100;
						break;
					case 'g':
						positions |= 0010;
						break;
					case 'o':
						positions |= 0001;
						break;
					}
				if (!positions)
					positions = 0111; /* default is a */
				if (!strchr("=+-", op = *cp))
					break;
				cp++;
				new_val = 0;
				while (*cp && strchr("rwxugoXs", *cp))
					switch (*cp++) {
					case 'r': new_val |= 04; break;
					case 'w': new_val |= 02; break;
					case 'x': new_val |= 01; break;
					case 'u': new_val |= old_umask >> 6;
						  break;
					case 'g': new_val |= old_umask >> 3;
						  break;
					case 'o': new_val |= old_umask >> 0;
						  break;
					case 'X': if (old_umask & 0111)
							new_val |= 01;
						  break;
					case 's': /* ignored */
						  break;
					}
				new_val = (new_val & 07) * positions;
				switch (op) {
				case '-':
					new_umask &= ~new_val;
					break;
				case '=':
					new_umask = new_val |
					    (new_umask & ~(positions * 07));
					break;
				case '+':
					new_umask |= new_val;
				}
				if (*cp == ',') {
					positions = 0;
					cp++;
				} else if (!strchr("=+-", *cp))
					break;
			}
			if (*cp) {
				bi_errorf("bad mask");
				return 1;
			}
			new_umask = ~new_umask;
		}
		umask(new_umask);
	}
	return 0;
}
Example #11
0
/* fg and bg built-ins: called only if Flag(FMONITOR) set */
int
j_resume(const char *cp, int bg)
{
	Job	*j;
	Proc	*p;
	int	ecode;
	int	running;
	int	rv = 0;
	sigset_t omask;

	sigprocmask(SIG_BLOCK, &sm_sigchld, &omask);

	if ((j = j_lookup(cp, &ecode)) == (Job *) 0) {
		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
		bi_errorf("%s: %s", cp, lookup_msgs[ecode]);
		return 1;
	}

	if (j->pgrp == 0) {
		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
		bi_errorf("job not job-controlled");
		return 1;
	}

	if (bg)
		shprintf("[%d] ", j->job);

	running = 0;
	for (p = j->proc_list; p != (Proc *) 0; p = p->next) {
		if (p->state == PSTOPPED) {
			p->state = PRUNNING;
			p->status = 0;
			running = 1;
		}
		shprintf("%s%s", p->command, p->next ? "| " : null);
	}
	shprintf("%s", newline);
	shf_flush(shl_stdout);
	if (running)
		j->state = PRUNNING;

	put_job(j, PJ_PAST_STOPPED);
	if (bg)
		j_set_async(j);
	else {
# ifdef JOBS
		/* attach tty to job */
		if (j->state == PRUNNING) {
			if (ttypgrp_ok && (j->flags & JF_SAVEDTTY))
				tcsetattr(tty_fd, TCSADRAIN, &j->ttystate);
			/* See comment in j_waitj regarding saved_ttypgrp. */
			if (ttypgrp_ok &&
			    tcsetpgrp(tty_fd, (j->flags & JF_SAVEDTTYPGRP) ?
			    j->saved_ttypgrp : j->pgrp) < 0) {
				if (j->flags & JF_SAVEDTTY)
					tcsetattr(tty_fd, TCSADRAIN, &tty_state);
				sigprocmask(SIG_SETMASK, &omask,
				    (sigset_t *) 0);
				bi_errorf("1st tcsetpgrp(%d, %d) failed: %s",
				    tty_fd,
				    (int) ((j->flags & JF_SAVEDTTYPGRP) ?
				    j->saved_ttypgrp : j->pgrp),
				    strerror(errno));
				return 1;
			}
		}
# endif /* JOBS */
		j->flags |= JF_FG;
		j->flags &= ~JF_KNOWN;
		if (j == async_job)
			async_job = (Job *) 0;
	}

	if (j->state == PRUNNING && killpg(j->pgrp, SIGCONT) < 0) {
		int	err = errno;

		if (!bg) {
			j->flags &= ~JF_FG;
# ifdef JOBS
			if (ttypgrp_ok && (j->flags & JF_SAVEDTTY))
				tcsetattr(tty_fd, TCSADRAIN, &tty_state);
			if (ttypgrp_ok && tcsetpgrp(tty_fd, our_pgrp) < 0) {
				warningf(true,
				    "fg: 2nd tcsetpgrp(%d, %d) failed: %s",
				    tty_fd, (int) our_pgrp,
				    strerror(errno));
			}
# endif /* JOBS */
		}
		sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
		bi_errorf("cannot continue job %s: %s",
		    cp, strerror(err));
		return 1;
	}
	if (!bg) {
# ifdef JOBS
		if (ttypgrp_ok) {
			j->flags &= ~(JF_SAVEDTTY | JF_SAVEDTTYPGRP);
		}
# endif /* JOBS */
		rv = j_waitj(j, JW_NONE, "jw:resume");
	}
	sigprocmask(SIG_SETMASK, &omask, (sigset_t *) 0);
	return rv;
}
Example #12
0
int
c_cd(const char **wp)
{
	int optc, rv, phys_path;
	bool physical = tobool(Flag(FPHYSICAL));
	/* was a node from cdpath added in? */
	int cdnode;
	/* show where we went?, error for $PWD */
	bool printpath = false, eflag = false;
	struct tbl *pwd_s, *oldpwd_s;
	XString xs;
	char *dir, *allocd = NULL, *tryp, *pwd, *cdpath;

	while ((optc = ksh_getopt(wp, &builtin_opt, "eLP")) != -1)
		switch (optc) {
		case 'e':
			eflag = true;
			break;
		case 'L':
			physical = false;
			break;
		case 'P':
			physical = true;
			break;
		case '?':
			return (2);
		}
	wp += builtin_opt.optind;

	if (Flag(FRESTRICTED)) {
		bi_errorf("restricted shell - can't cd");
		return (2);
	}

	pwd_s = global("PWD");
	oldpwd_s = global("OLDPWD");

	if (!wp[0]) {
		/* No arguments - go home */
		if ((dir = str_val(global("HOME"))) == null) {
			bi_errorf("no home directory (HOME not set)");
			return (2);
		}
	} else if (!wp[1]) {
		/* One argument: - or dir */
		strdupx(allocd, wp[0], ATEMP);
		if (ksh_isdash((dir = allocd))) {
			afree(allocd, ATEMP);
			allocd = NULL;
			dir = str_val(oldpwd_s);
			if (dir == null) {
				bi_errorf("no OLDPWD");
				return (2);
			}
			printpath = true;
		}
	} else if (!wp[2]) {
		/* Two arguments - substitute arg1 in PWD for arg2 */
		size_t ilen, olen, nlen, elen;
		char *cp;

		if (!current_wd[0]) {
			bi_errorf("can't determine current directory");
			return (2);
		}
		/*
		 * substitute arg1 for arg2 in current path.
		 * if the first substitution fails because the cd fails
		 * we could try to find another substitution. For now
		 * we don't
		 */
		if ((cp = strstr(current_wd, wp[0])) == NULL) {
			bi_errorf("bad substitution");
			return (2);
		}
		/*-
		 * ilen = part of current_wd before wp[0]
		 * elen = part of current_wd after wp[0]
		 * because current_wd and wp[1] need to be in memory at the
		 * same time beforehand the addition can stay unchecked
		 */
		ilen = cp - current_wd;
		olen = strlen(wp[0]);
		nlen = strlen(wp[1]);
		elen = strlen(current_wd + ilen + olen) + 1;
		dir = allocd = alloc(ilen + nlen + elen, ATEMP);
		memcpy(dir, current_wd, ilen);
		memcpy(dir + ilen, wp[1], nlen);
		memcpy(dir + ilen + nlen, current_wd + ilen + olen, elen);
		printpath = true;
	} else {
		bi_errorf("too many arguments");
		return (2);
	}

#ifdef MKSH__NO_PATH_MAX
	/* only a first guess; make_path will enlarge xs if necessary */
	XinitN(xs, 1024, ATEMP);
#else
	XinitN(xs, PATH_MAX, ATEMP);
#endif

	cdpath = str_val(global("CDPATH"));
	do {
		cdnode = make_path(current_wd, dir, &cdpath, &xs, &phys_path);
		if (physical)
			rv = chdir(tryp = Xstring(xs, xp) + phys_path);
		else {
			simplify_path(Xstring(xs, xp));
			rv = chdir(tryp = Xstring(xs, xp));
		}
	} while (rv < 0 && cdpath != NULL);

	if (rv < 0) {
		if (cdnode)
			bi_errorf("%s: %s", dir, "bad directory");
		else
			bi_errorf("%s: %s", tryp, cstrerror(errno));
		afree(allocd, ATEMP);
		Xfree(xs, xp);
		return (2);
	}

	rv = 0;

	/* allocd (above) => dir, which is no longer used */
	afree(allocd, ATEMP);
	allocd = NULL;

	/* Clear out tracked aliases with relative paths */
	flushcom(false);

	/*
	 * Set OLDPWD (note: unsetting OLDPWD does not disable this
	 * setting in AT&T ksh)
	 */
	if (current_wd[0])
		/* Ignore failure (happens if readonly or integer) */
		setstr(oldpwd_s, current_wd, KSH_RETURN_ERROR);

	if (!mksh_abspath(Xstring(xs, xp))) {
		pwd = NULL;
	} else if (!physical) {
		goto norealpath_PWD;
	} else if ((pwd = allocd = do_realpath(Xstring(xs, xp))) == NULL) {
		if (eflag)
			rv = 1;
 norealpath_PWD:
		pwd = Xstring(xs, xp);
	}

	/* Set PWD */
	if (pwd) {
		char *ptmp = pwd;

		set_current_wd(ptmp);
		/* Ignore failure (happens if readonly or integer) */
		setstr(pwd_s, ptmp, KSH_RETURN_ERROR);
	} else {
		set_current_wd(null);
		pwd = Xstring(xs, xp);
		/* XXX unset $PWD? */
		if (eflag)
			rv = 1;
	}
	if (printpath || cdnode)
		shprintf("%s\n", pwd);

	afree(allocd, ATEMP);
	Xfree(xs, xp);
	return (rv);
}
Example #13
0
File: c_sh.c Project: tomgrean/kash
int
c_trap(char **wp)
{
	int i;
	char *s;
	 Trap *p;

	if (ksh_getopt(wp, &builtin_opt, null) == '?')
		return 1;
	wp += builtin_opt.optind;

	if (*wp == NULL) {
#if 0/*defined but not used*/
		int anydfl = 0;
#endif

		for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) {
			if (p->trap == NULL) {
#if 0/*defined but not used*/
				anydfl = 1;
#endif
			} else {
				shprintf("trap -- ");
				print_value_quoted(p->trap);
				shprintf(" %s\n", p->name);
			}
		}
#if 0 /* this is ugly and not clear POSIX needs it */
		/* POSIX may need this so output of trap can be saved and
		 * used to restore trap conditions
		 */
		if (anydfl) {
			shprintf("trap -- -");
			for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
				if (p->trap == NULL && p->name)
					shprintf(" %s", p->name);
			shprintf(newline);
		}
#endif
		return 0;
	}

	/*
	 * Use case sensitive lookup for first arg so the
	 * command 'exit' isn't confused with the pseudo-signal
	 * 'EXIT'.
	 */
	s = (gettrap(*wp, false) == NULL) ? *wp++ : NULL; /* get command */
	if (s != NULL && s[0] == '-' && s[1] == '\0')
		s = NULL;

	/* set/clear traps */
	while (*wp != NULL) {
		p = gettrap(*wp++, true);
		if (p == NULL) {
			bi_errorf("bad signal %s", wp[-1]);
			return 1;
		}
		settrap(p, s);
	}
	return 0;
}
Example #14
0
int
c_ulimit(char **wp)
{
	static const struct limits limits[] = {
		/* Do not use options -H, -S or -a or change the order. */
		{ "time(cpu-seconds)", RLIMIT_CPU, 1, 't' },
		{ "file(blocks)", RLIMIT_FSIZE, 512, 'f' },
		{ "coredump(blocks)", RLIMIT_CORE, 512, 'c' },
		{ "data(kbytes)", RLIMIT_DATA, 1024, 'd' },
		{ "stack(kbytes)", RLIMIT_STACK, 1024, 's' },
		{ "lockedmem(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' },
		{ "memory(kbytes)", RLIMIT_RSS, 1024, 'm' },
		{ "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' },
		{ "processes", RLIMIT_NPROC, 1, 'p' },
		{ NULL }
	};
	const char	*options = "HSat#f#c#d#s#l#m#n#p#";
	int		how = SOFT | HARD;
	const struct limits	*l;
	int		optc, all = 0;

	/* First check for -a, -H and -S. */
	while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
		switch (optc) {
		case 'H':
			how = HARD;
			break;
		case 'S':
			how = SOFT;
			break;
		case 'a':
			all = 1;
			break;
		case '?':
			return 1;
		default:
			break;
		}

	if (wp[builtin_opt.optind] != NULL) {
		bi_errorf("usage: ulimit [-acdfHlmnpSst] [value]");
		return 1;
	}

	/* Then parse and act on the actual limits, one at a time */
	ksh_getopt_reset(&builtin_opt, GF_ERROR);
	while ((optc = ksh_getopt(wp, &builtin_opt, options)) != -1)
		switch (optc) {
		case 'a':
		case 'H':
		case 'S':
			break;
		case '?':
			return 1;
		default:
			for (l = limits; l->name && l->option != optc; l++)
				;
			if (!l->name) {
				internal_warningf("%s: %c", __func__, optc);
				return 1;
			}
			if (builtin_opt.optarg) {
				if (set_ulimit(l, builtin_opt.optarg, how))
					return 1;
			} else
				print_ulimit(l, how);
			break;
		}

	wp += builtin_opt.optind;

	if (all) {
		for (l = limits; l->name; l++) {
			shprintf("%-20s ", l->name);
			print_ulimit(l, how);
		}
	} else if (builtin_opt.optind == 1) {
		/* No limit specified, use file size */
		l = &limits[1];
		if (wp[0] != NULL) {
			if (set_ulimit(l, wp[0], how))
				return 1;
			wp++;
		} else {
			print_ulimit(l, how);
		}
	}

	return 0;
}