agetty: add an autologin feature
Add an autologin feature to agetty, that is that a user can be automatically logged in. For this the options of for the login program has to used. Make it possible to pass-through options to the login program which requires a security check. Signed-off-by: Werner Fink <werner@suse.de>
This commit is contained in:
parent
1683f6bf20
commit
eb8e1f9f0c
|
@ -4,6 +4,7 @@ agetty \- alternative Linux getty
|
||||||
|
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.BR "agetty " [\-8chiLmnsUw]
|
.BR "agetty " [\-8chiLmnsUw]
|
||||||
|
.RI "[-a " user ]
|
||||||
.RI "[-f " issue_file ]
|
.RI "[-f " issue_file ]
|
||||||
.RI "[-H " login_host ]
|
.RI "[-H " login_host ]
|
||||||
.RI "[-I " init ]
|
.RI "[-I " init ]
|
||||||
|
@ -85,6 +86,11 @@ whatever init(8) may have set, and is inherited by login and the shell.
|
||||||
\-8, \-\-8bits
|
\-8, \-\-8bits
|
||||||
Assume that the tty is 8-bit clean, hence disable parity detection.
|
Assume that the tty is 8-bit clean, hence disable parity detection.
|
||||||
.TP
|
.TP
|
||||||
|
\-a, \-\-autologin \fIusername\fP
|
||||||
|
Log the specified user automatically in without asking for a login
|
||||||
|
name and password. Check the -f option from
|
||||||
|
\fB/bin/login\fP for this.
|
||||||
|
.TP
|
||||||
\-c, \-\-noreset
|
\-c, \-\-noreset
|
||||||
Don't reset terminal cflags (control modes). See \fItermios(3)\fP for more
|
Don't reset terminal cflags (control modes). See \fItermios(3)\fP for more
|
||||||
details.
|
details.
|
||||||
|
@ -152,6 +158,16 @@ space parity, 7 bit characters, and ASCII CR (13) end-of-line character.
|
||||||
Beware that the program that \fBagetty\fR starts (usually /bin/login)
|
Beware that the program that \fBagetty\fR starts (usually /bin/login)
|
||||||
is run as root.
|
is run as root.
|
||||||
.TP
|
.TP
|
||||||
|
\-o, \-\-logopts \fI"login_options"\fP
|
||||||
|
Options that are passed to the login program. \\u is replaced
|
||||||
|
by the login name. Defaults to "-- \\u", which is suitable for
|
||||||
|
\fB/bin/login\fP. Please read the SECURITY NOTICE below if
|
||||||
|
you want to use this.
|
||||||
|
.TP
|
||||||
|
\-p, \-\-loginpause
|
||||||
|
Wait for any key before dropping to the login prompt. Can be combined
|
||||||
|
with \fB\-\-autologin\fP to save memory by lazily spawning shells.
|
||||||
|
.TP
|
||||||
\-R, \-\-hangup
|
\-R, \-\-hangup
|
||||||
Do call vhangup() for a virtually hangup of the specified terminal.
|
Do call vhangup() for a virtually hangup of the specified terminal.
|
||||||
.TP
|
.TP
|
||||||
|
@ -207,6 +223,19 @@ dis-connection and turn on auto-answer after 1 ring.)
|
||||||
.ti +5
|
.ti +5
|
||||||
/sbin/agetty \-w \-I 'ATE0Q1&D2&C1S0=1\\015' 115200 ttyS1
|
/sbin/agetty \-w \-I 'ATE0Q1&D2&C1S0=1\\015' 115200 ttyS1
|
||||||
|
|
||||||
|
.SH SECURITY NOTICE
|
||||||
|
If you use the \fB\-\-login\fP and \fB\-\-logopts\fP options, be aware
|
||||||
|
that a malicious user may try to enter lognames with embedded options,
|
||||||
|
which then get passed to the used login program. Agetty does check
|
||||||
|
for a leading - and makes sure the logname gets passed as one parameter
|
||||||
|
(so embedded spaces will not create yet another parameter), but depending
|
||||||
|
on how the login binary parses the command line that might not be sufficient.
|
||||||
|
Check that the used login program can not be abused this way.
|
||||||
|
.PP
|
||||||
|
Some programs use -- to indicate that the rest of the commandline should
|
||||||
|
not be interpreted as options. Use this feature if available by passing -- before
|
||||||
|
the username gets passed by \\u.
|
||||||
|
|
||||||
.SH ISSUE ESCAPES
|
.SH ISSUE ESCAPES
|
||||||
The issue-file (\fI/etc/issue\fP or the file set with the \-f option)
|
The issue-file (\fI/etc/issue\fP or the file set with the \-f option)
|
||||||
may contain certain escape codes to display the system name, date and
|
may contain certain escape codes to display the system name, date and
|
||||||
|
|
|
@ -93,7 +93,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Login prompt. */
|
/* Login prompt. */
|
||||||
#define LOGIN " login: "
|
#define LOGIN " login: "
|
||||||
|
#define ARRAY_SIZE_MAX 16 /* Numbers of args for login beside "-- \\u" */
|
||||||
|
|
||||||
/* Some shorthands for control characters. */
|
/* Some shorthands for control characters. */
|
||||||
#define CTL(x) (x ^ 0100) /* Assumes ASCII dialect */
|
#define CTL(x) (x ^ 0100) /* Assumes ASCII dialect */
|
||||||
|
@ -131,7 +132,9 @@
|
||||||
struct options {
|
struct options {
|
||||||
int flags; /* toggle switches, see below */
|
int flags; /* toggle switches, see below */
|
||||||
int timeout; /* time-out period */
|
int timeout; /* time-out period */
|
||||||
|
char *autolog; /* login the user automatically */
|
||||||
char *login; /* login program */
|
char *login; /* login program */
|
||||||
|
char *logopt; /* options for login program */
|
||||||
char *tty; /* name of tty */
|
char *tty; /* name of tty */
|
||||||
char *vcline; /* line of virtual console */
|
char *vcline; /* line of virtual console */
|
||||||
char *term; /* terminal type */
|
char *term; /* terminal type */
|
||||||
|
@ -156,6 +159,7 @@ struct options {
|
||||||
#define F_VCONSOLE (1<<12) /* This is a virtual console */
|
#define F_VCONSOLE (1<<12) /* This is a virtual console */
|
||||||
#define F_HANGUP (1<<13) /* Do call vhangup(2) */
|
#define F_HANGUP (1<<13) /* Do call vhangup(2) */
|
||||||
#define F_UTF8 (1<<14) /* We can do UTF8 */
|
#define F_UTF8 (1<<14) /* We can do UTF8 */
|
||||||
|
#define F_LOGINPAUSE (1<<15) /* Wait for any key before dropping login prompt */
|
||||||
|
|
||||||
#define serial_tty_option(opt, flag) \
|
#define serial_tty_option(opt, flag) \
|
||||||
(((opt)->flags & (F_VCONSOLE|(flag))) == (flag))
|
(((opt)->flags & (F_VCONSOLE|(flag))) == (flag))
|
||||||
|
@ -241,6 +245,9 @@ static speed_t bcode(char *s);
|
||||||
static void usage(FILE * out) __attribute__((__noreturn__));
|
static void usage(FILE * out) __attribute__((__noreturn__));
|
||||||
static void log_err(const char *, ...) __attribute__((__noreturn__)) __attribute__((__format__(printf, 1, 2)));
|
static void log_err(const char *, ...) __attribute__((__noreturn__)) __attribute__((__format__(printf, 1, 2)));
|
||||||
static void log_warn (const char *, ...) __attribute__((__format__(printf, 1, 2)));
|
static void log_warn (const char *, ...) __attribute__((__format__(printf, 1, 2)));
|
||||||
|
static void checkname (const char* nm);
|
||||||
|
static void replacename (char** arr, const char* nm);
|
||||||
|
static void mkarray (char** arr, char* str);
|
||||||
|
|
||||||
/* Fake hostname for ut_host specified on command line. */
|
/* Fake hostname for ut_host specified on command line. */
|
||||||
static char *fakehost;
|
static char *fakehost;
|
||||||
|
@ -254,20 +261,18 @@ FILE *dbf;
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
char *logname = NULL; /* login name, given to /bin/login */
|
char *logname = NULL; /* login name, given to /bin/login */
|
||||||
struct chardata chardata; /* will be set by get_logname() */
|
char logcmd[NAME_MAX+1];
|
||||||
struct termios termios; /* terminal mode bits */
|
char *logarr[ARRAY_SIZE_MAX + 2]; /* arguments plus "-- \\u" */
|
||||||
|
struct chardata chardata; /* will be set by get_logname() */
|
||||||
|
struct termios termios; /* terminal mode bits */
|
||||||
static struct options options = {
|
static struct options options = {
|
||||||
F_ISSUE, /* show /etc/issue (SYSV_STYLE) */
|
.flags = F_ISSUE, /* show /etc/issue (SYSV_STYLE) */
|
||||||
0, /* no timeout */
|
.login = _PATH_LOGIN, /* default login program */
|
||||||
_PATH_LOGIN, /* default login program */
|
.logopt = "-- \\u", /* escape for user name */
|
||||||
"tty1", /* default tty line */
|
.tty = "tty1", /* default tty line */
|
||||||
0, /* line of virtual console */
|
.term = DEFAULT_VCTERM, /* terminal type */
|
||||||
DEFAULT_VCTERM, /* terminal type */
|
.issue = ISSUE /* default issue file */
|
||||||
"", /* modem init string */
|
|
||||||
ISSUE, /* default issue file */
|
|
||||||
0, /* no baud rates known yet */
|
|
||||||
{ 0 }
|
|
||||||
};
|
};
|
||||||
struct sigaction sa, sa_hup, sa_quit, sa_int;
|
struct sigaction sa, sa_hup, sa_quit, sa_int;
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
|
@ -315,7 +320,8 @@ int main(int argc, char **argv)
|
||||||
termio_init(&options, &termios);
|
termio_init(&options, &termios);
|
||||||
|
|
||||||
/* Write the modem init string and DO NOT flush the buffers. */
|
/* Write the modem init string and DO NOT flush the buffers. */
|
||||||
if (serial_tty_option(&options, F_INITSTRING)) {
|
if (serial_tty_option(&options, F_INITSTRING) &&
|
||||||
|
options.initstring && *options.initstring != '\0') {
|
||||||
debug("writing init string\n");
|
debug("writing init string\n");
|
||||||
write_all(STDOUT_FILENO, options.initstring,
|
write_all(STDOUT_FILENO, options.initstring,
|
||||||
strlen(options.initstring));
|
strlen(options.initstring));
|
||||||
|
@ -353,12 +359,21 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
chardata = init_chardata;
|
chardata = init_chardata;
|
||||||
if ((options.flags & F_NOPROMPT) == 0) {
|
if ((options.flags & F_NOPROMPT) == 0) {
|
||||||
/* Read the login name. */
|
if (options.autolog) {
|
||||||
debug("reading login name\n");
|
/* Do the auto login */
|
||||||
while ((logname =
|
debug("doing auto login\n");
|
||||||
get_logname(&options, &termios, &chardata)) == 0)
|
do_prompt(&options, &termios);
|
||||||
if ((options.flags & F_VCONSOLE) == 0)
|
printf ("%s%s (automatic login)\n", LOGIN, options.autolog);
|
||||||
next_speed(&options, &termios);
|
logname = options.autolog;
|
||||||
|
options.logopt = "-f \\u";
|
||||||
|
} else {
|
||||||
|
/* Read the login name. */
|
||||||
|
debug("reading login name\n");
|
||||||
|
while ((logname =
|
||||||
|
get_logname(&options, &termios, &chardata)) == 0)
|
||||||
|
if ((options.flags & F_VCONSOLE) == 0)
|
||||||
|
next_speed(&options, &termios);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable timer. */
|
/* Disable timer. */
|
||||||
|
@ -376,8 +391,16 @@ int main(int argc, char **argv)
|
||||||
sigaction (SIGQUIT, &sa_quit, NULL);
|
sigaction (SIGQUIT, &sa_quit, NULL);
|
||||||
sigaction (SIGINT, &sa_int, NULL);
|
sigaction (SIGINT, &sa_int, NULL);
|
||||||
|
|
||||||
|
strncpy(logcmd, options.login, NAME_MAX);
|
||||||
|
strncat(logcmd, " ", NAME_MAX - strlen(logcmd));
|
||||||
|
strncat(logcmd, options.logopt, NAME_MAX - strlen(logcmd));
|
||||||
|
|
||||||
|
checkname(logname);
|
||||||
|
mkarray(logarr, logcmd);
|
||||||
|
replacename(logarr, logname);
|
||||||
|
|
||||||
/* Let the login program take care of password validation. */
|
/* Let the login program take care of password validation. */
|
||||||
execl(options.login, options.login, "--", logname, NULL);
|
execv(options.login, logarr);
|
||||||
log_err(_("%s: can't exec %s: %m"), options.tty, options.login);
|
log_err(_("%s: can't exec %s: %m"), options.tty, options.login);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,6 +417,7 @@ static void parse_args(int argc, char **argv, struct options *op)
|
||||||
};
|
};
|
||||||
const struct option longopts[] = {
|
const struct option longopts[] = {
|
||||||
{ "8bits", no_argument, 0, '8' },
|
{ "8bits", no_argument, 0, '8' },
|
||||||
|
{ "autologin", required_argument, 0, 'a' },
|
||||||
{ "noreset", no_argument, 0, 'c' },
|
{ "noreset", no_argument, 0, 'c' },
|
||||||
{ "issue-file", required_argument, 0, 'f' },
|
{ "issue-file", required_argument, 0, 'f' },
|
||||||
{ "flow-control", no_argument, 0, 'h' },
|
{ "flow-control", no_argument, 0, 'h' },
|
||||||
|
@ -404,6 +428,10 @@ static void parse_args(int argc, char **argv, struct options *op)
|
||||||
{ "local-line", no_argument, 0, 'L' },
|
{ "local-line", no_argument, 0, 'L' },
|
||||||
{ "extract-baud", no_argument, 0, 'm' },
|
{ "extract-baud", no_argument, 0, 'm' },
|
||||||
{ "skip-login", no_argument, 0, 'n' },
|
{ "skip-login", no_argument, 0, 'n' },
|
||||||
|
{ "login-options", required_argument, 0, 'o' },
|
||||||
|
{ "loginopts", required_argument, 0, 'o' }, /* compat option */
|
||||||
|
{ "logopts", required_argument, 0, 'o' }, /* compat option */
|
||||||
|
{ "loginpause", no_argument, 0, 'p' },
|
||||||
{ "hangup", no_argument, 0, 'R' },
|
{ "hangup", no_argument, 0, 'R' },
|
||||||
{ "keep-baud", no_argument, 0, 's' },
|
{ "keep-baud", no_argument, 0, 's' },
|
||||||
{ "timeout", required_argument, 0, 't' },
|
{ "timeout", required_argument, 0, 't' },
|
||||||
|
@ -414,12 +442,15 @@ static void parse_args(int argc, char **argv, struct options *op)
|
||||||
{ NULL, 0, 0, 0 }
|
{ NULL, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "8cf:hH:iI:l:LmnsRt:Uw", longopts,
|
while ((c = getopt_long(argc, argv, "8a:cf:hH:iI:l:Lmno:pRst:Uw", longopts,
|
||||||
NULL)) != -1) {
|
NULL)) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '8':
|
case '8':
|
||||||
op->flags |= F_EIGHTBITS;
|
op->flags |= F_EIGHTBITS;
|
||||||
break;
|
break;
|
||||||
|
case 'a':
|
||||||
|
op->autolog = optarg;
|
||||||
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
op->flags |= F_KEEPCFLAGS;
|
op->flags |= F_KEEPCFLAGS;
|
||||||
break;
|
break;
|
||||||
|
@ -452,6 +483,12 @@ static void parse_args(int argc, char **argv, struct options *op)
|
||||||
case 'n':
|
case 'n':
|
||||||
op->flags |= F_NOPROMPT;
|
op->flags |= F_NOPROMPT;
|
||||||
break;
|
break;
|
||||||
|
case 'o':
|
||||||
|
op->logopt = optarg;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
op->flags |= F_LOGINPAUSE;
|
||||||
|
break;
|
||||||
case 'R':
|
case 'R':
|
||||||
op->flags |= F_HANGUP;
|
op->flags |= F_HANGUP;
|
||||||
break;
|
break;
|
||||||
|
@ -1066,14 +1103,73 @@ static void do_prompt(struct options *op, struct termios *tp)
|
||||||
}
|
}
|
||||||
fclose(fd);
|
fclose(fd);
|
||||||
}
|
}
|
||||||
#endif /* ISSUE */
|
#endif /* ISSUE */
|
||||||
|
if (op->flags & F_LOGINPAUSE) {
|
||||||
|
puts("[press ENTER to login]");
|
||||||
|
getc(stdin);
|
||||||
|
}
|
||||||
|
#ifdef KDGKBLED
|
||||||
|
if (op->autolog == (char*)0 && (op->flags & F_VCONSOLE)) {
|
||||||
|
int kb = 0, nl = 0;
|
||||||
|
struct stat st;
|
||||||
|
if (stat("/var/run/numlock-on", &st) == 0)
|
||||||
|
nl = 1;
|
||||||
|
if (ioctl(STDIN_FILENO, KDGKBLED, &kb) == 0) {
|
||||||
|
const char *hint = _("Hint: ");
|
||||||
|
char warn[256];
|
||||||
|
off_t space = sizeof(warn) - 1, off = 0;
|
||||||
|
|
||||||
|
if (nl && (kb & 0x02) == 0) {
|
||||||
|
const char *msg = _("Num Lock off");
|
||||||
|
const size_t len = strlen(msg);
|
||||||
|
strncpy(&warn[0], msg, space);
|
||||||
|
space -= len;
|
||||||
|
off += len;
|
||||||
|
} else if (nl == 0 && (kb & 2) && (kb & 0x20) == 0) {
|
||||||
|
const char *msg = _("Num Lock on");
|
||||||
|
const size_t len = strlen(msg);
|
||||||
|
strncpy(&warn[0], msg, space);
|
||||||
|
space -= len;
|
||||||
|
off += len;
|
||||||
|
}
|
||||||
|
if ((kb & 0x04) && (kb & 0x40) == 0) {
|
||||||
|
const char *msg = _("Caps Lock on");
|
||||||
|
const size_t len = strlen(msg);
|
||||||
|
if (off) {
|
||||||
|
strncpy(&warn[off], ", ", space);
|
||||||
|
space -= 2;
|
||||||
|
off += 2;
|
||||||
|
}
|
||||||
|
strncpy(&warn[off], msg, space);
|
||||||
|
space -= len;
|
||||||
|
off += len;
|
||||||
|
}
|
||||||
|
if ((kb & 0x01) && (kb & 0x10) == 0) {
|
||||||
|
const char *msg = _("Scroll Lock on");
|
||||||
|
const size_t len = strlen(msg);
|
||||||
|
if (off) {
|
||||||
|
strncpy(&warn[off], ", ", space);
|
||||||
|
space -= 2;
|
||||||
|
off += 2;
|
||||||
|
}
|
||||||
|
strncpy(&warn[off], msg, space);
|
||||||
|
space -= len;
|
||||||
|
off += len;
|
||||||
|
}
|
||||||
|
if (off)
|
||||||
|
printf ("%s%s\n\n", hint, warn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* KDGKBLED */
|
||||||
{
|
{
|
||||||
char hn[MAXHOSTNAMELEN + 1];
|
char hn[MAXHOSTNAMELEN + 1];
|
||||||
if (gethostname(hn, sizeof(hn)) == 0)
|
if (gethostname(hn, sizeof(hn)) == 0)
|
||||||
write_all(STDOUT_FILENO, hn, strlen(hn));
|
write_all(STDOUT_FILENO, hn, strlen(hn));
|
||||||
}
|
}
|
||||||
/* Always show login prompt. */
|
if (op->autolog == (char*)0) {
|
||||||
write_all(STDOUT_FILENO, LOGIN, sizeof(LOGIN) - 1);
|
/* Always show login prompt. */
|
||||||
|
write_all(STDOUT_FILENO, LOGIN, sizeof(LOGIN) - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Select next baud rate. */
|
/* Select next baud rate. */
|
||||||
|
@ -1360,6 +1456,7 @@ static void __attribute__ ((__noreturn__)) usage(FILE * out)
|
||||||
|
|
||||||
fprintf(out, _("\nOptions:\n"
|
fprintf(out, _("\nOptions:\n"
|
||||||
" -8, --8bits assume 8-bit tty\n"
|
" -8, --8bits assume 8-bit tty\n"
|
||||||
|
" -a, --autologin USER login the specified user automatically\n"
|
||||||
" -c, --noreset do not reset control mode\n"
|
" -c, --noreset do not reset control mode\n"
|
||||||
" -f, --issue-file FILE display issue file\n"
|
" -f, --issue-file FILE display issue file\n"
|
||||||
" -h, --flow-control enable hardware flow control\n"
|
" -h, --flow-control enable hardware flow control\n"
|
||||||
|
@ -1370,6 +1467,8 @@ static void __attribute__ ((__noreturn__)) usage(FILE * out)
|
||||||
" -L, --local-line force local line\n"
|
" -L, --local-line force local line\n"
|
||||||
" -m, --extract-baud extract baud rate during connect\n"
|
" -m, --extract-baud extract baud rate during connect\n"
|
||||||
" -n, --skip-login do not prompt for login\n"
|
" -n, --skip-login do not prompt for login\n"
|
||||||
|
" -o, --login-options OPTS options that are passed to login\n"
|
||||||
|
" -p, --loginpause wait for any key before the login\n"
|
||||||
" -R, --hangup do virtually hangup on the tty\n"
|
" -R, --hangup do virtually hangup on the tty\n"
|
||||||
" -s, --keep-baud try to keep baud rate after break\n"
|
" -s, --keep-baud try to keep baud rate after break\n"
|
||||||
" -t, --timeout NUMBER login process timeout\n"
|
" -t, --timeout NUMBER login process timeout\n"
|
||||||
|
@ -1603,3 +1702,71 @@ static void init_special_char(char* arg, struct options *op)
|
||||||
}
|
}
|
||||||
*q = '\0';
|
*q = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do not allow the user to pass an option as a user name
|
||||||
|
* To be more safe: Use `--' to make sure the rest is
|
||||||
|
* interpreted as non-options by the program, if it supports it.
|
||||||
|
*/
|
||||||
|
static void checkname(const char* nm)
|
||||||
|
{
|
||||||
|
const char *p = nm;
|
||||||
|
if (!nm)
|
||||||
|
goto err;
|
||||||
|
if (strlen (nm) > 42)
|
||||||
|
goto err;
|
||||||
|
while (isspace (*p))
|
||||||
|
p++;
|
||||||
|
if (*p == '-')
|
||||||
|
goto err;
|
||||||
|
return;
|
||||||
|
err:
|
||||||
|
errno = EPERM;
|
||||||
|
log_err ("checkname: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void replacename(char** arr, const char* nm)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
char *tmp;
|
||||||
|
while ((p = *arr)) {
|
||||||
|
const char *p1 = p;
|
||||||
|
while (*p1) {
|
||||||
|
if (memcmp (p1, "\\u", 2) == 0) {
|
||||||
|
tmp = malloc (strlen (p) + strlen (nm));
|
||||||
|
if (!tmp)
|
||||||
|
log_err ("replacename: %m");
|
||||||
|
if (p1 != p)
|
||||||
|
memcpy (tmp, p, (p1-p));
|
||||||
|
*(tmp + (p1-p)) = 0;
|
||||||
|
strcat (tmp, nm);
|
||||||
|
strcat (tmp, p1+2);
|
||||||
|
*arr = tmp;
|
||||||
|
}
|
||||||
|
p1++;
|
||||||
|
}
|
||||||
|
arr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mkarray(char** arr, char* str)
|
||||||
|
{
|
||||||
|
char* p = str;
|
||||||
|
char* start = p;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (*p && i < (ARRAY_SIZE_MAX)) {
|
||||||
|
if (isspace (*p)) {
|
||||||
|
*p = 0;
|
||||||
|
while (isspace (*++p))
|
||||||
|
;
|
||||||
|
if (*p) {
|
||||||
|
arr[i++] = start;
|
||||||
|
start = p;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
arr[i++] = start;
|
||||||
|
arr[i++] = (char*)0;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue