Imported from conserver-7.1.2.tar.gz

This commit is contained in:
Bryan Stansell 2001-10-15 22:49:17 -07:00
parent 03aa79c53d
commit d8b3cd4fb9
18 changed files with 800 additions and 408 deletions

20
CHANGES
View File

@ -1,6 +1,24 @@
CHANGES
=======
version 7.1.2 (Oct 15, 2001):
- fixed line-based timestamp code - reported by Benn Oshrin
<benno@columbia.edu>
- tcp_wrappers support (--with-libwrap)
- CLOCAL bit set for local ports - patch by Egan Ford
<egan@us.ibm.com>
- timestamp added to 'lost carrier' error - suggested by Todd
Stansell <todd@stansell.org>
- Alternate break sequence for Solaris 8 is available as ^ecl2
escape sequence - patch by William Charles
<william.charles@db.com>
The following suggested by Trevor Fiatal <trevor@seven.com>
- Widened username field of 'console -w' output
- Added server hostname to password entry prompt
- AC_CHECK_LIB replaced with AC_SEARCH_LIBS in configure.in so
that irrelavent (and sometimes incompatible) libraries aren't
linked in
version 7.1.1 (Aug 4, 2001):
- Now using getlogin() for real username info - suggested by
Dave Stuit <djs@gnac.com>
@ -222,5 +240,5 @@ before version 6.05:
and enhancements of various types were applied.
#
# $Id: CHANGES,v 1.45 2001-08-04 21:09:12-07 bryan Exp $
# $Id: CHANGES,v 1.48 2001-10-15 22:37:08-07 bryan Exp $
#

13
README
View File

@ -17,7 +17,18 @@ Downloading
The latest version can be found at http://www.conserver.com/
Contributions
Contributions distributed with the code can be found in the contrib
subdirectory. Other tools that complement conserver are listed
below.
Zinc
----
According to the website, Zinc is a console log output management
program. For more information, visit the website at:
http://www.columbia.edu/acis/sy/unixdev/zinc
#
# $Id: README,v 1.16 2001-06-15 04:34:31-07 bryan Exp $
# $Id: README,v 1.17 2001-10-15 16:58:45-07 bryan Exp $
#

31
TODO
View File

@ -9,6 +9,9 @@ Bryan Stansell
---------------------------------------------------------------------------
- Singular logging so that swatch/logsurfer can watch for errors across
the board - unloved output comes close
- Telnet protocol should be improved
- Not even RFC 854 compliant
- Data sent to terminal server not encapsulated
@ -47,7 +50,9 @@ Bryan Stansell
- "listen" capability (watch all/multiple consoles)
- alternate break (^ecl2?)
- alternate break (^ecl2) sends 'CR-~-^B' sequence (solaris 8 default)
- probably should be able to redefine it like the escape sequence
- to support older alt-break code it would need .5 second delays
- aliases for console entries
@ -79,11 +84,33 @@ Bryan Stansell
- logfile rotation based on size
- automatic log rotation in general : Egan Ford <egan@us.ibm.com>
- website docs on serial port configs
- PCs (solaris x86, linux, *bsd, etc)
- lilo
- bios support
- suggestions by Trevor Fiatal <trevor@seven.com>
- include server hostname on 'console -x' output
- non-interactively be able to
- disconnect a single user-to-port session
- disconnect all sessions to a given port
- disconnect all sessions registered to a particular user
- non-interactively be able to send messages to
- all sessions open by a particular user
console -t user "Time to go home."
- a particular user-session
console -t user@managed-host "Please disconnect from this host."
- all users on a given host
console -t @managed-host "I am taking over this host."
- support 2 stop bits (as well as other stty-type options in console
definitions) : Kelly Setzer <setzer@placemark.com>
- try to reopen downed console (from loss of carrier, maybe other
things) once instead of leaving it down.
#
# $Id: TODO,v 1.12 2001-07-30 23:28:56-07 bryan Exp $
# $Id: TODO,v 1.15 2001-10-15 17:19:17-07 bryan Exp $
#

View File

@ -47,3 +47,8 @@
* pidfile to write to
*/
#undef PIDFILE
/*
* use tcp_wrappers libwrap
*/
#undef USE_LIBWRAP

View File

@ -49,6 +49,11 @@
*/
#undef PIDFILE
/*
* use tcp_wrappers libwrap
*/
#undef USE_LIBWRAP
/* Define if you have the <crypt.h> header file. */
#undef HAVE_CRYPT_H
@ -91,15 +96,6 @@
/* Define if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define if you have the `crypt' library (-lcrypt). */
#undef HAVE_LIBCRYPT
/* Define if you have the `nsl' library (-lnsl). */
#undef HAVE_LIBNSL
/* Define if you have the `socket' library (-lsocket). */
#undef HAVE_LIBSOCKET
/* Define if you have the `memcmp' function. */
#undef HAVE_MEMCMP

929
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@ AC_SUBST(MKDIR)
dnl ### Custom settings. ############################################
AC_MSG_CHECKING(for port number specification)
AC_ARG_WITH(port,
AC_HELP_STRING([--with-port=PORT],[Specify port number [[conserver]]]),
AC_HELP_STRING([--with-port=PORT],[Specify port number @<:@conserver@:>@]),
[if test "$withval" != yes -a "$withval" != no; then
AC_DEFINE_UNQUOTED(DEFPORT, "$withval")
AC_MSG_RESULT(port '$withval')
@ -27,7 +27,7 @@ AC_ARG_WITH(port,
AC_MSG_CHECKING(for secondary channel base port)
AC_ARG_WITH(base,
AC_HELP_STRING([--with-base=PORT], [Base port for secondary channel [[0]]]),
AC_HELP_STRING([--with-base=PORT], [Base port for secondary channel @<:@0@:>@]),
[if test "$withval" != yes -a "$withval" != no; then
AC_DEFINE_UNQUOTED(DEFBASEPORT, "$withval")
AC_MSG_RESULT(port '$withval')
@ -40,7 +40,7 @@ AC_ARG_WITH(base,
AC_MSG_CHECKING(for master conserver hostname)
AC_ARG_WITH(master,
AC_HELP_STRING([--with-master=MASTER],[Specify master server hostname [[console]]]),
AC_HELP_STRING([--with-master=MASTER],[Specify master server hostname @<:@console@:>@]),
[if test "$withval" != yes; then
AC_DEFINE_UNQUOTED(MASTERHOST, "$withval")
AC_MSG_RESULT('$withval')
@ -53,7 +53,7 @@ AC_ARG_WITH(master,
AC_MSG_CHECKING(for configuration filename)
AC_ARG_WITH(cffile,
AC_HELP_STRING([--with-cffile=CFFILE],[Specify config filename [[conserver.cf]]]),
AC_HELP_STRING([--with-cffile=CFFILE],[Specify config filename @<:@conserver.cf@:>@]),
[if test "$withval" != yes; then
AC_DEFINE_UNQUOTED(CONFIGFILE, "$withval")
AC_MSG_RESULT('$withval')
@ -66,7 +66,7 @@ AC_ARG_WITH(cffile,
AC_MSG_CHECKING(for password filename)
AC_ARG_WITH(pwdfile,
AC_HELP_STRING([--with-pwdfile=PWDFILE],[Specify password filename [[conserver.passwd]]]),
AC_HELP_STRING([--with-pwdfile=PWDFILE],[Specify password filename @<:@conserver.passwd@:>@]),
[if test "$withval" != yes; then
AC_DEFINE_UNQUOTED(PASSWDFILE, "$withval")
AC_MSG_RESULT('$withval')
@ -79,7 +79,7 @@ AC_ARG_WITH(pwdfile,
AC_MSG_CHECKING(for log filename)
AC_ARG_WITH(logfile,
AC_HELP_STRING([--with-logfile=LOGFILE],[Specify log filename [[/var/log/conserver]]]),
AC_HELP_STRING([--with-logfile=LOGFILE],[Specify log filename @<:@/var/log/conserver@:>@]),
[if test "$withval" != yes; then
AC_DEFINE_UNQUOTED(LOGFILEPATH, "$withval")
AC_MSG_RESULT('$withval')
@ -92,7 +92,7 @@ AC_ARG_WITH(logfile,
AC_MSG_CHECKING(for PID filename)
AC_ARG_WITH(pidfile,
AC_HELP_STRING([--with-pidfile=PIDFILE],[Specify PID filepath [[/var/run/conserver.pid]]]),
AC_HELP_STRING([--with-pidfile=PIDFILE],[Specify PID filepath @<:@/var/run/conserver.pid@:>@]),
[if test "$withval" != yes; then
AC_DEFINE_UNQUOTED(PIDFILE, "$withval")
AC_MSG_RESULT('$withval')
@ -105,7 +105,7 @@ AC_ARG_WITH(pidfile,
AC_MSG_CHECKING(for MAXMEMB setting)
AC_ARG_WITH(maxmemb,
AC_HELP_STRING([--with-maxmemb=MAXMEMB],[Specify maximum consoles per process [[16]]]),
AC_HELP_STRING([--with-maxmemb=MAXMEMB],[Specify maximum consoles per process @<:@16@:>@]),
[if test "$withval" != yes; then
AC_DEFINE_UNQUOTED(MAXMEMB, $withval)
AC_MSG_RESULT($withval)
@ -118,7 +118,7 @@ AC_ARG_WITH(maxmemb,
AC_MSG_CHECKING(for MAXGRP setting)
AC_ARG_WITH(maxgrp,
AC_HELP_STRING([--with-maxgrp=MAXGRP],[Specify maximum number of processes [[32]]]),
AC_HELP_STRING([--with-maxgrp=MAXGRP],[Specify maximum number of processes @<:@32@:>@]),
[if test "$withval" != yes; then
AC_DEFINE_UNQUOTED(MAXGRP, $withval)
AC_MSG_RESULT($withval)
@ -131,7 +131,7 @@ AC_ARG_WITH(maxgrp,
AC_MSG_CHECKING(for connect() timeout)
AC_ARG_WITH(timeout,
AC_HELP_STRING([--with-timeout=TIMEOUT],[Specify connect() timeout in seconds [[10]]]),
AC_HELP_STRING([--with-timeout=TIMEOUT],[Specify connect() timeout in seconds @<:@10@:>@]),
[if test "$withval" -gt 0 -o "$withval" -lt 300; then
AC_DEFINE_UNQUOTED(CONNECTTIMEOUT, $withval)
AC_MSG_RESULT($withval)
@ -212,9 +212,50 @@ fi
dnl ### Check for libraries. #######################################
AC_CHECK_LIB(socket,socket)
AC_CHECK_LIB(nsl,gethostbyname)
AC_CHECK_LIB(crypt,crypt)
AC_SEARCH_LIBS(socket,socket)
AC_SEARCH_LIBS(gethostbyname,nsl)
AC_SEARCH_LIBS(crypt,crypt)
AC_SUBST(WRAPLIBS)
AC_SUBST(WRAPINCS)
AC_ARG_WITH(libwrap,
AC_HELP_STRING([--with-libwrap@<:@=PATH@:>@],
[Compile in libwrap (tcp_wrappers) support]),
[if test "$with_libwrap" != "no"; then
if test "$with_libwrap" != "yes"; then
WRAPCPPFLAGS="-I$with_libwrap/include"
WRAPLDFLAGS="-L$with_libwrap/lib"
else
WRAPCPPFLAGS=""
WRAPLDFLAGS=""
fi
oCPPFLAGS="$CPPFLAGS"
oLDFLAGS="$LDFLAGS"
oLIBS="$LIBS"
CPPFLAGS="$CPPFLAGS $WRAPCPPFLAGS"
LDFLAGS="$LDFLAGS $WRAPLDFLAGS"
AC_MSG_CHECKING(for TCP wrappers header tcpd.h)
AC_CHECK_HEADER(tcpd.h,
[LIBS="$LIBS -lwrap"
AC_MSG_CHECKING(for TCP wrappers library -lwrap)
AC_TRY_LINK([#include <tcpd.h>
int allow_severity = 0;
int deny_severity = 0;
],[hosts_access((void *)0)],
[AC_MSG_RESULT(yes)
AC_DEFINE(USE_LIBWRAP)
WRAPLIBS="$WRAPLDFLAGS -lwrap"
WRAPINCS="$WRAPCPPFLAGS"],
[AC_MSG_RESULT(no)])],)
LIBS="$oLIBS"
CPPFLAGS="$oCPPFLAGS"
LDFLAGS="$oLDFLAGS"
fi]
)
dnl ### Check for needed functions. ################################

View File

@ -167,10 +167,10 @@ contrast for yourself.
<P>
The current version, released on RELEASE_DATE, is <A
HREF="http://www.conserver.com/7.1.1.tar.gz">
7.1.1.tar.gz</A>. You can get it via <A
HREF="ftp://ftp.conserver.com/conserver/7.1.1.tar.gz">FTP</A>
or <A HREF="http://www.conserver.com/7.1.1.tar.gz">HTTP</A>.
HREF="http://www.conserver.com/7.1.2.tar.gz">
7.1.2.tar.gz</A>. You can get it via <A
HREF="ftp://ftp.conserver.com/conserver/7.1.2.tar.gz">FTP</A>
or <A HREF="http://www.conserver.com/7.1.2.tar.gz">HTTP</A>.
See the <A HREF="http://www.conserver.com/CHANGES">CHANGES</A> file for
information on the latest updates.
</P>

View File

@ -17,9 +17,9 @@ MKDIR = @MKDIR@
CC = @CC@
CFLAGS = @CFLAGS@ # -DPUCC -DSUN5
DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)\"
CPPFLAGS = -I.. -I$(top_srcdir) -I$(srcdir) $(DEFS) @CPPFLAGS@
CPPFLAGS = -I.. -I$(top_srcdir) -I$(srcdir) $(DEFS) @CPPFLAGS@ @WRAPINCS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
LIBS = @LIBS@ @WRAPLIBS@
@SET_MAKE@

View File

@ -1,5 +1,5 @@
/*
* $Id: client.c,v 5.32 2001-07-23 00:54:11-07 bryan Exp $
* $Id: client.c,v 5.34 2001-10-15 17:24:16-07 bryan Exp $
*
* Copyright conserver.com, 2000-2001
*
@ -213,6 +213,7 @@ static HELP aHLTable[] = {
{WHEN_ALWAYS, "g group info"},
{WHEN_ATTACH, "L toggle logging on/off"},
{WHEN_ATTACH, "l1 send break (halt host!)"},
{WHEN_ATTACH, "l2 send alt. break (halt host!)"},
{WHEN_ALWAYS, "o (re)open the tty and log file"},
{WHEN_ALWAYS, "p replay the last 60 lines"},
{WHEN_ALWAYS, "r replay the last 20 lines"},

View File

@ -1,5 +1,5 @@
/*
* $Id: consent.c,v 5.69 2001-07-29 22:28:40-07 bryan Exp $
* $Id: consent.c,v 5.70 2001-08-28 15:23:04-07 bryan Exp $
*
* Copyright conserver.com, 2000-2001
*
@ -197,7 +197,10 @@ TtyDev(pCE)
*/
termp.c_iflag = IXON | IXOFF | BRKINT;
termp.c_oflag = 0;
termp.c_cflag = CREAD;
/* CLOCAL suggested by egan@us.ibm.com
* carrier transitions result in dropped consoles otherwise
*/
termp.c_cflag = CREAD | CLOCAL;
termp.c_cflag |= pCE->pparity->iset;
termp.c_lflag = 0;
/*

View File

@ -1,5 +1,5 @@
/*
* $Id: group.c,v 5.132 2001-08-04 17:03:30-07 bryan Exp $
* $Id: group.c,v 5.138 2001-10-15 17:17:27-07 bryan Exp $
*
* Copyright conserver.com, 2000-2001
*
@ -72,6 +72,11 @@
#define TELOPTS
#include <arpa/telnet.h>
#if defined(USE_LIBWRAP)
#include <syslog.h>
#include <tcpd.h>
#endif
#include <compat.h>
#include <port.h>
#include <util.h>
@ -285,15 +290,19 @@ writeLog(pCE, s, len)
}
acOut[0] = '\000';
for (j = 0; j < len; j++) {
if (s[j] == '\n') {
Debug("Found newline for %s (nextMark=%d, mark=%d)",
pCE->server, pCE->nextMark, pCE->mark);
(void)fileWrite(pCE->fdlog, s + i, j - i + 1);
i = j + 1;
if (pCE->nextMark == 0) {
(void)fileWrite(pCE->fdlog, s + i, j - i);
i = j;
if (acOut[0] == '\000') {
sprintf(acOut, "[%s]", strtime(NULL));
}
(void)fileWrite(pCE->fdlog, acOut, -1);
pCE->nextMark = pCE->mark;
}
if (s[j] == '\n') {
Debug("Found newline for %s (nextMark=%d, mark=%d)",
pCE->server, pCE->nextMark, pCE->mark);
pCE->nextMark++;
}
}
if (i < j) {
@ -775,9 +784,9 @@ Kiddie(pGE, sfd)
read(pCEServing->fdtty, acInOrig,
sizeof(acInOrig))) <= 0) {
/* carrier lost */
Error("lost carrier on %s (%s)!", pCEServing->server,
Error("lost carrier on %s (%s)! [%s]", pCEServing->server,
pCEServing->fvirtual ? pCEServing->
acslave : pCEServing->dfile);
acslave : pCEServing->dfile, strtime(NULL));
/* If someone was writing, they fall back to read-only */
if (pCEServing->pCLwr != (CONSCLIENT *) 0) {
@ -1295,7 +1304,7 @@ Kiddie(pGE, sfd)
case S_HALT1: /* halt sequence? */
pCLServing->iState = S_NORMAL;
if (acIn[i] != '1') {
if (acIn[i] != '1' && acIn[i] != '2') {
fileWrite(pCLServing->fd, "aborted]\r\n", -1);
continue;
}
@ -1303,11 +1312,21 @@ Kiddie(pGE, sfd)
/* send a break
*/
if (pCEServing->isNetworkConsole) {
char haltseq[2];
if (acIn[i] == 1) {
char haltseq[2];
haltseq[0] = IAC;
haltseq[1] = BREAK;
write(pCEServing->fdtty, haltseq, 2);
haltseq[0] = IAC;
haltseq[1] = BREAK;
write(pCEServing->fdtty, haltseq, 2);
} else {
char haltseq[3];
/* The default Solaris 8 `alternate' break... */
haltseq[0] = 0x0D; /* CR */
haltseq[1] = 0x7E; /* Tilde */
haltseq[2] = 0x02; /* Ctrl-B */
write(pCEServing->fdtty, haltseq, 3);
}
} else {
#if HAVE_TERMIO_H
if (-1 ==
@ -1647,7 +1666,7 @@ Kiddie(pGE, sfd)
if (&CECtl == pCL->pCEto)
continue;
sprintf(acOut,
" %-24.24s %c %-7.7s %5s %.32s\r\n",
" %-32.32s %c %-7.7s %5s %s\r\n",
pCL->acid,
pCL == pCLServing ? '*' : ' ',
pCL->fcon ? (pCL->
@ -1838,7 +1857,7 @@ Kiddie(pGE, sfd)
(CONSCLIENT *) 0 != pCL;
pCL = pCL->pCLnext) {
sprintf(acOut,
" %-24.24s %c %-7.7s %5s %s\r\n",
" %-32.32s %c %-7.7s %5s %s\r\n",
pCL->acid,
pCL == pCLServing ? '*' : ' ',
pCL->fcon ? (pCL->
@ -2017,12 +2036,26 @@ Kiddie(pGE, sfd)
Error("accept: %s", strerror(errno));
continue;
}
pCLFree->fd = fileOpenFD(fd, simpleSocket);
if (pCLFree->fd < 0) {
Error("fileOpenFD: %s", strerror(errno));
close(fd);
continue;
}
#if defined(USE_LIBWRAP)
{
struct request_info request;
request_init(&request, RQ_DAEMON, progname, RQ_FILE, fd, 0);
fromhost(&request);
if (!hosts_access(&request)) {
fileWrite(pCLFree->fd, "access from your host refused\r\n",
-1);
(void)fileClose(pCLFree->fd);
continue;
}
}
#endif
/* We use this information to verify (ksb)
* the source machine as being local.

View File

@ -1,5 +1,5 @@
/*
* $Id: master.c,v 5.61 2001-07-30 01:58:00-07 bryan Exp $
* $Id: master.c,v 5.63 2001-10-10 11:52:57-07 bryan Exp $
*
* Copyright conserver.com, 2000-2001
*
@ -42,6 +42,13 @@
#include <signal.h>
#include <pwd.h>
#if defined(USE_LIBWRAP)
#include <syslog.h>
#include <tcpd.h>
int allow_severity = LOG_INFO;
int deny_severity = LOG_WARNING;
#endif
#include <compat.h>
#include <port.h>
#include <util.h>
@ -304,11 +311,25 @@ Master(pRCUniq)
Error("accept: %s", strerror(errno));
continue;
}
if ((CONSFILE *) 0 == (csocket = fileOpenFD(cfd, simpleSocket))) {
Error("fileOpenFD: %s", strerror(errno));
close(cfd);
continue;
}
#if defined(USE_LIBWRAP)
{
struct request_info request;
request_init(&request, RQ_DAEMON, progname, RQ_FILE, cfd, 0);
fromhost(&request);
if (!hosts_access(&request)) {
fileWrite(csocket, "access from your host refused\r\n",
-1);
(void)fileClose(csocket);
continue;
}
}
#endif
so = sizeof(in_port);
if (-1 ==

View File

@ -1,5 +1,5 @@
/*
* $Id: version.h,v 1.27 2001-08-04 21:09:31-07 bryan Exp $
* $Id: version.h,v 1.28 2001-10-15 16:59:50-07 bryan Exp $
*
* Copyright conserver.com, 2000-2001
*
@ -14,4 +14,4 @@
@(#) Copyright 2000 conserver.com.\n\
All rights reserved.\n"
#define THIS_VERSION "conserver.com version 7.1.1"
#define THIS_VERSION "conserver.com version 7.1.2"

View File

@ -1,5 +1,5 @@
/*
* $Id: console.c,v 5.70 2001-07-26 11:03:32-07 bryan Exp $
* $Id: console.c,v 5.71 2001-10-10 11:30:17-07 bryan Exp $
*
* Copyright conserver.com, 2000-2001
*
@ -386,7 +386,8 @@ c2raw()
n_tio = o_tio;
n_tio.c_iflag &= ~(INLCR | IGNCR | ICRNL | IUCLC | IXON);
n_tio.c_oflag &= ~OPOST;
n_tio.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHONL | IEXTEN);
n_tio.c_lflag &=
~(ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHONL | IEXTEN);
n_tio.c_cc[VMIN] = 1;
n_tio.c_cc[VTIME] = 0;
if (0 != ioctl(0, TCSETAF, &n_tio)) {
@ -822,7 +823,8 @@ CallUp(s, pcMaster, pcMach, pcHow, pcUser)
(void)ReadReply(s, acMesg, sizeof(acMesg), (char *)0);
if (0 == strcmp(acMesg, "passwd:")) {
char pass[256];
(void)sprintf(acMesg, "Enter %s's password:", pcUser);
(void)sprintf(acMesg, "Enter %s@%s's password:", pcUser,
pcMaster);
#if defined(HAVE_GETPASSPHRASE)
(void)strcpy(pass, getpassphrase(acMesg));
#else

View File

@ -1,4 +1,4 @@
.\" $Id: console.man,v 1.11 2001-07-26 10:25:24-07 bryan Exp $
.\" $Id: console.man,v 1.12 2001-10-15 22:46:09-07 bryan Exp $
.TH CONSOLE 1 "Local"
.SH NAME
console \- console server client program
@ -189,6 +189,9 @@ toggle logging on/off
.IP l1
send a 3-second serial line break (might halt a Sun)
("ell" then "one", not the L1 key)
.IP l2
send the alternate break sequence (<CR>, tilde, CTRL-B)
(might halt a Sun)
.IP o
close (if open) and reopen the line (to clear errors (silo overflows))
and the log file

View File

@ -4,7 +4,7 @@
#
%define pkg conserver
%define ver 7.1.1
%define ver 7.1.2
# define the name of the machine on which the main conserver
# daemon will be running if you don't want to use the default

View File

@ -1,7 +1,7 @@
PKG="conserver"
NAME="Console server and client"
CATEGORY="system"
VERSION="7.1.1"
VERSION="7.1.2"
DESC="Console server and client"
CLASSES=none
ARCH=sparc