khostname.cpp
00001 /* This file is part of the KDE libraries 00002 * Copyright (C) 2001 Waldo Bastian <bastian@kde.org> 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Library General Public 00006 * License version 2 as published by the Free Software Foundation; 00007 * 00008 * This library is distributed in the hope that it will be useful, 00009 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00011 * Library General Public License for more details. 00012 * 00013 * You should have received a copy of the GNU Library General Public License 00014 * along with this library; see the file COPYING.LIB. If not, write to 00015 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00016 * Boston, MA 02110-1301, USA. 00017 **/ 00018 00019 #include <config.h> 00020 00021 #include <sys/types.h> 00022 #include <sys/stat.h> 00023 #include <unistd.h> 00024 #include <stdlib.h> 00025 #include <stdio.h> 00026 00027 #include <tqfile.h> 00028 #include <tqtextstream.h> 00029 #include <tqregexp.h> 00030 00031 #include <dcopclient.h> 00032 00033 #include <kcmdlineargs.h> 00034 #include <kapplication.h> 00035 #include <klocale.h> 00036 #include <kaboutdata.h> 00037 #include <kglobal.h> 00038 #include <kstandarddirs.h> 00039 #include <kprocess.h> 00040 #include <kde_file.h> 00041 00042 static KCmdLineOptions options[] = { 00043 { "+old", I18N_NOOP("Old hostname"), 0 }, 00044 { "+new", I18N_NOOP("New hostname"), 0 }, 00045 KCmdLineLastOption 00046 }; 00047 00048 static const char appName[] = "kdontchangethehostname"; 00049 static const char appVersion[] = "1.1"; 00050 00051 class KHostName 00052 { 00053 public: 00054 KHostName(); 00055 00056 void changeX(); 00057 void changeDcop(); 00058 void changeStdDirs(const TQCString &type); 00059 void changeSessionManager(); 00060 00061 protected: 00062 TQCString oldName; 00063 TQCString newName; 00064 TQCString display; 00065 TQCString home; 00066 }; 00067 00068 KHostName::KHostName() 00069 { 00070 KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); 00071 if (args->count() != 2) 00072 args->usage(); 00073 oldName = args->arg(0); 00074 newName = args->arg(1); 00075 if (oldName == newName) 00076 exit(0); 00077 00078 home = ::getenv("HOME"); 00079 if (home.isEmpty()) 00080 { 00081 fprintf(stderr, "%s", i18n("Error: HOME environment variable not set.\n").local8Bit().data()); 00082 exit(1); 00083 } 00084 00085 display = ::getenv("DISPLAY"); 00086 // strip the screen number from the display 00087 display.replace(TQRegExp("\\.[0-9]+$"), ""); 00088 if (display.isEmpty()) 00089 { 00090 fprintf(stderr, "%s", i18n("Error: DISPLAY environment variable not set.\n").local8Bit().data()); 00091 exit(1); 00092 } 00093 } 00094 00095 static QCStringList split(const TQCString &str) 00096 { 00097 const char *s = str.data(); 00098 QCStringList result; 00099 while (*s) 00100 { 00101 const char *i = strchr(s, ' '); 00102 if (!i) 00103 { 00104 result.append(TQCString(s)); 00105 return result; 00106 } 00107 result.append(TQCString(s, i-s+1)); 00108 s = i; 00109 while (*s == ' ') s++; 00110 } 00111 return result; 00112 } 00113 00114 void KHostName::changeX() 00115 { 00116 const char* xauthlocalhostname = getenv("XAUTHLOCALHOSTNAME"); 00117 TQString cmd = "xauth -n list"; 00118 FILE *xFile = popen(TQFile::encodeName(cmd), "r"); 00119 if (!xFile) 00120 { 00121 fprintf(stderr, "Warning: Can't run xauth.\n"); 00122 return; 00123 } 00124 QCStringList lines; 00125 { 00126 char buf[1024+1]; 00127 while (!feof(xFile)) 00128 { 00129 buf[1024]='\0'; 00130 TQCString line = fgets(buf, 1024, xFile); 00131 if (line.length()) 00132 line.truncate(line.length()-1); // Strip LF. 00133 if (!line.isEmpty()) 00134 lines.append(line); 00135 } 00136 } 00137 pclose(xFile); 00138 00139 for(QCStringList::ConstIterator it = lines.begin(); 00140 it != lines.end(); ++it) 00141 { 00142 QCStringList entries = split(*it); 00143 if (entries.count() != 3) 00144 continue; 00145 00146 TQCString netId = entries[0]; 00147 TQCString authName = entries[1]; 00148 TQCString authKey = entries[2]; 00149 00150 int i = netId.findRev(':'); 00151 if (i == -1) 00152 continue; 00153 TQCString netDisplay = netId.mid(i); 00154 if (netDisplay != display) 00155 continue; 00156 00157 i = netId.find('/'); 00158 if (i == -1) 00159 continue; 00160 00161 TQCString newNetId = newName+netId.mid(i); 00162 TQCString oldNetId = netId.left(i); 00163 00164 if(oldNetId != oldName 00165 && (!xauthlocalhostname || strcmp(xauthlocalhostname, oldNetId.data()) != 0)) 00166 continue; 00167 00168 // don't nuke the xauth when XAUTHLOCALHOSTNAME points to it 00169 if (!xauthlocalhostname || oldNetId != xauthlocalhostname) 00170 { 00171 cmd = "xauth -n remove "+KProcess::quote(netId); 00172 system(TQFile::encodeName(cmd)); 00173 } 00174 cmd = "xauth -n add "; 00175 cmd += KProcess::quote(newNetId); 00176 cmd += " "; 00177 cmd += KProcess::quote(authName); 00178 cmd += " "; 00179 cmd += KProcess::quote(authKey); 00180 system(TQFile::encodeName(cmd)); 00181 } 00182 } 00183 00184 void KHostName::changeDcop() 00185 { 00186 TQCString origFNameOld = DCOPClient::dcopServerFileOld(oldName); 00187 TQCString fname = DCOPClient::dcopServerFile(oldName); 00188 TQCString origFName = fname; 00189 FILE *dcopFile = fopen(fname.data(), "r"); 00190 if (!dcopFile) 00191 { 00192 fprintf(stderr, "Warning: Can't open '%s' for reading.\n", fname.data()); 00193 return; 00194 } 00195 00196 TQCString line1, line2; 00197 { 00198 char buf[1024+1]; 00199 line1 = fgets(buf, 1024, dcopFile); 00200 if (line1.length()) 00201 line1.truncate(line1.length()-1); // Strip LF. 00202 00203 line2 = fgets(buf, 1024, dcopFile); 00204 if (line2.length()) 00205 line2.truncate(line2.length()-1); // Strip LF. 00206 } 00207 fclose(dcopFile); 00208 00209 TQCString oldNetId = line1; 00210 00211 if (!newName.isEmpty()) 00212 { 00213 int i = line1.findRev(':'); 00214 if (i == -1) 00215 { 00216 fprintf(stderr, "Warning: File '%s' has unexpected format.\n", fname.data()); 00217 return; 00218 } 00219 line1 = "local/"+newName+line1.mid(i); 00220 TQCString newNetId = line1; 00221 fname = DCOPClient::dcopServerFile(newName); 00222 unlink(fname.data()); 00223 dcopFile = fopen(fname.data(), "w"); 00224 if (!dcopFile) 00225 { 00226 fprintf(stderr, "Warning: Can't open '%s' for writing.\n", fname.data()); 00227 return; 00228 } 00229 00230 fputs(line1.data(), dcopFile); 00231 fputc('\n', dcopFile); 00232 fputs(line2.data(), dcopFile); 00233 fputc('\n', dcopFile); 00234 00235 fclose(dcopFile); 00236 00237 TQCString compatLink = DCOPClient::dcopServerFileOld(newName); 00238 ::symlink(fname.data(), compatLink.data()); // Compatibility link 00239 00240 // Update .ICEauthority 00241 TQString cmd = ICEAUTH_COMMAND " list "+KProcess::quote("netid="+oldNetId); 00242 FILE *iceFile = popen(TQFile::encodeName(cmd), "r"); 00243 if (!iceFile) 00244 { 00245 fprintf(stderr, "Warning: Can't run iceauth.\n"); 00246 return; 00247 } 00248 QCStringList lines; 00249 { 00250 char buf[1024+1]; 00251 while (!feof(iceFile)) 00252 { 00253 TQCString line = fgets(buf, 1024, iceFile); 00254 if (line.length()) 00255 line.truncate(line.length()-1); // Strip LF. 00256 if (!line.isEmpty()) 00257 lines.append(line); 00258 } 00259 } 00260 pclose(iceFile); 00261 00262 for(QCStringList::ConstIterator it = lines.begin(); 00263 it != lines.end(); ++it) 00264 { 00265 QCStringList entries = split(*it); 00266 if (entries.count() != 5) 00267 continue; 00268 00269 TQCString protName = entries[0]; 00270 TQCString netId = entries[2]; 00271 TQCString authName = entries[3]; 00272 TQCString authKey = entries[4]; 00273 if (netId != oldNetId) 00274 continue; 00275 00276 cmd = ICEAUTH_COMMAND " add "; 00277 cmd += KProcess::quote(protName); 00278 cmd += " '' "; 00279 cmd += KProcess::quote(newNetId); 00280 cmd += " "; 00281 cmd += KProcess::quote(authName); 00282 cmd += " "; 00283 cmd += KProcess::quote(authKey); 00284 system(TQFile::encodeName(cmd)); 00285 } 00286 } 00287 00288 // Remove old entries, but only if XAUTHLOCALHOSTNAME doesn't point 00289 // to it 00290 char* xauthlocalhostname = getenv("XAUTHLOCALHOSTNAME"); 00291 if (!xauthlocalhostname || !oldNetId.contains(xauthlocalhostname)) 00292 { 00293 TQString cmd = ICEAUTH_COMMAND " remove "+KProcess::quote("netid="+oldNetId); 00294 system(TQFile::encodeName(cmd)); 00295 unlink(origFName.data()); 00296 origFName = DCOPClient::dcopServerFileOld(oldName); // Compatibility link 00297 unlink(origFName.data()); 00298 } 00299 } 00300 00301 void KHostName::changeStdDirs(const TQCString &type) 00302 { 00303 // We make links to the old dirs cause we can't delete the old dirs. 00304 TQCString oldDir = TQFile::encodeName(TQString("%1%2-%3").arg(KGlobal::dirs()->localkdedir()).arg(type.data()).arg(oldName.data())); 00305 TQCString newDir = TQFile::encodeName(TQString("%1%2-%3").arg(KGlobal::dirs()->localkdedir()).arg(type.data()).arg(newName.data())); 00306 00307 KDE_struct_stat st_buf; 00308 00309 int result = KDE_lstat(oldDir.data(), &st_buf); 00310 if (result == 0) 00311 { 00312 if (S_ISLNK(st_buf.st_mode)) 00313 { 00314 char buf[4096+1]; 00315 result = readlink(oldDir.data(), buf, 4096); 00316 if (result >= 0) 00317 { 00318 buf[result] = 0; 00319 result = symlink(buf, newDir.data()); 00320 } 00321 } 00322 else if (S_ISDIR(st_buf.st_mode)) 00323 { 00324 result = symlink(oldDir.data(), newDir.data()); 00325 } 00326 else 00327 { 00328 result = -1; 00329 } 00330 } 00331 if (result != 0) 00332 { 00333 system(("lnusertemp "+type).data()); 00334 } 00335 } 00336 00337 void KHostName::changeSessionManager() 00338 { 00339 TQCString sm = ::getenv("SESSION_MANAGER"); 00340 if (sm.isEmpty()) 00341 { 00342 fprintf(stderr, "Warning: No session management specified.\n"); 00343 return; 00344 } 00345 int i = sm.findRev(':'); 00346 if ((i == -1) || (sm.left(6) != "local/")) 00347 { 00348 fprintf(stderr, "Warning: Session Management socket '%s' has unexpected format.\n", sm.data()); 00349 return; 00350 } 00351 sm = "local/"+newName+sm.mid(i); 00352 TQCString name = "SESSION_MANAGER"; 00353 TQByteArray params; 00354 TQDataStream stream(params, IO_WriteOnly); 00355 stream << name << sm; 00356 DCOPClient *client = new DCOPClient(); 00357 if (!client->attach()) 00358 { 00359 fprintf(stderr, "Warning: DCOP communication problem, can't fix Session Management.\n"); 00360 delete client; 00361 return; 00362 } 00363 TQCString launcher = KApplication::launcher(); 00364 client->send(launcher, launcher, "setLaunchEnv(TQCString,TQCString)", params); 00365 delete client; 00366 } 00367 00368 int main(int argc, char **argv) 00369 { 00370 KLocale::setMainCatalogue("kdelibs"); 00371 KAboutData d(appName, I18N_NOOP("KDontChangeTheHostName"), appVersion, 00372 I18N_NOOP("Informs KDE about a change in hostname"), 00373 KAboutData::License_GPL, "(c) 2001 Waldo Bastian"); 00374 d.addAuthor("Waldo Bastian", I18N_NOOP("Author"), "bastian@kde.org"); 00375 00376 KCmdLineArgs::init(argc, argv, &d); 00377 KCmdLineArgs::addCmdLineOptions(options); 00378 00379 KInstance k(&d); 00380 00381 KHostName hn; 00382 00383 hn.changeX(); 00384 hn.changeDcop(); 00385 hn.changeStdDirs("socket"); 00386 hn.changeStdDirs("tmp"); 00387 hn.changeSessionManager(); 00388 } 00389