You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2856 lines
63 KiB
2856 lines
63 KiB
/*
|
|
|
|
Create a suitable configuration for tdm taking old xdm/tdm
|
|
installations into account
|
|
|
|
Copyright (C) 2001-2005 Oswald Buddenhagen <ossi@kde.org>
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xresource.h>
|
|
|
|
#include <config.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <stdarg.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <utime.h>
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
#include <pwd.h>
|
|
#include <time.h>
|
|
#include <limits.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/param.h>
|
|
#if defined(BSD) && !defined(HAVE_UTMPX)
|
|
# include <utmp.h>
|
|
#endif
|
|
|
|
#include "config.ci"
|
|
|
|
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
|
|
# define ATTR_UNUSED __attribute__((unused))
|
|
#else
|
|
# define ATTR_UNUSED
|
|
#endif
|
|
|
|
#if defined(__sun) && !defined(__sun__)
|
|
# define __sun__
|
|
#endif
|
|
|
|
#define as(ar) ((int)(sizeof(ar)/sizeof(ar[0])))
|
|
|
|
#define __stringify(x) #x
|
|
#define stringify(x) __stringify(x)
|
|
|
|
#define RCVERSTR stringify(RCVERMAJOR) "." stringify(RCVERMINOR)
|
|
|
|
static int old_scripts, no_old_scripts, old_confs, no_old,
|
|
no_backup, no_in_notice, use_destdir, mixed_scripts;
|
|
static const char *newdir = TDMCONF, *facesrc = TDMDATA "/pics/users",
|
|
*oldxdm, *oldkde;
|
|
|
|
static int oldver;
|
|
|
|
|
|
typedef struct StrList {
|
|
struct StrList *next;
|
|
const char *str;
|
|
} StrList;
|
|
|
|
|
|
static void *
|
|
mmalloc( size_t sz )
|
|
{
|
|
void *ptr;
|
|
|
|
if (!(ptr = malloc( sz ))) {
|
|
fprintf( stderr, "Out of memory\n" );
|
|
exit( 1 );
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
static void *
|
|
mcalloc( size_t sz )
|
|
{
|
|
void *ptr;
|
|
|
|
if (!(ptr = calloc( 1, sz ))) {
|
|
fprintf( stderr, "Out of memory\n" );
|
|
exit( 1 );
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
static void *
|
|
mrealloc( void *optr, size_t sz )
|
|
{
|
|
void *ptr;
|
|
|
|
if (!(ptr = realloc( optr, sz ))) {
|
|
fprintf( stderr, "Out of memory\n" );
|
|
exit( 1 );
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
static char *
|
|
mstrdup( const char *optr )
|
|
{
|
|
char *ptr;
|
|
|
|
if (!optr)
|
|
return 0;
|
|
if (!(ptr = strdup( optr ))) {
|
|
fprintf( stderr, "Out of memory\n" );
|
|
exit( 1 );
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
|
|
#define NO_LOGGER
|
|
#define STATIC static
|
|
#include <printf.c>
|
|
|
|
typedef struct {
|
|
char *buf;
|
|
int clen, blen, tlen;
|
|
} OCABuf;
|
|
|
|
static void
|
|
OutCh_OCA( void *bp, char c )
|
|
{
|
|
OCABuf *ocabp = (OCABuf *)bp;
|
|
|
|
ocabp->tlen++;
|
|
if (ocabp->clen >= ocabp->blen) {
|
|
ocabp->blen = ocabp->blen * 3 / 2 + 100;
|
|
ocabp->buf = mrealloc( ocabp->buf, ocabp->blen );
|
|
}
|
|
ocabp->buf[ocabp->clen++] = c;
|
|
}
|
|
|
|
static int
|
|
VASPrintf( char **strp, const char *fmt, va_list args )
|
|
{
|
|
OCABuf ocab = { 0, 0, 0, -1 };
|
|
|
|
DoPr( OutCh_OCA, &ocab, fmt, args );
|
|
OutCh_OCA( &ocab, 0 );
|
|
*strp = realloc( ocab.buf, ocab.clen );
|
|
if (!*strp)
|
|
*strp = ocab.buf;
|
|
return ocab.tlen;
|
|
}
|
|
|
|
static int
|
|
ASPrintf( char **strp, const char *fmt, ... )
|
|
{
|
|
va_list args;
|
|
int len;
|
|
|
|
va_start( args, fmt );
|
|
len = VASPrintf( strp, fmt, args );
|
|
va_end( args );
|
|
return len;
|
|
}
|
|
|
|
static void
|
|
StrCat( char **strp, const char *fmt, ... )
|
|
{
|
|
char *str, *tstr;
|
|
va_list args;
|
|
int el;
|
|
|
|
va_start( args, fmt );
|
|
el = VASPrintf( &str, fmt, args );
|
|
va_end( args );
|
|
if (*strp) {
|
|
int ol = strlen( *strp );
|
|
tstr = mmalloc( el + ol + 1 );
|
|
memcpy( tstr, *strp, ol );
|
|
memcpy( tstr + ol, str, el + 1 );
|
|
free( *strp );
|
|
free( str );
|
|
*strp = tstr;
|
|
} else
|
|
*strp = str;
|
|
}
|
|
|
|
|
|
#define WANT_CLOSE 1
|
|
|
|
typedef struct File {
|
|
char *buf, *eof, *cur;
|
|
#if defined(HAVE_MMAP) && defined(WANT_CLOSE)
|
|
int ismapped;
|
|
#endif
|
|
} File;
|
|
|
|
static int
|
|
readFile( File *file, const char *fn )
|
|
{
|
|
off_t flen;
|
|
int fd;
|
|
|
|
if ((fd = open( fn, O_RDONLY )) < 0)
|
|
return 0;
|
|
|
|
flen = lseek( fd, 0, SEEK_END );
|
|
#ifdef HAVE_MMAP
|
|
# ifdef WANT_CLOSE
|
|
file->ismapped = 0;
|
|
# endif
|
|
file->buf = mmap( 0, flen + 1, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0 );
|
|
# ifdef WANT_CLOSE
|
|
if (file->buf)
|
|
file->ismapped = 1;
|
|
else
|
|
# else
|
|
if (!file->buf)
|
|
# endif
|
|
#endif
|
|
{
|
|
file->buf = mmalloc( flen + 1 );
|
|
lseek( fd, 0, SEEK_SET );
|
|
if (read( fd, file->buf, flen ) != flen) {
|
|
free( file->buf );
|
|
close( fd );
|
|
fprintf( stderr, "Cannot read file\n" );
|
|
return 0; /* maybe better abort? */
|
|
}
|
|
}
|
|
file->eof = file->buf + flen;
|
|
close( fd );
|
|
return 1;
|
|
}
|
|
|
|
#ifdef WANT_CLOSE
|
|
static void
|
|
freeBuf( File *file )
|
|
{
|
|
# ifdef HAVE_MMAP
|
|
if (file->ismapped)
|
|
munmap( file->buf, file->eof - file->buf );
|
|
else
|
|
# endif
|
|
free( file->buf );
|
|
}
|
|
#endif
|
|
|
|
static int
|
|
isTrue( const char *val )
|
|
{
|
|
return !strcmp( val, "true" ) ||
|
|
!strcmp( val, "yes" ) ||
|
|
!strcmp( val, "on" ) ||
|
|
atoi( val );
|
|
}
|
|
|
|
static int
|
|
mkdirp( const char *name, int mode, const char *what, int existok )
|
|
{
|
|
char *mfname = mstrdup( name );
|
|
int i;
|
|
struct stat st;
|
|
|
|
for (i = 1; mfname[i]; i++)
|
|
if (mfname[i] == '/') {
|
|
mfname[i] = 0;
|
|
if (stat( mfname, &st )) {
|
|
if (mkdir( mfname, 0755 )) {
|
|
fprintf( stderr, "Cannot create parent %s of %s directory %s: %s\n",
|
|
mfname, what, name, strerror( errno ) );
|
|
free( mfname );
|
|
return 0;
|
|
}
|
|
chmod( mfname, 0755 );
|
|
}
|
|
mfname[i] = '/';
|
|
}
|
|
free( mfname );
|
|
if (stat( name, &st )) {
|
|
if (mkdir( name, mode )) {
|
|
fprintf( stderr, "Cannot create %s directory %s: %s\n",
|
|
what, name, strerror( errno ) );
|
|
return 0;
|
|
}
|
|
chmod( name, mode );
|
|
return 1;
|
|
}
|
|
return existok;
|
|
}
|
|
|
|
|
|
static void
|
|
displace( const char *fn )
|
|
{
|
|
if (!no_backup) {
|
|
char bn[PATH_MAX + 4];
|
|
sprintf( bn, "%s.bak", fn ); /* won't overflow if only existing paths are passed */
|
|
rename( fn, bn );
|
|
} else
|
|
unlink( fn );
|
|
}
|
|
|
|
|
|
static char *
|
|
locate( const char *exe )
|
|
{
|
|
int len;
|
|
char *path, *name, *thenam, nambuf[PATH_MAX+1];
|
|
char *pathe;
|
|
|
|
if (!(path = getenv( "PATH" )))
|
|
return 0;
|
|
len = strlen( exe );
|
|
name = nambuf + PATH_MAX - len;
|
|
memcpy( name, exe, len + 1 );
|
|
*--name = '/';
|
|
do {
|
|
if (!(pathe = strchr( path, ':' )))
|
|
pathe = path + strlen( path );
|
|
len = pathe - path;
|
|
if (len && !(len == 1 && *path == '.')) {
|
|
thenam = name - len;
|
|
if (thenam >= nambuf) {
|
|
memcpy( thenam, path, len );
|
|
if (!access( thenam, X_OK ))
|
|
return mstrdup( thenam );
|
|
}
|
|
}
|
|
path = pathe;
|
|
} while (*path++ != '\0');
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* target data to be written to tdmrc
|
|
*/
|
|
|
|
typedef struct Entry {
|
|
struct Entry *next;
|
|
struct Ent *spec;
|
|
const char *value;
|
|
int active:1;
|
|
int written:1;
|
|
} Entry;
|
|
|
|
typedef struct Section {
|
|
struct Section *next;
|
|
struct Sect *spec;
|
|
const char *name;
|
|
const char *comment;
|
|
Entry *ents;
|
|
} Section;
|
|
|
|
static Section *config; /* the tdmrc data to be written */
|
|
|
|
/*
|
|
* Specification of the (currently possible) tdmrc entries
|
|
*/
|
|
|
|
typedef struct Ent {
|
|
const char *key;
|
|
int prio;
|
|
void (*func)( Entry *ce, Section *cs );
|
|
const char *comment;
|
|
} Ent;
|
|
|
|
typedef struct Sect {
|
|
const char *name;
|
|
Ent *ents;
|
|
int nents;
|
|
} Sect;
|
|
|
|
static Sect *findSect( const char *name );
|
|
static Ent *findEnt( Sect *sect, const char *key );
|
|
|
|
/*
|
|
* Functions to manipulate the current tdmrc data
|
|
*/
|
|
|
|
static const char *
|
|
getfqval( const char *sect, const char *key, const char *defval )
|
|
{
|
|
Section *cs;
|
|
Entry *ce;
|
|
|
|
for (cs = config; cs; cs = cs->next)
|
|
if (!strcmp( cs->name, sect )) {
|
|
for (ce = cs->ents; ce; ce = ce->next)
|
|
if (!strcmp( ce->spec->key, key )) {
|
|
if (ce->active && ce->written)
|
|
return ce->value;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
return defval;
|
|
}
|
|
|
|
static void
|
|
putfqval( const char *sect, const char *key, const char *value )
|
|
{
|
|
Section *cs, **csp;
|
|
Entry *ce, **cep;
|
|
|
|
if (!value)
|
|
return;
|
|
|
|
for (csp = &config; (cs = *csp); csp = &(cs->next))
|
|
if (!strcmp( sect, cs->name ))
|
|
goto havesec;
|
|
cs = mcalloc( sizeof(*cs) );
|
|
ASPrintf( (char **)&cs->name, "%s", sect );
|
|
cs->spec = findSect( sect );
|
|
*csp = cs;
|
|
havesec:
|
|
|
|
for (cep = &(cs->ents); (ce = *cep); cep = &(ce->next))
|
|
if (!strcmp( key, ce->spec->key ))
|
|
goto haveent;
|
|
ce = mcalloc( sizeof(*ce) );
|
|
ce->spec = findEnt( cs->spec, key );
|
|
*cep = ce;
|
|
haveent:
|
|
ASPrintf( (char **)&ce->value, "%s", value );
|
|
ce->written = ce->active = 1;
|
|
}
|
|
|
|
static const char *csect;
|
|
|
|
#define setsect(se) csect = se
|
|
|
|
static void
|
|
putval( const char *key, const char *value )
|
|
{
|
|
putfqval( csect, key, value );
|
|
}
|
|
|
|
|
|
static void
|
|
wrconf( FILE *f )
|
|
{
|
|
Section *cs;
|
|
Entry *ce;
|
|
StrList *sl = 0, *sp;
|
|
const char *cmt;
|
|
|
|
putfqval( "General", "ConfigVersion", RCVERSTR );
|
|
for (cs = config; cs; cs = cs->next) {
|
|
fprintf( f, "%s[%s]\n",
|
|
cs->comment ? cs->comment : "\n", cs->name );
|
|
for (ce = cs->ents; ce; ce = ce->next) {
|
|
if (ce->spec->comment) {
|
|
cmt = ce->spec->comment;
|
|
for (sp = sl; sp; sp = sp->next)
|
|
if (sp->str == cmt) {
|
|
cmt = "# See above\n";
|
|
goto havit;
|
|
}
|
|
if (!(sp = malloc( sizeof(*sp) )))
|
|
fprintf( stderr, "Warning: Out of memory\n" );
|
|
else {
|
|
sp->str = cmt;
|
|
sp->next = sl; sl = sp;
|
|
}
|
|
} else
|
|
cmt = "";
|
|
havit:
|
|
fprintf( f, "%s%s%s=%s\n",
|
|
cmt, ce->active ? "" : "#", ce->spec->key, ce->value );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* defaults
|
|
*/
|
|
#ifdef XDMCP
|
|
static const char def_xaccess[] =
|
|
"# Xaccess - Access control file for XDMCP connections\n"
|
|
"#\n"
|
|
"# To control Direct and Broadcast access:\n"
|
|
"#\n"
|
|
"# pattern\n"
|
|
"#\n"
|
|
"# To control Indirect queries:\n"
|
|
"#\n"
|
|
"# pattern list of hostnames and/or macros ...\n"
|
|
"#\n"
|
|
"# To use the chooser:\n"
|
|
"#\n"
|
|
"# pattern CHOOSER BROADCAST\n"
|
|
"#\n"
|
|
"# or\n"
|
|
"#\n"
|
|
"# pattern CHOOSER list of hostnames and/or macros ...\n"
|
|
"#\n"
|
|
"# To define macros:\n"
|
|
"#\n"
|
|
"# %name list of hosts ...\n"
|
|
"#\n"
|
|
"# The first form tells xdm which displays to respond to itself.\n"
|
|
"# The second form tells xdm to forward indirect queries from hosts matching\n"
|
|
"# the specified pattern to the indicated list of hosts.\n"
|
|
"# The third form tells xdm to handle indirect queries using the chooser;\n"
|
|
"# the chooser is directed to send its own queries out via the broadcast\n"
|
|
"# address and display the results on the terminal.\n"
|
|
"# The fourth form is similar to the third, except instead of using the\n"
|
|
"# broadcast address, it sends DirectQuerys to each of the hosts in the list\n"
|
|
"#\n"
|
|
"# In all cases, xdm uses the first entry which matches the terminal;\n"
|
|
"# for IndirectQuery messages only entries with right hand sides can\n"
|
|
"# match, for Direct and Broadcast Query messages, only entries without\n"
|
|
"# right hand sides can match.\n"
|
|
"#\n"
|
|
"\n"
|
|
"#* #any host can get a login window\n"
|
|
"\n"
|
|
"#\n"
|
|
"# To hardwire a specific terminal to a specific host, you can\n"
|
|
"# leave the terminal sending indirect queries to this host, and\n"
|
|
"# use an entry of the form:\n"
|
|
"#\n"
|
|
"\n"
|
|
"#terminal-a host-a\n"
|
|
"\n"
|
|
"\n"
|
|
"#\n"
|
|
"# The nicest way to run the chooser is to just ask it to broadcast\n"
|
|
"# requests to the network - that way new hosts show up automatically.\n"
|
|
"# Sometimes, however, the chooser can't figure out how to broadcast,\n"
|
|
"# so this may not work in all environments.\n"
|
|
"#\n"
|
|
"\n"
|
|
"#* CHOOSER BROADCAST #any indirect host can get a chooser\n"
|
|
"\n"
|
|
"#\n"
|
|
"# If you'd prefer to configure the set of hosts each terminal sees,\n"
|
|
"# then just uncomment these lines (and comment the CHOOSER line above)\n"
|
|
"# and edit the %hostlist line as appropriate\n"
|
|
"#\n"
|
|
"\n"
|
|
"#%hostlist host-a host-b\n"
|
|
"\n"
|
|
"#* CHOOSER %hostlist #\n";
|
|
#endif
|
|
|
|
#ifdef XDMCP
|
|
static const char def_willing[] =
|
|
"#! /bin/sh\n"
|
|
"# The output of this script is displayed in the chooser window\n"
|
|
"# (instead of \"Willing to manage\").\n"
|
|
"\n"
|
|
"load=`uptime|sed -e 's/^.*load[^0-9]*//'`\n"
|
|
"nrusers=`who|cut -c 1-8|sort -u|wc -l|sed 's/^[ \t]*//'`\n"
|
|
"s=\"\"; [ \"$nrusers\" != 1 ] && s=s\n"
|
|
"\n"
|
|
"echo \"${nrusers} user${s}, load: ${load}\"\n";
|
|
#endif
|
|
|
|
static const char def_setup[] =
|
|
"#! /bin/sh\n"
|
|
"# Xsetup - run as root before the login dialog appears\n"
|
|
"\n"
|
|
"#xconsole -geometry 480x130-0-0 -notify -verbose -fn fixed -exitOnFail -file /dev/xconsole &\n";
|
|
|
|
static const char def_startup[] =
|
|
"#! /bin/sh\n"
|
|
"# Xstartup - run as root before session starts\n"
|
|
"\n"
|
|
"\n"
|
|
"\n"
|
|
"if [ -e /etc/nologin ]; then\n"
|
|
" # always display the nologin message, if possible\n"
|
|
" if [ -s /etc/nologin ] && which xmessage > /dev/null 2>&1; then\n"
|
|
" xmessage -file /etc/nologin -geometry 640x480\n"
|
|
" fi\n"
|
|
" if [ \"$(id -u)\" != \"0\" ] && \\\n"
|
|
" ! grep -qs '^ignore-nologin' /etc/trinity/tdm/tdm.options; then\n"
|
|
" exit 1\n"
|
|
" fi\n"
|
|
"fi\n"
|
|
"\n"
|
|
"if grep -qs '^use-sessreg' /etc/trinity/tdm/tdm.options && \\\n"
|
|
" which sessreg > /dev/null 2>&1; then\n"
|
|
" exec sessreg -a -l \"$DISPLAY\" -u /var/run/utmp \\\n"
|
|
" -h \"`echo $DISPLAY | cut -d: -f1`\" \"$USER\"\n"
|
|
" # NOTREACHED\n"
|
|
"fi\n";
|
|
|
|
static const char def_reset[] =
|
|
"#! /bin/sh\n"
|
|
"# Xreset - run as root after session exits\n"
|
|
"\n"
|
|
"# Reassign ownership of the console to root, this should disallow\n"
|
|
"# assignment of console output to any random users's xterm. See Xstartup.\n"
|
|
"#\n"
|
|
"#chown root /dev/console\n"
|
|
"#chmod 622 /dev/console\n"
|
|
"\n"
|
|
#ifdef _AIX
|
|
"#devname=`echo $DISPLAY | cut -c1-8`\n"
|
|
"#exec sessreg -d -l xdm/$devname -h \"`echo $DISPLAY | cut -d: -f1`\""
|
|
#else
|
|
"if grep -qs '^use-sessreg' /etc/trinity/tdm/tdm.options && \\\n"
|
|
" which sessreg > /dev/null 2>&1; then\n"
|
|
" exec sessreg -d -l \"$DISPLAY\" -u /var/run/utmp \\\n"
|
|
" -h \"`echo $DISPLAY | cut -d: -f1`\" \"$USER\"\n"
|
|
" # NOTREACHED\n"
|
|
"fi\n";
|
|
#endif /* _AIX */
|
|
|
|
static const char def_session1[] =
|
|
"#! /bin/sh\n"
|
|
"# Xsession - run as user\n"
|
|
"\n"
|
|
"session=$1\n"
|
|
"\n"
|
|
"# Note that the respective logout scripts are not sourced.\n"
|
|
"case $SHELL in\n"
|
|
" */bash)\n"
|
|
" [ -z \"$BASH\" ] && exec $SHELL $0 \"$@\"\n"
|
|
" set +o posix\n"
|
|
" [ -f /etc/profile ] && . /etc/profile\n"
|
|
" if [ -f $HOME/.bash_profile ]; then\n"
|
|
" . $HOME/.bash_profile\n"
|
|
" elif [ -f $HOME/.bash_login ]; then\n"
|
|
" . $HOME/.bash_login\n"
|
|
" elif [ -f $HOME/.profile ]; then\n"
|
|
" . $HOME/.profile\n"
|
|
" fi\n"
|
|
" ;;\n"
|
|
" */zsh)\n"
|
|
" [ -z \"$ZSH_NAME\" ] && exec $SHELL $0 \"$@\"\n"
|
|
" emulate -R zsh\n"
|
|
" [ -d /etc/zsh ] && zdir=/etc/zsh || zdir=/etc\n"
|
|
" zhome=${ZDOTDIR:-$HOME}\n"
|
|
" # zshenv is always sourced automatically.\n"
|
|
" [ -f $zdir/zprofile ] && . $zdir/zprofile\n"
|
|
" [ -f $zhome/.zprofile ] && . $zhome/.zprofile\n"
|
|
" [ -f $zdir/zlogin ] && . $zdir/zlogin\n"
|
|
" [ -f $zhome/.zlogin ] && . $zhome/.zlogin\n"
|
|
" setopt shwordsplit noextendedglob\n"
|
|
" ;;\n"
|
|
" */csh|*/tcsh)\n"
|
|
" # [t]cshrc is always sourced automatically.\n"
|
|
" # Note that sourcing csh.login after .cshrc is non-standard.\n"
|
|
" xsess_tmp=";
|
|
static const char def_session2[] =
|
|
"\n"
|
|
" $SHELL -c \"if (-f /etc/csh.login) source /etc/csh.login; if (-f ~/.login) source ~/.login; /bin/sh -c export -p >! $xsess_tmp\"\n"
|
|
" . $xsess_tmp\n"
|
|
" rm -f $xsess_tmp\n"
|
|
" ;;\n"
|
|
" *) # Plain sh, ksh, and anything we don't know.\n"
|
|
" [ -f /etc/profile ] && . /etc/profile\n"
|
|
" [ -f $HOME/.profile ] && . $HOME/.profile\n"
|
|
" ;;\n"
|
|
"esac\n"
|
|
"# invoke global X session script\n"
|
|
". /etc/X11/Xsession\n";
|
|
|
|
static const char def_background[] =
|
|
"[Desktop0]\n"
|
|
"BackgroundMode=Flat\n"
|
|
"BlendBalance=100\n"
|
|
"BlendMode=NoBlending\n"
|
|
"ChangeInterval=60\n"
|
|
"Color1=0,0,200\n"
|
|
"Color2=192,192,192\n"
|
|
"CurrentWallpaper=0\n"
|
|
"LastChange=0\n"
|
|
"MinOptimizationDepth=1\n"
|
|
"MultiWallpaperMode=NoMulti\n"
|
|
"Pattern=fish\n"
|
|
"Program=\n"
|
|
"ReverseBlending=false\n"
|
|
"UseSHM=false\n"
|
|
"Wallpaper=Trinity-lineart.svg\n"
|
|
"WallpaperList=\n"
|
|
"WallpaperMode=Scaled\n";
|
|
|
|
static char *
|
|
prepName( const char *fn )
|
|
{
|
|
const char *tname;
|
|
char *nname;
|
|
|
|
tname = strrchr( fn, '/' );
|
|
ASPrintf( &nname, "%s/%s", newdir, tname ? tname + 1 : fn );
|
|
displace( nname );
|
|
return nname;
|
|
}
|
|
|
|
static FILE *
|
|
Create( const char *fn, int mode )
|
|
{
|
|
char *nname;
|
|
FILE *f;
|
|
|
|
nname = prepName( fn );
|
|
if (!(f = fopen( nname, "w" ))) {
|
|
fprintf( stderr, "Cannot create %s\n", nname );
|
|
exit( 1 );
|
|
}
|
|
chmod( nname, mode );
|
|
free( nname );
|
|
return f;
|
|
}
|
|
|
|
static void
|
|
WriteOut( const char *fn, int mode, time_t stamp, const char *buf, size_t len )
|
|
{
|
|
char *nname;
|
|
int fd;
|
|
struct utimbuf utim;
|
|
|
|
nname = prepName( fn );
|
|
if ((fd = creat( nname, mode )) < 0) {
|
|
fprintf( stderr, "Cannot create %s\n", nname );
|
|
exit( 1 );
|
|
}
|
|
write( fd, buf, len );
|
|
close( fd );
|
|
if (stamp) {
|
|
utim.actime = utim.modtime = stamp;
|
|
utime( nname, &utim );
|
|
}
|
|
free( nname );
|
|
}
|
|
|
|
|
|
/* returns static array! */
|
|
static const char *
|
|
resect( const char *sec, const char *name )
|
|
{
|
|
static char sname[64];
|
|
char *p;
|
|
|
|
if ((p = strrchr( sec, '-' ))) {
|
|
sprintf( sname, "%.*s-%s", p - sec, sec, name );
|
|
return sname;
|
|
} else
|
|
return name;
|
|
}
|
|
|
|
static int
|
|
inNewDir( const char *name )
|
|
{
|
|
return !memcmp( name, TDMCONF "/", sizeof(TDMCONF) );
|
|
}
|
|
|
|
static int
|
|
inList( StrList *sp, const char *s )
|
|
{
|
|
for (; sp; sp = sp->next)
|
|
if (!strcmp( sp->str, s ))
|
|
return 1;
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
addStr( StrList **sp, const char *s )
|
|
{
|
|
for (; *sp; sp = &(*sp)->next)
|
|
if (!strcmp( (*sp)->str, s ))
|
|
return;
|
|
*sp = mcalloc( sizeof(**sp) );
|
|
ASPrintf( (char **)&(*sp)->str, "%s", s );
|
|
}
|
|
|
|
StrList *aflist, *uflist, *eflist, *cflist, *lflist;
|
|
|
|
/* file is part of new config */
|
|
static void
|
|
addedFile( const char *fn )
|
|
{
|
|
addStr( &aflist, fn );
|
|
}
|
|
|
|
/* file from old config was parsed */
|
|
static void
|
|
usedFile( const char *fn )
|
|
{
|
|
addStr( &uflist, fn );
|
|
}
|
|
|
|
/* file from old config was copied with slight modifications */
|
|
static void
|
|
editedFile( const char *fn )
|
|
{
|
|
addStr( &eflist, fn );
|
|
}
|
|
|
|
/* file from old config was copied verbatim */
|
|
static void
|
|
copiedFile( const char *fn )
|
|
{
|
|
addStr( &cflist, fn );
|
|
}
|
|
|
|
/* file from old config is still being used */
|
|
static void
|
|
linkedFile( const char *fn )
|
|
{
|
|
addStr( &lflist, fn );
|
|
}
|
|
|
|
/*
|
|
* XXX this stuff is highly borked. it does not handle collisions at all.
|
|
*/
|
|
static int
|
|
copyfile( Entry *ce, const char *tname, int mode, int (*proc)( File * ) )
|
|
{
|
|
const char *tptr;
|
|
char *nname;
|
|
File file;
|
|
int rt;
|
|
|
|
if (!*ce->value)
|
|
return 1;
|
|
|
|
tptr = strrchr( tname, '/' );
|
|
ASPrintf( &nname, TDMCONF "/%s", tptr ? tptr + 1 : tname );
|
|
if (inList( cflist, ce->value ) ||
|
|
inList( eflist, ce->value ) ||
|
|
inList( lflist, ce->value ))
|
|
{
|
|
rt = 1;
|
|
goto doret;
|
|
}
|
|
if (!readFile( &file, ce->value )) {
|
|
fprintf( stderr, "Warning: cannot copy file %s\n", ce->value );
|
|
rt = 0;
|
|
} else {
|
|
if (!proc || !proc( &file )) {
|
|
if (!use_destdir && !strcmp( ce->value, nname ))
|
|
linkedFile( nname );
|
|
else {
|
|
struct stat st;
|
|
stat( ce->value, &st );
|
|
WriteOut( nname, mode, st.st_mtime, file.buf, file.eof - file.buf );
|
|
copiedFile( ce->value );
|
|
}
|
|
} else {
|
|
WriteOut( nname, mode, 0, file.buf, file.eof - file.buf );
|
|
editedFile( ce->value );
|
|
}
|
|
if (strcmp( ce->value, nname ) && inNewDir( ce->value ) && !use_destdir)
|
|
displace( ce->value );
|
|
addedFile( nname );
|
|
rt = 1;
|
|
}
|
|
doret:
|
|
ce->value = nname;
|
|
return rt;
|
|
}
|
|
|
|
static void
|
|
dlinkfile( const char *name )
|
|
{
|
|
File file;
|
|
|
|
if (!readFile( &file, name )) {
|
|
fprintf( stderr, "Warning: cannot read file %s\n", name );
|
|
return;
|
|
}
|
|
if (inNewDir( name ) && use_destdir) {
|
|
struct stat st;
|
|
stat( name, &st );
|
|
WriteOut( name, st.st_mode, st.st_mtime, file.buf, file.eof - file.buf );
|
|
copiedFile( name );
|
|
} else
|
|
linkedFile( name );
|
|
addedFile( name );
|
|
}
|
|
|
|
static void
|
|
linkfile( Entry *ce )
|
|
{
|
|
if (ce->written && *ce->value)
|
|
dlinkfile( ce->value );
|
|
}
|
|
|
|
static void
|
|
writefile( const char *tname, int mode, const char *cont )
|
|
{
|
|
WriteOut( tname, mode, 0, cont, strlen( cont ) );
|
|
addedFile( tname );
|
|
}
|
|
|
|
|
|
char *background;
|
|
|
|
static void
|
|
handBgCfg( Entry *ce, Section *cs ATTR_UNUSED )
|
|
{
|
|
if (!ce->active) /* can be only the X-*-Greeter one */
|
|
writefile( def_BackgroundCfg, 0644,
|
|
background ? background : def_background );
|
|
#if 0 /* risk of kcontrol clobbering the original file */
|
|
else if (old_confs)
|
|
linkfile( ce );
|
|
#endif
|
|
else {
|
|
if (!copyfile( ce, ce->value, 0644, 0 )) {
|
|
if (!strcmp( cs->name, "X-*-Greeter" ))
|
|
writefile( def_BackgroundCfg, 0644, def_background );
|
|
ce->active = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef HAVE_VTS
|
|
static char *
|
|
mem_mem( char *mem, int lmem, const char *smem, int lsmem )
|
|
{
|
|
for (; lmem >= lsmem; mem++, lmem--)
|
|
if (!memcmp( mem, smem, lsmem ))
|
|
return mem + lsmem;
|
|
return 0;
|
|
}
|
|
|
|
static int maxTTY, TTYmask;
|
|
|
|
static void
|
|
getInitTab( void )
|
|
{
|
|
if (maxTTY)
|
|
return;
|
|
if (!maxTTY) {
|
|
maxTTY = 6;
|
|
TTYmask = 0x3f;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
/* TODO: handle solaris' local_uid specs */
|
|
|
|
static char *
|
|
ReadWord( File *file, int EOFatEOL )
|
|
{
|
|
char *wordp, *wordBuffer;
|
|
int quoted;
|
|
char c;
|
|
|
|
rest:
|
|
wordp = wordBuffer = file->cur;
|
|
mloop:
|
|
quoted = 0;
|
|
qloop:
|
|
if (file->cur == file->eof) {
|
|
doeow:
|
|
if (wordp == wordBuffer)
|
|
return 0;
|
|
retw:
|
|
*wordp = '\0';
|
|
return wordBuffer;
|
|
}
|
|
c = *file->cur++;
|
|
switch (c) {
|
|
case '#':
|
|
if (quoted)
|
|
break;
|
|
do {
|
|
if (file->cur == file->eof)
|
|
goto doeow;
|
|
c = *file->cur++;
|
|
} while (c != '\n');
|
|
case '\0':
|
|
case '\n':
|
|
if (EOFatEOL && !quoted) {
|
|
file->cur--;
|
|
goto doeow;
|
|
}
|
|
if (wordp != wordBuffer) {
|
|
file->cur--;
|
|
goto retw;
|
|
}
|
|
goto rest;
|
|
case ' ':
|
|
case '\t':
|
|
if (wordp != wordBuffer)
|
|
goto retw;
|
|
goto rest;
|
|
case '\\':
|
|
if (!quoted) {
|
|
quoted = 1;
|
|
goto qloop;
|
|
}
|
|
break;
|
|
}
|
|
*wordp++ = c;
|
|
goto mloop;
|
|
}
|
|
|
|
/* backslashes are double-escaped - for TDEConfig and for parseArgs */
|
|
static const char *
|
|
joinArgs( StrList *argv )
|
|
{
|
|
StrList *av;
|
|
const char *s, *rs;
|
|
char *str;
|
|
int slen;
|
|
|
|
if (!argv)
|
|
return "";
|
|
for (slen = 0, av = argv; slen++, av; av = av->next) {
|
|
int nq = 0;
|
|
for (s = av->str; *s; s++, slen++)
|
|
if (isspace( *s ) || *s == '\'')
|
|
nq = 2;
|
|
else if (*s == '"')
|
|
slen += 2;
|
|
else if (*s == '\\')
|
|
slen += 3;
|
|
slen += nq;
|
|
}
|
|
rs = str = mmalloc( slen );
|
|
for (av = argv; av; av = av->next) {
|
|
int nq = 0;
|
|
for (s = av->str; *s; s++)
|
|
if (isspace( *s ) || *s == '\'')
|
|
nq = 2;
|
|
if (av != argv)
|
|
*str++ = ' ';
|
|
if (nq)
|
|
*str++ = '"';
|
|
for (s = av->str; *s; s++) {
|
|
if (*s == '\\')
|
|
*str++ = '\\';
|
|
if (*s == '"' || *s == '\\') {
|
|
*str++ = '\\';
|
|
*str++ = '\\';
|
|
}
|
|
*str++ = *s;
|
|
}
|
|
if (nq)
|
|
*str++ = '"';
|
|
}
|
|
*str = 0;
|
|
return rs;
|
|
}
|
|
|
|
# define dLocation 1
|
|
# define dLocal 0
|
|
# define dForeign 1
|
|
|
|
static struct displayMatch {
|
|
const char *name;
|
|
int len, type;
|
|
} displayTypes[] = {
|
|
{ "local", 5, dLocal },
|
|
{ "foreign", 7, dForeign },
|
|
};
|
|
|
|
static int
|
|
parseDisplayType( const char *string, const char **atPos )
|
|
{
|
|
struct displayMatch *d;
|
|
|
|
*atPos = 0;
|
|
for (d = displayTypes; d < displayTypes + as(displayTypes); d++) {
|
|
if (!memcmp( d->name, string, d->len ) &&
|
|
(!string[d->len] || string[d->len] == '@'))
|
|
{
|
|
if (string[d->len] == '@' && string[d->len + 1])
|
|
*atPos = string + d->len + 1;
|
|
return d->type;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
typedef struct serverEntry {
|
|
struct serverEntry *next;
|
|
const char *name, *class2, *console, *argvs, *arglvs;
|
|
StrList *argv, *arglv;
|
|
int type, reserve, vt;
|
|
} ServerEntry;
|
|
|
|
static void
|
|
absorb_xservers( const char *sect ATTR_UNUSED, char **value )
|
|
{
|
|
ServerEntry *se, *se1, *serverList, **serverPtr;
|
|
const char *word, *word2;
|
|
char *sdpys, *rdpys;
|
|
StrList **argp, **arglp, *ap, *ap2;
|
|
File file;
|
|
int nldpys = 0, nrdpys = 0, dpymask = 0;
|
|
int cpcmd, cpcmdl;
|
|
#ifdef HAVE_VTS
|
|
int dn, cpvt, mtty;
|
|
#endif
|
|
|
|
if (**value == '/') {
|
|
if (!readFile( &file, *value ))
|
|
return;
|
|
usedFile( *value );
|
|
} else {
|
|
file.buf = *value;
|
|
file.eof = *value + strlen( *value );
|
|
}
|
|
file.cur = file.buf;
|
|
|
|
serverPtr = &serverList;
|
|
#ifdef HAVE_VTS
|
|
bustd:
|
|
#endif
|
|
while ((word = ReadWord( &file, 0 ))) {
|
|
se = mcalloc( sizeof(*se) );
|
|
se->name = word;
|
|
if (!(word = ReadWord( &file, 1 )))
|
|
continue;
|
|
se->type = parseDisplayType( word, &se->console );
|
|
if (se->type < 0) {
|
|
se->class2 = word;
|
|
if (!(word = ReadWord( &file, 1 )))
|
|
continue;
|
|
se->type = parseDisplayType( word, &se->console );
|
|
if (se->type < 0) {
|
|
while (ReadWord( &file, 1 ));
|
|
continue;
|
|
}
|
|
}
|
|
word = ReadWord( &file, 1 );
|
|
if (word && !strcmp( word, "reserve" )) {
|
|
se->reserve = 1;
|
|
word = ReadWord( &file, 1 );
|
|
}
|
|
if (((se->type & dLocation) == dLocal) != (word != 0))
|
|
continue;
|
|
argp = &se->argv;
|
|
arglp = &se->arglv;
|
|
while (word) {
|
|
#ifdef HAVE_VTS
|
|
if (word[0] == 'v' && word[1] == 't')
|
|
se->vt = atoi( word + 2 );
|
|
else if (!strcmp( word, "-crt" )) { /* SCO style */
|
|
if (!(word = ReadWord( &file, 1 )) ||
|
|
memcmp( word, "/dev/tty", 8 ))
|
|
goto bustd;
|
|
se->vt = atoi( word + 8 );
|
|
} else
|
|
#endif
|
|
if (strcmp( word, se->name )) {
|
|
ap = mmalloc( sizeof(*ap) );
|
|
ap->str = word;
|
|
if (!strcmp( word, "-nolisten" )) {
|
|
if (!(word2 = ReadWord( &file, 1 )))
|
|
break;
|
|
ap2 = mmalloc( sizeof(*ap2) );
|
|
ap2->str = word2;
|
|
ap->next = ap2;
|
|
if (!strcmp( word2, "unix" )) {
|
|
*argp = ap;
|
|
argp = &ap2->next;
|
|
} else {
|
|
*arglp = ap;
|
|
arglp = &ap2->next;
|
|
}
|
|
} else {
|
|
*argp = ap;
|
|
argp = &ap->next;
|
|
}
|
|
}
|
|
word = ReadWord( &file, 1 );
|
|
}
|
|
*argp = *arglp = 0;
|
|
if ((se->type & dLocation) == dLocal) {
|
|
nldpys++;
|
|
dpymask |= 1 << atoi( se->name + 1 );
|
|
if (se->reserve)
|
|
nrdpys++;
|
|
}
|
|
*serverPtr = se;
|
|
serverPtr = &se->next;
|
|
}
|
|
*serverPtr = 0;
|
|
|
|
#ifdef HAVE_VTS
|
|
/* don't copy only if all local displays are ordered and have a vt */
|
|
cpvt = 0;
|
|
getInitTab();
|
|
for (se = serverList, mtty = maxTTY; se; se = se->next)
|
|
if ((se->type & dLocation) == dLocal) {
|
|
mtty++;
|
|
if (se->vt != mtty) {
|
|
cpvt = 1;
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
for (se = serverList; se; se = se->next) {
|
|
se->argvs = joinArgs( se->argv );
|
|
se->arglvs = joinArgs( se->arglv );
|
|
}
|
|
|
|
se1 = 0, cpcmd = cpcmdl = 0;
|
|
for (se = serverList; se; se = se->next)
|
|
if ((se->type & dLocation) == dLocal) {
|
|
if (!se1)
|
|
se1 = se;
|
|
else {
|
|
if (strcmp( se1->argvs, se->argvs ))
|
|
cpcmd = 1;
|
|
if (strcmp( se1->arglvs, se->arglvs ))
|
|
cpcmdl = 1;
|
|
}
|
|
}
|
|
if (se1) {
|
|
putfqval( "X-:*-Core", "ServerCmd", se1->argvs );
|
|
putfqval( "X-:*-Core", "ServerArgsLocal", se1->arglvs );
|
|
for (se = serverList; se; se = se->next)
|
|
if ((se->type & dLocation) == dLocal) {
|
|
char sec[32];
|
|
sprintf( sec, "X-%s-Core", se->name );
|
|
if (cpcmd)
|
|
putfqval( sec, "ServerCmd", se->argvs );
|
|
if (cpcmdl)
|
|
putfqval( sec, "ServerArgsLocal", se->arglvs );
|
|
#ifdef HAVE_VTS
|
|
if (cpvt && se->vt) {
|
|
char vt[8];
|
|
sprintf( vt, "%d", se->vt );
|
|
putfqval( sec, "ServerVT", vt );
|
|
}
|
|
#else
|
|
if (se->console)
|
|
putfqval( sec, "ServerTTY", se->console );
|
|
#endif
|
|
}
|
|
}
|
|
|
|
sdpys = rdpys = 0;
|
|
for (se = serverList; se; se = se->next)
|
|
StrCat( se->reserve ? &rdpys : &sdpys,
|
|
se->class2 ? ",%s_%s" : ",%s", se->name, se->class2 );
|
|
|
|
#ifdef HAVE_VTS
|
|
/* add reserve dpys */
|
|
if (nldpys < 4 && nldpys && !nrdpys)
|
|
for (; nldpys < 4; nldpys++) {
|
|
for (dn = 0; dpymask & (1 << dn); dn++);
|
|
dpymask |= (1 << dn);
|
|
StrCat( &rdpys, ",:%d", dn );
|
|
}
|
|
#endif
|
|
|
|
putfqval( "General", "StaticServers", sdpys ? sdpys + 1 : "" );
|
|
putfqval( "General", "ReserveServers", rdpys ? rdpys + 1 : "" );
|
|
|
|
if (**value == '/' && inNewDir( *value ) && !use_destdir)
|
|
displace( *value );
|
|
}
|
|
|
|
#ifdef HAVE_VTS
|
|
static void
|
|
upd_servervts( Entry *ce, Section *cs ATTR_UNUSED )
|
|
{
|
|
if (!ce->active) { /* there is only the Global one */
|
|
#ifdef __linux__ /* XXX actually, sysvinit */
|
|
getInitTab();
|
|
ASPrintf( (char **)&ce->value, "-%d", maxTTY + 1 );
|
|
ce->active = ce->written = 1;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
static void
|
|
upd_consolettys( Entry *ce, Section *cs ATTR_UNUSED )
|
|
{
|
|
if (!ce->active) { /* there is only the Global one */
|
|
#ifdef __linux__ /* XXX actually, sysvinit */
|
|
char *buf;
|
|
int i;
|
|
|
|
getInitTab();
|
|
for (i = 0, buf = 0; i < 16; i++)
|
|
if (TTYmask & (1 << i))
|
|
StrCat( &buf, ",tty%d", i + 1 );
|
|
if (buf) {
|
|
ce->value = buf + 1;
|
|
ce->active = ce->written = 1;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef XDMCP
|
|
static void
|
|
cp_keyfile( Entry *ce, Section *cs ATTR_UNUSED )
|
|
{
|
|
if (!ce->active) /* there is only the Global one */
|
|
return;
|
|
if (old_confs)
|
|
linkfile( ce );
|
|
else
|
|
if (!copyfile( ce, "tdmkeys", 0600, 0 ))
|
|
ce->active = 0;
|
|
}
|
|
|
|
static void
|
|
mk_xaccess( Entry *ce, Section *cs ATTR_UNUSED )
|
|
{
|
|
if (!ce->active) /* there is only the Global one */
|
|
writefile( def_Xaccess, 0644, def_xaccess );
|
|
else if (old_confs)
|
|
linkfile( ce );
|
|
else
|
|
copyfile( ce, "Xaccess", 0644, 0 ); /* don't handle error, it will disable Xdmcp automatically */
|
|
}
|
|
|
|
static void
|
|
mk_willing( Entry *ce, Section *cs ATTR_UNUSED )
|
|
{
|
|
char *fname;
|
|
|
|
if (!ce->active) /* there is only the Global one */
|
|
goto dflt;
|
|
else {
|
|
if (!(fname = strchr( ce->value, '/' )))
|
|
return; /* obviously in-line (or empty) */
|
|
if (old_scripts || inNewDir( fname ))
|
|
dlinkfile( fname );
|
|
else {
|
|
dflt:
|
|
ce->value = TDMCONF "/Xwilling";
|
|
ce->active = ce->written = 1;
|
|
writefile( ce->value, 0755, def_willing );
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
static int
|
|
edit_resources( File *file )
|
|
{
|
|
// XXX remove any login*, chooser*, ... resources
|
|
return 0;
|
|
}
|
|
*/
|
|
|
|
static void
|
|
cp_resources( Entry *ce, Section *cs ATTR_UNUSED )
|
|
{
|
|
if (!ce->active) /* the X-*-Greeter one */
|
|
return;
|
|
if (old_confs)
|
|
linkfile( ce );
|
|
else
|
|
if (!copyfile( ce, ce->value, 0644, 0/*edit_resources*/ ))
|
|
ce->active = 0;
|
|
}
|
|
|
|
static int
|
|
delstr( File *fil, const char *pat )
|
|
{
|
|
char *p, *pp, *bpp;
|
|
const char *pap, *paap;
|
|
|
|
*fil->eof = 0;
|
|
for (p = fil->buf; *p; p++) {
|
|
for (pp = p, pap = pat; ; ) {
|
|
if (!*pap) {
|
|
*p = '\n';
|
|
memcpy( p + 1, pp, fil->eof - pp + 1 );
|
|
fil->eof -= pp - p - 1;
|
|
return 1;
|
|
} else if (!memcmp( pap, "*/", 2 )) {
|
|
paap = pap += 2;
|
|
while (!isspace( *pap ))
|
|
pap++;
|
|
if (*pp != '/')
|
|
break;
|
|
for (;;)
|
|
for (bpp = ++pp; *pp != '/'; pp++)
|
|
if (!*pp || isspace( *pp ))
|
|
goto wbrk;
|
|
wbrk:
|
|
if ((pp - bpp != pap - paap) || memcmp( bpp, paap, pap - paap ))
|
|
break;
|
|
} else if (*pap == '\t') {
|
|
pap++;
|
|
while (*pp == ' ' || *pp == '\t')
|
|
pp++;
|
|
} else if (*pap == '[') {
|
|
pap++;
|
|
for (;;) {
|
|
if (!*pap) {
|
|
fprintf( stderr, "Internal error: unterminated char set\n" );
|
|
exit( 1 );
|
|
}
|
|
if (*pap == *pp) {
|
|
while (*++pap != ']')
|
|
if (!*pap) {
|
|
fprintf( stderr, "Internal error: unterminated char set\n" );
|
|
exit( 1 );
|
|
}
|
|
pap++;
|
|
pp++;
|
|
break;
|
|
}
|
|
if (*++pap == ']')
|
|
goto no;
|
|
}
|
|
} else {
|
|
if (*pap == '\n')
|
|
while (*pp == ' ' || *pp == '\t')
|
|
pp++;
|
|
if (*pap != *pp)
|
|
break;
|
|
pap++;
|
|
pp++;
|
|
}
|
|
}
|
|
no: ;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* XXX
|
|
the UseBackground voodoo will horribly fail, if multiple sections link
|
|
to the same Xsetup file
|
|
*/
|
|
|
|
static int mod_usebg;
|
|
|
|
static int
|
|
edit_setup( File *file )
|
|
{
|
|
int chg =
|
|
delstr( file, "\n"
|
|
"(\n"
|
|
" PIDFILE=/var/run/tdmdesktop-$DISPLAY.pid\n"
|
|
" */tdmdesktop\t&\n"
|
|
" echo $! >$PIDFILE\n"
|
|
" wait $!\n"
|
|
" rm $PIDFILE\n"
|
|
")\t&\n" ) |
|
|
delstr( file, "\n"
|
|
"*/tdmdesktop\t&\n" ) |
|
|
delstr( file, "\n"
|
|
"tdmdesktop\t&\n" ) |
|
|
delstr( file, "\n"
|
|
"tdmdesktop\n" );
|
|
putval( "UseBackground", chg ? "true" : "false" );
|
|
return chg;
|
|
}
|
|
|
|
static void
|
|
mk_setup( Entry *ce, Section *cs )
|
|
{
|
|
setsect( resect( cs->name, "Greeter" ) );
|
|
if (old_scripts || mixed_scripts) {
|
|
if (mod_usebg && *ce->value)
|
|
putval( "UseBackground", "false" );
|
|
linkfile( ce );
|
|
} else {
|
|
if (ce->active && inNewDir( ce->value )) {
|
|
if (mod_usebg)
|
|
copyfile( ce, ce->value, 0755, edit_setup );
|
|
else
|
|
linkfile( ce );
|
|
} else {
|
|
ce->value = TDMCONF "/Xsetup";
|
|
ce->active = ce->written = 1;
|
|
writefile( ce->value, 0755, def_setup );
|
|
}
|
|
}
|
|
}
|
|
|
|
static int
|
|
edit_startup( File *file )
|
|
{
|
|
int chg1 = 0, chg2 = 0;
|
|
|
|
if (mod_usebg &&
|
|
(delstr( file, "\n"
|
|
"PIDFILE=/var/run/tdmdesktop-$DISPLAY.pid\n"
|
|
"if [[] -f $PIDFILE ] ; then\n"
|
|
" kill `cat $PIDFILE`\n"
|
|
"fi\n" ) ||
|
|
delstr( file, "\n"
|
|
"PIDFILE=/var/run/tdmdesktop-$DISPLAY.pid\n"
|
|
"test -f $PIDFILE && kill `cat $PIDFILE`\n" )))
|
|
chg1 = 1;
|
|
if (oldver < 0x0203) {
|
|
chg2 =
|
|
#ifdef _AIX
|
|
delstr( file, "\n"
|
|
"# We create a pseudodevice for finger. (host:0 becomes [kx]dm/host_0)\n" );
|
|
"# Without it, finger errors out with \"Can't stat /dev/host:0\".\n"
|
|
"#\n"
|
|
"if [[] -f /usr/lib/X11/xdm/sessreg ]; then\n"
|
|
" devname=`echo $DISPLAY | /usr/bin/sed -e 's/[[]:\\.]/_/g' | /usr/bin/cut -c1-8`\n"
|
|
" hostname=`echo $DISPLAY | /usr/bin/cut -d':' -f1`\n"
|
|
"\n"
|
|
" if [[] -z \"$devname\" ]; then\n"
|
|
" devname=\"unknown\"\n"
|
|
" fi\n"
|
|
" if [[] ! -d /dev/[kx]dm ]; then\n"
|
|
" /usr/bin/mkdir /dev/[kx]dm\n"
|
|
" /usr/bin/chmod 755 /dev/[kx]dm\n"
|
|
" fi\n"
|
|
" /usr/bin/touch /dev/[kx]dm/$devname\n"
|
|
" /usr/bin/chmod 644 /dev/[kx]dm/$devname\n"
|
|
"\n"
|
|
" if [[] -z \"$hostname\" ]; then\n"
|
|
" exec /usr/lib/X11/xdm/sessreg -a -l [kx]dm/$devname $USER\n"
|
|
" else\n"
|
|
" exec /usr/lib/X11/xdm/sessreg -a -l [kx]dm/$devname -h $hostname $USER\n"
|
|
" fi\n"
|
|
"fi\n") |
|
|
#else
|
|
# ifdef BSD
|
|
# ifdef HAVE_UTMPX
|
|
delstr( file, "\n"
|
|
"exec sessreg -a -l $DISPLAY -x */Xservers $USER\n" ) |
|
|
# else
|
|
delstr( file, "\n"
|
|
"exec sessreg -a -l $DISPLAY -x */Xservers -u " _PATH_UTMP " $USER\n" ) |
|
|
# endif
|
|
# endif
|
|
#endif /* _AIX */
|
|
delstr( file, "\n"
|
|
"exec sessreg -a -l $DISPLAY"
|
|
#ifdef BSD
|
|
" -x */Xservers"
|
|
#endif
|
|
" $USER\n" ) |
|
|
delstr( file, "\n"
|
|
"exec sessreg -a -l $DISPLAY -u /var/run/utmp -x */Xservers $USER\n" );
|
|
putval( "UseSessReg", chg2 ? "true" : "false");
|
|
}
|
|
return chg1 | chg2;
|
|
}
|
|
|
|
static void
|
|
mk_startup( Entry *ce, Section *cs )
|
|
{
|
|
setsect( cs->name );
|
|
if (old_scripts || mixed_scripts)
|
|
linkfile( ce );
|
|
else {
|
|
if (ce->active && inNewDir( ce->value )) {
|
|
if (mod_usebg || oldver < 0x0203)
|
|
copyfile( ce, ce->value, 0755, edit_startup );
|
|
else
|
|
linkfile( ce );
|
|
} else {
|
|
ce->value = TDMCONF "/Xstartup";
|
|
ce->active = ce->written = 1;
|
|
writefile( ce->value, 0755, def_startup );
|
|
}
|
|
}
|
|
}
|
|
|
|
static int
|
|
edit_reset( File *file )
|
|
{
|
|
return
|
|
#ifdef _AIX
|
|
delstr( file, "\n"
|
|
"if [[] -f /usr/lib/X11/xdm/sessreg ]; then\n"
|
|
" devname=`echo $DISPLAY | /usr/bin/sed -e 's/[[]:\\.]/_/g' | /usr/bin/cut -c1-8`\n"
|
|
" exec /usr/lib/X11/xdm/sessreg -d -l [kx]dm/$devname $USER\n"
|
|
"fi\n" ) |
|
|
#else
|
|
# ifdef BSD
|
|
# ifdef HAVE_UTMPX
|
|
delstr( file, "\n"
|
|
"exec sessreg -d -l $DISPLAY -x */Xservers $USER\n" ) |
|
|
# else
|
|
delstr( file, "\n"
|
|
"exec sessreg -d -l $DISPLAY -x */Xservers -u " _PATH_UTMP " $USER\n" ) |
|
|
# endif
|
|
# endif
|
|
#endif /* _AIX */
|
|
delstr( file, "\n"
|
|
"exec sessreg -d -l $DISPLAY"
|
|
# ifdef BSD
|
|
" -x */Xservers"
|
|
# endif
|
|
" $USER\n" ) |
|
|
delstr( file, "\n"
|
|
"exec sessreg -d -l $DISPLAY -u /var/run/utmp -x */Xservers $USER\n" );
|
|
}
|
|
|
|
static void
|
|
mk_reset( Entry *ce, Section *cs ATTR_UNUSED )
|
|
{
|
|
if (old_scripts || mixed_scripts)
|
|
linkfile( ce );
|
|
else {
|
|
if (ce->active && inNewDir( ce->value )) {
|
|
if (oldver < 0x0203)
|
|
copyfile( ce, ce->value, 0755, edit_reset );
|
|
else
|
|
linkfile( ce );
|
|
} else {
|
|
ce->value = TDMCONF "/Xreset";
|
|
ce->active = ce->written = 1;
|
|
writefile( ce->value, 0755, def_reset );
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
mk_session( Entry *ce, Section *cs ATTR_UNUSED )
|
|
{
|
|
char *def_session;
|
|
const char *tmpf;
|
|
|
|
if ((old_scripts || (ce->active && inNewDir( ce->value ))) &&
|
|
oldver >= 0x202)
|
|
linkfile( ce );
|
|
else {
|
|
tmpf = locate( "mktemp" ) ?
|
|
"`mktemp /tmp/xsess-env-XXXXXX`" :
|
|
locate( "tempfile" ) ?
|
|
"`tempfile`" :
|
|
"$HOME/.xsession-env-$DISPLAY";
|
|
ASPrintf( &def_session, "%s%s%s", def_session1, tmpf, def_session2 );
|
|
ce->value = TDMCONF "/Xsession";
|
|
ce->active = ce->written = 1;
|
|
writefile( ce->value, 0755, def_session );
|
|
}
|
|
}
|
|
|
|
static void
|
|
upd_language( Entry *ce, Section *cs ATTR_UNUSED )
|
|
{
|
|
if (!strcmp( ce->value, "C" ))
|
|
ce->value = (char *)"en_US";
|
|
}
|
|
|
|
static void
|
|
upd_guistyle( Entry *ce, Section *cs ATTR_UNUSED )
|
|
{
|
|
if (!strcmp( ce->value, "Motif+" ))
|
|
ce->value = (char *)"MotifPlus";
|
|
else if (!strcmp( ce->value, "KDE" ))
|
|
ce->value = (char *)"Default";
|
|
}
|
|
|
|
static void
|
|
upd_showusers( Entry *ce, Section *cs )
|
|
{
|
|
if (!strcmp( ce->value, "All" ))
|
|
ce->value = (char *)"NotHidden";
|
|
else if (!strcmp( ce->value, "None" )) {
|
|
if (ce->active)
|
|
putfqval( cs->name, "UserList", "false" );
|
|
ce->value = (char *)"Selected";
|
|
ce->active = 0;
|
|
ce->written = 1;
|
|
}
|
|
}
|
|
|
|
static const char *defminuid, *defmaxuid;
|
|
|
|
static void
|
|
upd_minshowuid( Entry *ce, Section *cs ATTR_UNUSED )
|
|
{
|
|
if (!ce->active) {
|
|
ce->value = defminuid;
|
|
ce->active = ce->written = 1;
|
|
}
|
|
}
|
|
|
|
static void
|
|
upd_maxshowuid( Entry *ce, Section *cs ATTR_UNUSED )
|
|
{
|
|
if (!ce->active) {
|
|
ce->value = defmaxuid;
|
|
ce->active = ce->written = 1;
|
|
}
|
|
}
|
|
|
|
static void
|
|
upd_hiddenusers( Entry *ce, Section *cs ATTR_UNUSED )
|
|
{
|
|
char *nv;
|
|
const char *msu, *pt, *et;
|
|
struct passwd *pw;
|
|
unsigned minuid, maxuid;
|
|
char nbuf[128];
|
|
|
|
if (!ce->active)
|
|
return;
|
|
|
|
msu = getfqval( cs->name, "MinShowUID", "0" );
|
|
sscanf( msu, "%u", &minuid );
|
|
msu = getfqval( cs->name, "MaxShowUID", "65535" );
|
|
sscanf( msu, "%u", &maxuid );
|
|
|
|
nv = 0;
|
|
pt = ce->value;
|
|
for (;;) {
|
|
et = strpbrk( pt, ";," );
|
|
if (et) {
|
|
memcpy( nbuf, pt, et - pt );
|
|
nbuf[et - pt] = 0;
|
|
} else
|
|
strcpy( nbuf, pt );
|
|
if ((pw = getpwnam( nbuf ))) {
|
|
if (!pw->pw_uid ||
|
|
(pw->pw_uid >= minuid && pw->pw_uid <= maxuid))
|
|
{
|
|
if (nv)
|
|
StrCat( &nv, ",%s", nbuf );
|
|
else
|
|
nv = mstrdup( nbuf );
|
|
}
|
|
}
|
|
if (!et)
|
|
break;
|
|
pt = et + 1;
|
|
}
|
|
ce->value = nv ? nv : "";
|
|
}
|
|
|
|
static void
|
|
upd_forgingseed( Entry *ce, Section *cs ATTR_UNUSED )
|
|
{
|
|
if (!ce->active) {
|
|
ASPrintf( (char **)&ce->value, "%d", time( 0 ) );
|
|
ce->active = ce->written = 1;
|
|
}
|
|
}
|
|
|
|
static void
|
|
upd_fifodir( Entry *ce, Section *cs ATTR_UNUSED )
|
|
{
|
|
const char *dir;
|
|
struct stat st;
|
|
|
|
if (use_destdir)
|
|
return;
|
|
dir = ce->active ? ce->value : def_FifoDir;
|
|
stat( dir, &st );
|
|
chmod( dir, st.st_mode | 0755 );
|
|
}
|
|
|
|
static void
|
|
upd_datadir( Entry *ce, Section *cs ATTR_UNUSED )
|
|
{
|
|
char *oldsts, *newsts;
|
|
const char *dir;
|
|
|
|
if (use_destdir)
|
|
return;
|
|
dir = ce->active ? ce->value : def_DataDir;
|
|
if (mkdirp( dir, 0755, "data", 0 ) && oldkde) {
|
|
ASPrintf( &oldsts, "%s/tdm/tdmsts", oldkde );
|
|
ASPrintf( &newsts, "%s/tdmsts", dir );
|
|
rename( oldsts, newsts );
|
|
}
|
|
}
|
|
|
|
static void
|
|
CopyFile( const char *from, const char *to )
|
|
{
|
|
File file;
|
|
int fd;
|
|
|
|
if (readFile( &file, from )) {
|
|
if ((fd = creat( to, 0644 )) >= 0) {
|
|
write( fd, file.buf, file.eof - file.buf );
|
|
close( fd );
|
|
}
|
|
freeBuf( &file );
|
|
}
|
|
}
|
|
|
|
static void
|
|
upd_facedir( Entry *ce, Section *cs ATTR_UNUSED )
|
|
{
|
|
char *oldpic, *newpic, *defpic, *rootpic;
|
|
const char *dir;
|
|
struct passwd *pw;
|
|
|
|
if (use_destdir)
|
|
return;
|
|
dir = ce->active ? ce->value : def_FaceDir;
|
|
if (mkdirp( dir, 0755, "user face", 0 )) {
|
|
ASPrintf( &defpic, "%s/.default.face.icon", dir );
|
|
ASPrintf( &rootpic, "%s/root.face.icon", dir );
|
|
if (oldkde) {
|
|
setpwent();
|
|
while ((pw = getpwent()))
|
|
if (strcmp( pw->pw_name, "root" )) {
|
|
ASPrintf( &oldpic, "%s/../apps/tdm/pics/users/%s.png",
|
|
oldkde, pw->pw_name );
|
|
ASPrintf( &newpic, "%s/%s.face.icon", dir, pw->pw_name );
|
|
rename( oldpic, newpic );
|
|
free( newpic );
|
|
free( oldpic );
|
|
}
|
|
endpwent();
|
|
ASPrintf( &oldpic, "%s/../apps/tdm/pics/users/default.png", oldkde );
|
|
if (!rename( oldpic, defpic ))
|
|
defpic = 0;
|
|
ASPrintf( &oldpic, "%s/../apps/tdm/pics/users/root.png", oldkde );
|
|
if (!rename( oldpic, rootpic ))
|
|
rootpic = 0;
|
|
}
|
|
if (defpic) {
|
|
ASPrintf( &oldpic, "%s/default1.png", facesrc );
|
|
CopyFile( oldpic, defpic );
|
|
}
|
|
if (rootpic) {
|
|
ASPrintf( &oldpic, "%s/root1.png", facesrc );
|
|
CopyFile( oldpic, rootpic );
|
|
}
|
|
}
|
|
}
|
|
|
|
CONF_GEN_ENTRIES
|
|
|
|
static Sect *
|
|
findSect( const char *name )
|
|
{
|
|
const char *p;
|
|
int i;
|
|
|
|
p = strrchr( name, '-' );
|
|
if (!p)
|
|
p = name;
|
|
for (i = 0; i < as(allSects); i++)
|
|
if (!strcmp( allSects[i]->name, p ))
|
|
return allSects[i];
|
|
fprintf( stderr, "Internal error: unknown section %s\n", name );
|
|
exit( 1 );
|
|
}
|
|
|
|
static Ent *
|
|
findEnt( Sect *sect, const char *key )
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < sect->nents; i++)
|
|
if (!strcmp( sect->ents[i].key, key ))
|
|
return sect->ents + i;
|
|
fprintf( stderr, "Internal error: unknown key %s in section %s\n",
|
|
key, sect->name );
|
|
exit( 1 );
|
|
}
|
|
|
|
|
|
/*
|
|
* defaults
|
|
*/
|
|
|
|
typedef struct DEnt {
|
|
const char *key;
|
|
const char *value;
|
|
int active;
|
|
} DEnt;
|
|
|
|
typedef struct DSect {
|
|
const char *name;
|
|
DEnt *ents;
|
|
int nents;
|
|
const char *comment;
|
|
} DSect;
|
|
|
|
CONF_GEN_EXAMPLE
|
|
|
|
static void
|
|
mkdefconf( void )
|
|
{
|
|
Section *cs, **csp;
|
|
Entry *ce, **cep;
|
|
int sc, ec;
|
|
|
|
for (csp = &config, sc = 0; sc < as(dAllSects); csp = &(cs->next), sc++) {
|
|
cs = mcalloc( sizeof(*cs) );
|
|
*csp = cs;
|
|
cs->spec = findSect( dAllSects[sc].name );
|
|
cs->name = dAllSects[sc].name;
|
|
cs->comment = dAllSects[sc].comment;
|
|
for (cep = &(cs->ents), ec = 0; ec < dAllSects[sc].nents;
|
|
cep = &(ce->next), ec++)
|
|
{
|
|
ce = mcalloc( sizeof(*ce) );
|
|
*cep = ce;
|
|
ce->spec = findEnt( cs->spec, dAllSects[sc].ents[ec].key );
|
|
ce->value = dAllSects[sc].ents[ec].value;
|
|
ce->active = dAllSects[sc].ents[ec].active;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* read rc file structure
|
|
*/
|
|
|
|
typedef struct REntry {
|
|
struct REntry *next;
|
|
const char *key;
|
|
char *value;
|
|
} REntry;
|
|
|
|
typedef struct RSection {
|
|
struct RSection *next;
|
|
const char *name;
|
|
REntry *ents;
|
|
} RSection;
|
|
|
|
static RSection *
|
|
ReadConf( const char *fname )
|
|
{
|
|
char *nstr;
|
|
char *s, *e, *st, *en, *ek, *sl;
|
|
RSection *rootsec = 0, *cursec;
|
|
REntry *curent;
|
|
int nlen;
|
|
int line, sectmoan;
|
|
File file;
|
|
|
|
if (!readFile( &file, fname ))
|
|
return 0;
|
|
usedFile( fname );
|
|
|
|
for (s = file.buf, line = 0, cursec = 0, sectmoan = 1; s < file.eof; s++) {
|
|
line++;
|
|
|
|
while ((s < file.eof) && isspace( *s ) && (*s != '\n'))
|
|
s++;
|
|
|
|
if ((s < file.eof) && ((*s == '\n') || (*s == '#'))) {
|
|
sktoeol:
|
|
while ((s < file.eof) && (*s != '\n'))
|
|
s++;
|
|
continue;
|
|
}
|
|
sl = s;
|
|
|
|
if (*s == '[') {
|
|
while ((s < file.eof) && (*s != '\n'))
|
|
s++;
|
|
e = s - 1;
|
|
while ((e > sl) && isspace( *e ))
|
|
e--;
|
|
if (*e != ']') {
|
|
fprintf( stderr, "Invalid section header at %s:%d\n",
|
|
fname, line );
|
|
continue;
|
|
}
|
|
sectmoan = 0;
|
|
nstr = sl + 1;
|
|
nlen = e - nstr;
|
|
for (cursec = rootsec; cursec; cursec = cursec->next)
|
|
if (!memcmp( nstr, cursec->name, nlen ) &&
|
|
!cursec->name[nlen])
|
|
{
|
|
#if 0 /* not our business ... */
|
|
fprintf( stderr, "Warning: Multiple occurrences of section "
|
|
"[%.*s] in %s. Consider merging them.\n",
|
|
nlen, nstr, fname );
|
|
#endif
|
|
goto secfnd;
|
|
}
|
|
cursec = mmalloc( sizeof(*cursec) );
|
|
ASPrintf( (char **)&cursec->name, "%.*s", nlen, nstr );
|
|
cursec->ents = 0;
|
|
cursec->next = rootsec;
|
|
rootsec = cursec;
|
|
secfnd:
|
|
continue;
|
|
}
|
|
|
|
if (!cursec) {
|
|
if (sectmoan) {
|
|
sectmoan = 0;
|
|
fprintf( stderr, "Entry outside any section at %s:%d",
|
|
fname, line );
|
|
}
|
|
goto sktoeol;
|
|
}
|
|
|
|
for (; (s < file.eof) && (*s != '\n'); s++)
|
|
if (*s == '=')
|
|
goto haveeq;
|
|
fprintf( stderr, "Invalid entry (missing '=') at %s:%d\n", fname, line );
|
|
continue;
|
|
|
|
haveeq:
|
|
for (ek = s - 1;; ek--) {
|
|
if (ek < sl) {
|
|
fprintf( stderr, "Invalid entry (empty key) at %s:%d\n",
|
|
fname, line );
|
|
goto sktoeol;
|
|
}
|
|
if (!isspace( *ek ))
|
|
break;
|
|
}
|
|
|
|
s++;
|
|
while ((s < file.eof) && isspace( *s ) && (*s != '\n'))
|
|
s++;
|
|
st = s;
|
|
while ((s < file.eof) && (*s != '\n'))
|
|
s++;
|
|
for (en = s - 1; en >= st && isspace( *en ); en--);
|
|
|
|
nstr = sl;
|
|
nlen = ek - sl + 1;
|
|
for (curent = cursec->ents; curent; curent = curent->next)
|
|
if (!memcmp( nstr, curent->key, nlen ) &&
|
|
!curent->key[nlen]) {
|
|
fprintf( stderr, "Multiple occurrences of key '%s' in section "
|
|
"[%s] of %s.\n", curent->key, cursec->name, fname );
|
|
goto keyfnd;
|
|
}
|
|
curent = mmalloc( sizeof(*curent) );
|
|
ASPrintf( (char **)&curent->key, "%.*s", nlen, nstr );
|
|
ASPrintf( (char **)&curent->value, "%.*s", en - st + 1, st );
|
|
curent->next = cursec->ents;
|
|
cursec->ents = curent;
|
|
keyfnd:
|
|
continue;
|
|
}
|
|
return rootsec;
|
|
}
|
|
|
|
|
|
static int
|
|
mergeKdmRcOld( const char *path )
|
|
{
|
|
char *p;
|
|
struct stat st;
|
|
|
|
ASPrintf( &p, "%s/tdmrc", path );
|
|
if (stat( p, &st )) {
|
|
free( p );
|
|
return 0;
|
|
}
|
|
printf( "Information: ignoring old tdmrc %s from kde < 2.2\n", p );
|
|
free( p );
|
|
return 1;
|
|
}
|
|
|
|
typedef struct {
|
|
const char *sect, *key, *def;
|
|
int (*cond)( void );
|
|
} FDefs;
|
|
|
|
static void
|
|
applydefs( FDefs *chgdef, int ndefs, const char *path )
|
|
{
|
|
char *p;
|
|
int i;
|
|
|
|
for (i = 0; i < ndefs; i++)
|
|
if (!getfqval( chgdef[i].sect, chgdef[i].key, 0 ) &&
|
|
(!chgdef[i].cond || chgdef[i].cond()))
|
|
{
|
|
ASPrintf( &p, chgdef[i].def, path );
|
|
putfqval( chgdef[i].sect, chgdef[i].key, p );
|
|
free( p );
|
|
}
|
|
}
|
|
|
|
#ifdef XDMCP
|
|
static FDefs tdmdefs_all[] = {
|
|
{ "Xdmcp", "Xaccess", "%s/tdm/Xaccess", 0 },
|
|
{ "Xdmcp", "Willing", "", 0 },
|
|
};
|
|
#endif
|
|
|
|
static FDefs tdmdefs_eq_22[] = {
|
|
{ "General", "PidFile", "/var/run/xdm.pid", 0 },
|
|
{ "X-*-Core", "Setup", "%s/tdm/Xsetup", 0 },
|
|
{ "X-*-Core", "Startup", "%s/tdm/Xstartup", 0 },
|
|
{ "X-*-Core", "Reset", "%s/tdm/Xreset", 0 },
|
|
{ "X-*-Core", "Session", "%s/tdm/Xsession", 0 },
|
|
};
|
|
|
|
#ifdef XDMCP
|
|
static int
|
|
if_xdmcp (void)
|
|
{
|
|
return isTrue( getfqval( "Xdmcp", "Enable", "true" ) );
|
|
}
|
|
|
|
static FDefs tdmdefs_le_30[] = {
|
|
{ "Xdmcp", "KeyFile", "%s/tdm/tdmkeys", if_xdmcp },
|
|
};
|
|
#endif
|
|
|
|
/* HACK: misused by is22conf() below */
|
|
static FDefs tdmdefs_ge_30[] = {
|
|
{ "X-*-Core", "Setup", "", 0 },
|
|
{ "X-*-Core", "Startup", "", 0 },
|
|
{ "X-*-Core", "Reset", "", 0 },
|
|
{ "X-*-Core", "Session", XBINDIR "/xterm -ls -T", 0 },
|
|
};
|
|
|
|
static int
|
|
if_usebg (void)
|
|
{
|
|
return isTrue( getfqval( "X-*-Greeter", "UseBackground", "true" ) );
|
|
}
|
|
|
|
static FDefs tdmdefs_ge_31[] = {
|
|
{ "X-*-Greeter","BackgroundCfg","%s/tdm/backgroundrc", if_usebg },
|
|
};
|
|
|
|
static int
|
|
is22conf( const char *path )
|
|
{
|
|
char *p;
|
|
const char *val;
|
|
int i, sl;
|
|
|
|
sl = ASPrintf( &p, "%s/tdm/", path );
|
|
/* safe bet, i guess ... */
|
|
for (i = 0; i < 4; i++) {
|
|
val = getfqval( "X-*-Core", tdmdefs_ge_30[i].key, 0 );
|
|
if (val && !memcmp( val, p, sl )) {
|
|
free( p );
|
|
return 0;
|
|
}
|
|
}
|
|
free( p );
|
|
return 1;
|
|
}
|
|
|
|
typedef struct KUpdEnt {
|
|
const char *okey, *nsec, *nkey;
|
|
void (*func)( const char *sect, char **value );
|
|
} KUpdEnt;
|
|
|
|
typedef struct KUpdSec {
|
|
const char *osec;
|
|
KUpdEnt *ents;
|
|
int nents;
|
|
} KUpdSec;
|
|
|
|
#ifdef XDMCP
|
|
static void
|
|
P_EnableChooser( const char *sect ATTR_UNUSED, char **value )
|
|
{
|
|
*value = (char *)(isTrue( *value ) ? "DefaultLocal" : "LocalOnly");
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
P_UseLilo( const char *sect ATTR_UNUSED, char **value )
|
|
{
|
|
*value = (char *)(isTrue( *value ) ? "Lilo" : "None");
|
|
}
|
|
|
|
CONF_GEN_KMERGE
|
|
|
|
static int
|
|
mergeKdmRcNewer( const char *path )
|
|
{
|
|
char *p;
|
|
const char *cp, *sec, *key;
|
|
RSection *rootsect, *cs;
|
|
REntry *ce;
|
|
int i, j;
|
|
static char sname[64];
|
|
|
|
ASPrintf( &p, "%s/tdm/tdmrc", path );
|
|
if (!(rootsect = ReadConf( p ))) {
|
|
free( p );
|
|
return 0;
|
|
}
|
|
printf( "Information: reading current tdmrc %s (from kde >= 2.2.x)\n", p );
|
|
free( p );
|
|
|
|
for (cs = rootsect; cs; cs = cs->next) {
|
|
if (!strcmp( cs->name, "Desktop0" )) {
|
|
background = mstrdup( "[Desktop0]\n" );
|
|
for (ce = cs->ents; ce; ce = ce->next)
|
|
StrCat( &background, "%s=%s\n", ce->key, ce->value );
|
|
} else {
|
|
cp = strrchr( cs->name, '-' );
|
|
if (!cp)
|
|
cp = cs->name;
|
|
else if (cs->name[0] != 'X' || cs->name[1] != '-')
|
|
goto dropsec;
|
|
for (i = 0; i < as(kupsects); i++)
|
|
if (!strcmp( cp, kupsects[i].osec )) {
|
|
for (ce = cs->ents; ce; ce = ce->next) {
|
|
for (j = 0; j < kupsects[i].nents; j++)
|
|
if (!strcmp( ce->key, kupsects[i].ents[j].okey )) {
|
|
if (kupsects[i].ents[j].nsec == (char *)-1) {
|
|
kupsects[i].ents[j].func( 0, &ce->value );
|
|
goto gotkey;
|
|
}
|
|
if (!kupsects[i].ents[j].nsec)
|
|
sec = cs->name;
|
|
else {
|
|
sec = sname;
|
|
sprintf( sname, "%.*s-%s", cp - cs->name, cs->name,
|
|
kupsects[i].ents[j].nsec );
|
|
}
|
|
if (!kupsects[i].ents[j].nkey)
|
|
key = ce->key;
|
|
else
|
|
key = kupsects[i].ents[j].nkey;
|
|
if (kupsects[i].ents[j].func)
|
|
kupsects[i].ents[j].func( sec, &ce->value );
|
|
putfqval( sec, key, ce->value );
|
|
goto gotkey;
|
|
}
|
|
printf( "Information: dropping key %s from section [%s]\n",
|
|
ce->key, cs->name );
|
|
gotkey: ;
|
|
}
|
|
goto gotsec;
|
|
}
|
|
dropsec:
|
|
printf( "Information: dropping section [%s]\n", cs->name );
|
|
gotsec: ;
|
|
}
|
|
}
|
|
|
|
#ifdef XDMCP
|
|
applydefs( tdmdefs_all, as(tdmdefs_all), path );
|
|
#endif
|
|
if (!*(cp = getfqval( "General", "ConfigVersion", "" ))) { /* < 3.1 */
|
|
mod_usebg = 1;
|
|
if (is22conf( path )) {
|
|
/* work around 2.2.x defaults borkedness */
|
|
applydefs( tdmdefs_eq_22, as(tdmdefs_eq_22), path );
|
|
printf( "Information: current tdmrc is from kde 2.2\n" );
|
|
} else {
|
|
applydefs( tdmdefs_ge_30, as(tdmdefs_ge_30), path );
|
|
printf( "Information: current tdmrc is from kde 3.0\n" );
|
|
}
|
|
#ifdef XDMCP
|
|
/* work around minor <= 3.0.x defaults borkedness */
|
|
applydefs( tdmdefs_le_30, as(tdmdefs_le_30), path );
|
|
#endif
|
|
} else {
|
|
int ma, mi;
|
|
sscanf( cp, "%d.%d", &ma, &mi );
|
|
oldver = (ma << 8) | mi;
|
|
printf( "Information: current tdmrc is from kde >= 3.1 (config version %d.%d)\n", ma, mi );
|
|
applydefs( tdmdefs_ge_30, as(tdmdefs_ge_30), path );
|
|
applydefs( tdmdefs_ge_31, as(tdmdefs_ge_31), path );
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
typedef struct XResEnt {
|
|
const char *xname;
|
|
const char *ksec, *kname;
|
|
void (*func)( const char *sect, char **value );
|
|
} XResEnt;
|
|
|
|
static void
|
|
handleXdmVal( const char *dpy, const char *key, char *value,
|
|
const XResEnt *ents, int nents )
|
|
{
|
|
const char *kname;
|
|
int i;
|
|
char knameb[80], sname[80];
|
|
|
|
for (i = 0; i < nents; i++)
|
|
if (!strcmp( key, ents[i].xname ) ||
|
|
(key[0] == toupper( ents[i].xname[0] ) &&
|
|
!strcmp( key + 1, ents[i].xname + 1 )))
|
|
{
|
|
if (ents[i].ksec == (char *)-1) {
|
|
ents[i].func (0, &value);
|
|
break;
|
|
}
|
|
sprintf( sname, ents[i].ksec, dpy );
|
|
if (ents[i].kname)
|
|
kname = ents[i].kname;
|
|
else {
|
|
kname = knameb;
|
|
sprintf( knameb, "%c%s",
|
|
toupper( ents[i].xname[0] ), ents[i].xname + 1 );
|
|
}
|
|
if (ents[i].func)
|
|
ents[i].func( sname, &value );
|
|
putfqval( sname, kname, value );
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
P_List( const char *sect ATTR_UNUSED, char **value )
|
|
{
|
|
int is, d, s;
|
|
char *st;
|
|
|
|
for (st = *value, is = d = s = 0; st[s]; s++)
|
|
if (st[s] == ' ' || st[s] == '\t') {
|
|
if (!is)
|
|
st[d++] = ',';
|
|
is = 1;
|
|
} else {
|
|
st[d++] = st[s];
|
|
is = 0;
|
|
}
|
|
st[d] = 0;
|
|
}
|
|
|
|
static void
|
|
P_authDir( const char *sect ATTR_UNUSED, char **value )
|
|
{
|
|
int l;
|
|
|
|
l = strlen( *value );
|
|
if (l < 4) {
|
|
*value = 0;
|
|
return;
|
|
}
|
|
if ((*value)[l-1] == '/')
|
|
(*value)[--l] = 0;
|
|
if (!strncmp( *value, "/tmp/", 5 ) ||
|
|
!strncmp( *value, "/var/tmp/", 9 ))
|
|
{
|
|
printf( "Warning: Resetting inappropriate value %s for AuthDir to default\n",
|
|
*value );
|
|
*value = 0;
|
|
return;
|
|
}
|
|
if ((l >= 4 && !strcmp( *value + l - 4, "/tmp" )) ||
|
|
(l >= 6 && !strcmp( *value + l - 6, "/xauth" )) ||
|
|
(l >= 8 && !strcmp( *value + l - 8, "/authdir" )) ||
|
|
(l >= 10 && !strcmp( *value + l - 10, "/authfiles" )))
|
|
return;
|
|
ASPrintf( value, "%s/authdir", *value );
|
|
}
|
|
|
|
static void
|
|
P_openDelay( const char *sect, char **value )
|
|
{
|
|
putfqval( sect, "ServerTimeout", *value );
|
|
}
|
|
|
|
static void
|
|
P_noPassUsers( const char *sect, char **value ATTR_UNUSED )
|
|
{
|
|
putfqval( sect, "NoPassEnable", "true" );
|
|
}
|
|
|
|
static void
|
|
P_autoUser( const char *sect, char **value ATTR_UNUSED )
|
|
{
|
|
putfqval( sect, "AutoLoginEnable", "true" );
|
|
}
|
|
|
|
#ifdef XDMCP
|
|
static void
|
|
P_requestPort( const char *sect, char **value )
|
|
{
|
|
if (!strcmp( *value, "0" )) {
|
|
*value = 0;
|
|
putfqval( sect, "Enable", "false" );
|
|
} else
|
|
putfqval( sect, "Enable", "true" );
|
|
}
|
|
#endif
|
|
|
|
static int tdmrcmode = 0644;
|
|
|
|
static void
|
|
P_autoPass( const char *sect ATTR_UNUSED, char **value ATTR_UNUSED )
|
|
{
|
|
tdmrcmode = 0600;
|
|
}
|
|
|
|
CONF_GEN_XMERGE
|
|
|
|
static XrmQuark XrmQString, empty = NULLQUARK;
|
|
|
|
static Bool
|
|
DumpEntry( XrmDatabase *db ATTR_UNUSED,
|
|
XrmBindingList bindings,
|
|
XrmQuarkList quarks,
|
|
XrmRepresentation *type,
|
|
XrmValuePtr value,
|
|
XPointer data ATTR_UNUSED )
|
|
{
|
|
const char *dpy, *key;
|
|
int el, hasu;
|
|
char dpybuf[80];
|
|
|
|
if (*type != XrmQString)
|
|
return False;
|
|
if (*bindings == XrmBindLoosely ||
|
|
strcmp( XrmQuarkToString (*quarks), "DisplayManager" ))
|
|
return False;
|
|
bindings++, quarks++;
|
|
if (!*quarks)
|
|
return False;
|
|
if (*bindings != XrmBindLoosely && !quarks[1]) { /* DM.foo */
|
|
key = XrmQuarkToString (*quarks);
|
|
handleXdmVal( 0, key, value->addr, globents, as(globents) );
|
|
return False;
|
|
} else if (*bindings == XrmBindLoosely && !quarks[1]) { /* DM*bar */
|
|
dpy = "*";
|
|
key = XrmQuarkToString (*quarks);
|
|
} else if (*bindings != XrmBindLoosely && quarks[1] &&
|
|
*bindings != XrmBindLoosely && !quarks[2])
|
|
{ /* DM.foo.bar */
|
|
dpy = dpybuf + 4;
|
|
strcpy( dpybuf + 4, XrmQuarkToString (*quarks) );
|
|
for (hasu = 0, el = 4; dpybuf[el]; el++)
|
|
if (dpybuf[el] == '_')
|
|
hasu = 1;
|
|
if (!hasu/* && isupper (dpy[0])*/) {
|
|
dpy = dpybuf;
|
|
memcpy( dpybuf, "*:*_", 4 );
|
|
} else {
|
|
for (; --el >= 0; )
|
|
if (dpybuf[el] == '_') {
|
|
dpybuf[el] = ':';
|
|
for (; --el >= 4; )
|
|
if (dpybuf[el] == '_')
|
|
dpybuf[el] = '.';
|
|
break;
|
|
}
|
|
}
|
|
key = XrmQuarkToString (quarks[1]);
|
|
} else
|
|
return False;
|
|
handleXdmVal( dpy, key, value->addr, dpyents, as(dpyents) );
|
|
return False;
|
|
}
|
|
|
|
static FDefs xdmdefs[] = {
|
|
#ifdef XDMCP
|
|
{ "Xdmcp", "Xaccess", "%s/Xaccess", 0 },
|
|
{ "Xdmcp", "Willing", "", 0 },
|
|
#endif
|
|
{ "X-*-Core", "Setup", "", 0 },
|
|
{ "X-*-Core", "Startup", "", 0 },
|
|
{ "X-*-Core", "Reset", "", 0 },
|
|
{ "X-*-Core", "Session", "", 0 },
|
|
};
|
|
|
|
static int
|
|
mergeXdmCfg( const char *path )
|
|
{
|
|
char *p;
|
|
XrmDatabase db;
|
|
|
|
ASPrintf( &p, "%s/xdm-config", path );
|
|
if ((db = XrmGetFileDatabase( p ))) {
|
|
printf( "Information: reading current xdm config file %s\n", p );
|
|
usedFile( p );
|
|
free( p );
|
|
XrmEnumerateDatabase( db, &empty, &empty, XrmEnumAllLevels,
|
|
DumpEntry, (XPointer)0 );
|
|
applydefs( xdmdefs, as(xdmdefs), path );
|
|
mod_usebg = 1;
|
|
return 1;
|
|
}
|
|
free( p );
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
fwrapprintf( FILE *f, const char *msg, ... )
|
|
{
|
|
char *txt, *ftxt, *line;
|
|
va_list ap;
|
|
int col, lword, fspace;
|
|
|
|
va_start( ap, msg );
|
|
VASPrintf( &txt, msg, ap );
|
|
va_end( ap );
|
|
ftxt = 0;
|
|
for (line = txt, col = 0, lword = fspace = -1; line[col]; ) {
|
|
if (line[col] == '\n') {
|
|
StrCat( &ftxt, "%.*s", ++col, line );
|
|
line += col;
|
|
col = 0;
|
|
lword = fspace = -1;
|
|
continue;
|
|
} else if (line[col] == ' ') {
|
|
if (lword >= 0) {
|
|
fspace = col;
|
|
lword = -1;
|
|
}
|
|
} else {
|
|
if (lword < 0)
|
|
lword = col;
|
|
if (col >= 78 && fspace >= 0) {
|
|
StrCat( &ftxt, "%.*s\n", fspace, line );
|
|
line += lword;
|
|
col -= lword;
|
|
lword = 0;
|
|
fspace = -1;
|
|
}
|
|
}
|
|
col++;
|
|
}
|
|
free( txt );
|
|
fputs( ftxt, f );
|
|
free( ftxt );
|
|
}
|
|
|
|
|
|
static const char *oldkdes[] = {
|
|
KDE_CONFDIR,
|
|
"/opt/trinity/share/config",
|
|
"/usr/local/trinity/share/config",
|
|
|
|
"/opt/kde/share/config",
|
|
"/usr/local/kde/share/config",
|
|
"/usr/local/share/config",
|
|
"/usr/share/config",
|
|
|
|
"/opt/kde2/share/config",
|
|
"/usr/local/kde2/share/config",
|
|
};
|
|
|
|
static const char *oldxdms[] = {
|
|
"/etc/X11/xdm",
|
|
XLIBDIR "/xdm",
|
|
};
|
|
|
|
int main( int argc, char **argv )
|
|
{
|
|
const char **where;
|
|
char *newtdmrc;
|
|
FILE *f;
|
|
StrList *fp;
|
|
Section *cs;
|
|
Entry *ce, **cep;
|
|
int i, ap, newer, locals, foreigns;
|
|
int no_old_xdm = 0, no_old_kde = 0;
|
|
struct stat st;
|
|
char *nname;
|
|
|
|
for (ap = 1; ap < argc; ap++) {
|
|
if (!strcmp( argv[ap], "--help" )) {
|
|
printf(
|
|
"gentdmconf - generate configuration files for tdm\n"
|
|
"\n"
|
|
"If an older xdm/tdm configuration is found, its config files are \"absorbed\";\n"
|
|
"if it lives in the new target directory, its scripts are reused (and possibly\n"
|
|
"modified) as well, otherwise the scripts are ignored and default scripts are\n"
|
|
"installed.\n"
|
|
"\n"
|
|
"options:\n"
|
|
" --in /path/to/new/tdm-config-dir\n"
|
|
" In which directory to put the new configuration. You can use this\n"
|
|
" to support a $(DESTDIR), but not to change the final location of\n"
|
|
" the installation - the paths inside the files are not affected.\n"
|
|
" Default is " TDMCONF ".\n"
|
|
" --old-xdm /path/to/old/xdm-dir\n"
|
|
" Where to look for the config files of an xdm/older tdm.\n"
|
|
" Default is to scan /etc/X11/tdm, $XLIBDIR/tdm, /etc/X11/xdm,\n"
|
|
" $XLIBDIR/xdm; there in turn look for tdm-config and xdm-config.\n"
|
|
" Note that you possibly need to use --no-old-kde to make this take effect.\n"
|
|
" --old-kde /path/to/old/tde-config-dir\n"
|
|
" Where to look for the tdmrc of an older tdm.\n"
|
|
" Default is to scan " KDE_CONFDIR " and\n"
|
|
" {/usr,/usr/local,{/opt,/usr/local}/{trinity,kde,kde2,kde1}}/share/config.\n"
|
|
" --no-old\n"
|
|
" Don't look at older xdm/tdm configurations, just create default config.\n"
|
|
" --no-old-xdm\n"
|
|
" Don't look at older xdm configurations.\n"
|
|
" --no-old-kde\n"
|
|
" Don't look at older tdm configurations.\n"
|
|
" --old-scripts\n"
|
|
" Directly use all scripts from the older xdm/tdm configuration.\n"
|
|
" --no-old-scripts\n"
|
|
" Don't use scripts from the older xdm/tdm configuration even if it lives\n"
|
|
" in the new target directory.\n"
|
|
" --old-confs\n"
|
|
" Directly use all ancillary config files from the older xdm/tdm\n"
|
|
" configuration. This is usually a bad idea.\n"
|
|
" --no-backup\n"
|
|
" Overwrite/delete old config files instead of backing them up.\n"
|
|
" --no-in-notice\n"
|
|
" Don't put the notice about --in being used into the generated README.\n"
|
|
);
|
|
exit( 0 );
|
|
}
|
|
if (!strcmp( argv[ap], "--no-old" )) {
|
|
no_old = 1;
|
|
continue;
|
|
}
|
|
if (!strcmp( argv[ap], "--old-scripts" )) {
|
|
old_scripts = 1;
|
|
continue;
|
|
}
|
|
if (!strcmp( argv[ap], "--no-old-scripts" )) {
|
|
no_old_scripts = 1;
|
|
continue;
|
|
}
|
|
if (!strcmp( argv[ap], "--old-confs" )) {
|
|
old_confs = 1;
|
|
continue;
|
|
}
|
|
if (!strcmp( argv[ap], "--no-old-xdm" )) {
|
|
no_old_xdm = 1;
|
|
continue;
|
|
}
|
|
if (!strcmp( argv[ap], "--no-old-kde" )) {
|
|
no_old_kde = 1;
|
|
continue;
|
|
}
|
|
if (!strcmp( argv[ap], "--no-backup" )) {
|
|
no_backup = 1;
|
|
continue;
|
|
}
|
|
if (!strcmp( argv[ap], "--no-in-notice" )) {
|
|
no_in_notice = 1;
|
|
continue;
|
|
}
|
|
where = 0;
|
|
if (!strcmp( argv[ap], "--in" ))
|
|
where = &newdir;
|
|
else if (!strcmp( argv[ap], "--old-xdm" ))
|
|
where = &oldxdm;
|
|
else if (!strcmp( argv[ap], "--old-kde" ))
|
|
where = &oldkde;
|
|
else if (!strcmp( argv[ap], "--face-src" ))
|
|
where = &facesrc;
|
|
else {
|
|
fprintf( stderr, "Unknown command line option '%s', try --help\n", argv[ap] );
|
|
exit( 1 );
|
|
}
|
|
if (ap + 1 == argc || argv[ap + 1][0] == '-') {
|
|
fprintf( stderr, "Missing argument to option '%s', try --help\n", argv[ap] );
|
|
exit( 1 );
|
|
}
|
|
*where = argv[++ap];
|
|
}
|
|
if (memcmp( newdir, TDMCONF, sizeof(TDMCONF) ))
|
|
use_destdir = 1;
|
|
|
|
if (!mkdirp( newdir, 0755, "target", 1 ))
|
|
exit( 1 );
|
|
|
|
mkdefconf();
|
|
newer = 0;
|
|
if (no_old) {
|
|
DIR *dir;
|
|
if ((dir = opendir( newdir ))) {
|
|
struct dirent *ent;
|
|
char bn[PATH_MAX];
|
|
while ((ent = readdir( dir ))) {
|
|
int l;
|
|
if (!strcmp( ent->d_name, "." ) || !strcmp( ent->d_name, ".." ))
|
|
continue;
|
|
l = sprintf( bn, "%s/%s", newdir, ent->d_name ); /* cannot overflow (kernel would not allow the creation of a longer path) */
|
|
if (!stat( bn, &st ) && !S_ISREG( st.st_mode ))
|
|
continue;
|
|
if (no_backup || !memcmp( bn + l - 4, ".bak", 5 ))
|
|
unlink( bn );
|
|
else
|
|
displace( bn );
|
|
}
|
|
closedir( dir );
|
|
}
|
|
} else {
|
|
if (oldkde) {
|
|
if (!(newer = mergeKdmRcNewer( oldkde )) && !mergeKdmRcOld( oldkde ))
|
|
fprintf( stderr,
|
|
"Cannot read old tdmrc at specified location\n" );
|
|
} else if (!no_old_kde) {
|
|
for (i = 0; i < as(oldkdes); i++) {
|
|
if ((newer = mergeKdmRcNewer( oldkdes[i] )) ||
|
|
mergeKdmRcOld( oldkdes[i] )) {
|
|
oldkde = oldkdes[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!newer && !no_old_xdm) {
|
|
XrmInitialize();
|
|
XrmQString = XrmPermStringToQuark( "String" );
|
|
if (oldxdm) {
|
|
if (!mergeXdmCfg( oldxdm ))
|
|
fprintf( stderr,
|
|
"Cannot read old tdm-config/xdm-config at specified location\n" );
|
|
} else
|
|
for (i = 0; i < as(oldxdms); i++)
|
|
if (mergeXdmCfg( oldxdms[i] )) {
|
|
oldxdm = oldxdms[i];
|
|
break;
|
|
}
|
|
} else
|
|
oldxdm = 0;
|
|
}
|
|
if (no_old_scripts)
|
|
goto no_old_s;
|
|
if (!old_scripts) {
|
|
locals = foreigns = 0;
|
|
for (cs = config; cs; cs = cs->next)
|
|
if (!strcmp( cs->spec->name, "-Core" )) {
|
|
for (ce = cs->ents; ce; ce = ce->next)
|
|
if (ce->active &&
|
|
(!strcmp( ce->spec->key, "Setup" ) ||
|
|
!strcmp( ce->spec->key, "Startup" ) ||
|
|
!strcmp( ce->spec->key, "Reset" )))
|
|
{
|
|
if (inNewDir( ce->value ))
|
|
locals = 1;
|
|
else
|
|
foreigns = 1;
|
|
}
|
|
}
|
|
if (foreigns) {
|
|
if (locals) {
|
|
fprintf( stderr,
|
|
"Warning: both local and foreign scripts referenced. "
|
|
"Won't touch any.\n" );
|
|
mixed_scripts = 1;
|
|
} else {
|
|
no_old_s:
|
|
for (cs = config; cs; cs = cs->next) {
|
|
if (!strcmp( cs->spec->name, "Xdmcp" )) {
|
|
for (ce = cs->ents; ce; ce = ce->next)
|
|
if (!strcmp( ce->spec->key, "Willing" ))
|
|
ce->active = ce->written = 0;
|
|
} else if (!strcmp( cs->spec->name, "-Core" )) {
|
|
for (cep = &cs->ents; (ce = *cep); ) {
|
|
if (ce->active &&
|
|
(!strcmp( ce->spec->key, "Setup" ) ||
|
|
!strcmp( ce->spec->key, "Startup" ) ||
|
|
!strcmp( ce->spec->key, "Reset" ) ||
|
|
!strcmp( ce->spec->key, "Session" )))
|
|
{
|
|
if (!memcmp( cs->name, "X-*-", 4 ))
|
|
ce->active = ce->written = 0;
|
|
else {
|
|
*cep = ce->next;
|
|
free( ce );
|
|
continue;
|
|
}
|
|
}
|
|
cep = &ce->next;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#ifdef __linux__
|
|
if (!stat( "/etc/debian_version", &st )) { /* debian */
|
|
defminuid = "1000";
|
|
defmaxuid = "29999";
|
|
} else if (!stat( "/usr/portage", &st )) { /* gentoo */
|
|
defminuid = "1000";
|
|
defmaxuid = "65000";
|
|
} else if (!stat( "/etc/mandrake-release", &st )) { /* mandrake - check before redhat! */
|
|
defminuid = "500";
|
|
defmaxuid = "65000";
|
|
} else if (!stat( "/etc/redhat-release", &st )) { /* redhat */
|
|
defminuid = "100";
|
|
defmaxuid = "65000";
|
|
} else /* if (!stat( "/etc/SuSE-release", &st )) */ { /* suse */
|
|
defminuid = "500";
|
|
defmaxuid = "65000";
|
|
}
|
|
#else
|
|
defminuid = "1000";
|
|
defmaxuid = "65000";
|
|
#endif
|
|
for (i = 0; i < CONF_MAX_PRIO; i++)
|
|
for (cs = config; cs; cs = cs->next)
|
|
for (ce = cs->ents; ce; ce = ce->next)
|
|
if (ce->spec->func && i == ce->spec->prio)
|
|
ce->spec->func( ce, cs );
|
|
ASPrintf( &newtdmrc, "%s/tdmrc", newdir );
|
|
f = Create( newtdmrc, tdmrcmode );
|
|
wrconf( f );
|
|
fclose( f );
|
|
|
|
ASPrintf( &nname, "%s/README", newdir );
|
|
f = Create( nname, 0644 );
|
|
fprintf( f,
|
|
"This automatically generated configuration consists of the following files:\n" );
|
|
fprintf( f, "- " TDMCONF "/tdmrc\n" );
|
|
for (fp = aflist; fp; fp = fp->next)
|
|
fprintf( f, "- %s\n", fp->str );
|
|
if (use_destdir && !no_in_notice)
|
|
fwrapprintf( f,
|
|
"All files destined for " TDMCONF " were actually saved in %s; "
|
|
"this config won't be workable until moved in place.\n", newdir );
|
|
if (uflist || eflist || cflist || lflist) {
|
|
fprintf( f,
|
|
"\n"
|
|
"This config was derived from existing files. As the used algorithms are\n"
|
|
"pretty dumb, it may be broken.\n" );
|
|
if (uflist) {
|
|
fprintf( f,
|
|
"Information from these files was extracted:\n" );
|
|
for (fp = uflist; fp; fp = fp->next)
|
|
fprintf( f, "- %s\n", fp->str );
|
|
}
|
|
if (lflist) {
|
|
fprintf( f,
|
|
"These files were directly incorporated:\n" );
|
|
for (fp = lflist; fp; fp = fp->next)
|
|
fprintf( f, "- %s\n", fp->str );
|
|
}
|
|
if (cflist) {
|
|
fprintf( f,
|
|
"These files were copied verbatim:\n" );
|
|
for (fp = cflist; fp; fp = fp->next)
|
|
fprintf( f, "- %s\n", fp->str );
|
|
}
|
|
if (eflist) {
|
|
fprintf( f,
|
|
"These files were copied with modifications:\n" );
|
|
for (fp = eflist; fp; fp = fp->next)
|
|
fprintf( f, "- %s\n", fp->str );
|
|
}
|
|
if (!no_backup && !use_destdir)
|
|
fprintf( f,
|
|
"Old files that would have been overwritten were renamed to <oldname>.bak.\n" );
|
|
}
|
|
fprintf( f,
|
|
"\nTry 'gentdmconf --help' if you want to generate another configuration.\n"
|
|
"\nYou may delete this README.\n" );
|
|
fclose( f );
|
|
|
|
return 0;
|
|
}
|