util.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /* (c) Copyright 1997 The Open Group */
  24. /* *
  25. * (c) Copyright 1993, 1994 Hewlett-Packard Company *
  26. * (c) Copyright 1993, 1994 International Business Machines Corp. *
  27. * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
  28. * (c) Copyright 1993, 1994 Novell, Inc. *
  29. */
  30. /*
  31. * xdm - display manager daemon
  32. *
  33. * $TOG: util.c /main/15 1998/04/06 13:22:20 mgreess $
  34. *
  35. * Copyright 1988 Massachusetts Institute of Technology
  36. *
  37. * Permission to use, copy, modify, and distribute this software and its
  38. * documentation for any purpose and without fee is hereby granted, provided
  39. * that the above copyright notice appear in all copies and that both that
  40. * copyright notice and this permission notice appear in supporting
  41. * documentation, and that the name of M.I.T. not be used in advertising or
  42. * publicity pertaining to distribution of the software without specific,
  43. * written prior permission. M.I.T. makes no representations about the
  44. * suitability of this software for any purpose. It is provided "as is"
  45. * without express or implied warranty.
  46. *
  47. * Author: Keith Packard, MIT X Consortium
  48. */
  49. /*
  50. * util.c
  51. *
  52. * various utility routines
  53. */
  54. #include <sys/stat.h>
  55. #include <setjmp.h>
  56. #include <string.h>
  57. #include <dirent.h>
  58. #include <Dt/MsgCatP.h>
  59. #include <X11/Xutil.h>
  60. #include <X11/Intrinsic.h>
  61. #include <X11/StringDefs.h>
  62. #include <X11/Xmu/SysUtil.h>
  63. #include <Dt/HourGlass.h>
  64. #include <signal.h>
  65. # include "dm.h"
  66. # include "vgmsg.h"
  67. nl_catd nl_fd = (nl_catd)-1; /* message catalog file descriptor */
  68. #if !defined(NL_CAT_LOCALE)
  69. #define NL_CAT_LOCALE 0
  70. #endif
  71. #if !defined (ENABLE_DYNAMIC_LANGLIST)
  72. #define LANGLISTSIZE 2048
  73. char languageList[LANGLISTSIZE]; /* global list of languages */
  74. #endif /* ENABLE_DYNAMIC_LANGLIST */
  75. /***************************************************************************
  76. *
  77. * Local procedure declarations
  78. *
  79. ***************************************************************************/
  80. static char * makeEnv(
  81. char *name,
  82. char *value) ;
  83. static SIGVAL MakeLangAbort(
  84. int arg );
  85. static int MatchesFileSuffix(const char *filename, const char *suffix);
  86. static void ScanNLSDir(
  87. char * dirname );
  88. /******** End Local Function Declarations ********/
  89. /***************************************************************************
  90. *
  91. * ReadCatalog
  92. *
  93. * read a string from the message catalog
  94. ***************************************************************************/
  95. unsigned char *
  96. ReadCatalog( int set_num, int msg_num, char *def_str )
  97. {
  98. static Bool alreadyopen = False;
  99. if (alreadyopen == False)
  100. {
  101. char *curNlsPath, *newNlsPath;
  102. int newNlsPathLen;
  103. alreadyopen = True;
  104. /*
  105. * Desktop message catalogs are in DT directory, so append desktop
  106. * search paths to current NLSPATH.
  107. */
  108. #define NLS_PATH_STRING CDE_INSTALLATION_TOP "/nls/msg/%L/%N.cat:" \
  109. CDE_INSTALLATION_TOP "/lib/nls/msg/%L/%N.cat:" \
  110. CDE_INSTALLATION_TOP "/lib/nls/msg/%l/%t/%c/%N.cat:" \
  111. CDE_INSTALLATION_TOP "/lib/nls/msg/%l/%c/%N.cat"
  112. curNlsPath = getenv("NLSPATH");
  113. if (curNlsPath && strlen(curNlsPath) == 0)
  114. {
  115. curNlsPath = NULL;
  116. }
  117. /*
  118. * 7 is "NLSPATH"
  119. * 1 is "="
  120. * <length of NLS_PATH_STRING>
  121. * 1 for null byte
  122. */
  123. newNlsPathLen = 7 + 1 + strlen(NLS_PATH_STRING) + 1;
  124. if (curNlsPath != NULL)
  125. {
  126. /*
  127. * 1 is ":"
  128. * <length of curNlsPath>
  129. */
  130. newNlsPathLen += (1 + strlen(curNlsPath));
  131. }
  132. newNlsPath = malloc(newNlsPathLen); /* placed in environ, do not free */
  133. if (curNlsPath != NULL)
  134. {
  135. sprintf(newNlsPath, "NLSPATH=%s:%s", curNlsPath, NLS_PATH_STRING);
  136. }
  137. else
  138. {
  139. sprintf(newNlsPath, "NLSPATH=%s", NLS_PATH_STRING);
  140. }
  141. /*
  142. * Store new NLSPATH in environment. Note this memory cannot be freed
  143. */
  144. putenv(newNlsPath);
  145. /*
  146. * Open message catalog. Note, if invalid descriptor returned (ie
  147. * msg catalog could not be opened), subsequent call to catgets() using
  148. * that descriptor will return 'def_str'.
  149. */
  150. nl_fd = CATOPEN("dtlogin", NL_CAT_LOCALE);
  151. }
  152. return ((unsigned char *) CATGETS(nl_fd, set_num, msg_num, def_str));
  153. }
  154. void
  155. printEnv( char **e )
  156. {
  157. while (*e)
  158. Debug (" %s\n", *e++);
  159. }
  160. static char *
  161. makeEnv( char *name, char *value )
  162. {
  163. char *result;
  164. result = malloc ((unsigned) (strlen (name) + strlen (value) + 2));
  165. if (!result) {
  166. LogOutOfMem(
  167. ReadCatalog(MC_LOG_SET,MC_LOG_MAKEENV,MC_DEF_LOG_MAKEENV));
  168. return 0;
  169. }
  170. if (*value) {
  171. sprintf (result, "%s=%s", name, value);
  172. }
  173. else {
  174. sprintf (result, "%s", name);
  175. }
  176. return result;
  177. }
  178. char *
  179. getEnv( char **e, char *name )
  180. {
  181. int l = strlen (name);
  182. while (*e) {
  183. if ((int) strlen (*e) > l &&
  184. !strncmp (*e, name, l) &&
  185. (*e)[l] == '=')
  186. return (*e) + l + 1;
  187. ++e;
  188. }
  189. return 0;
  190. }
  191. char **
  192. setEnv( char **e, char *name, char *value )
  193. {
  194. char **new, **old;
  195. char *newe;
  196. int envsize;
  197. int l;
  198. l = strlen (name);
  199. newe = makeEnv (name, value);
  200. if (!newe) {
  201. LogOutOfMem(ReadCatalog(MC_LOG_SET,MC_LOG_SETENV,MC_DEF_LOG_SETENV));
  202. return e;
  203. }
  204. if (e) {
  205. for (old = e; *old; old++)
  206. if ((int) strlen (*old) > l &&
  207. !strncmp (*old, name, l) &&
  208. (*old)[l] == '=')
  209. break;
  210. if (*old) {
  211. free (*old);
  212. *old = newe;
  213. return e;
  214. }
  215. envsize = old - e;
  216. new = (char **)
  217. realloc((char *) e, (unsigned) ((envsize + 2) * sizeof (char *)));
  218. } else {
  219. envsize = 0;
  220. new = (char **) malloc (2 * sizeof (char *));
  221. }
  222. if (!new) {
  223. LogOutOfMem(ReadCatalog(MC_LOG_SET,MC_LOG_SETENV,MC_DEF_LOG_SETENV));
  224. free (newe);
  225. return e;
  226. }
  227. new[envsize] = newe;
  228. new[envsize+1] = 0;
  229. return new;
  230. }
  231. void
  232. freeEnv (char **env)
  233. {
  234. char **e;
  235. if (env)
  236. {
  237. for (e = env; *e; e++)
  238. free (*e);
  239. free (env);
  240. }
  241. }
  242. # define isblank(c) ((c) == ' ' || c == '\t')
  243. char **
  244. parseArgs( char **argv, char *string )
  245. {
  246. char *word;
  247. char *save;
  248. int i;
  249. i = 0;
  250. while (argv && argv[i])
  251. ++i;
  252. if (!argv) {
  253. argv = (char **) malloc (sizeof (char *));
  254. if (!argv) {
  255. LogOutOfMem(ReadCatalog(
  256. MC_LOG_SET,MC_LOG_PARSEARGS,MC_DEF_LOG_PARSEARGS));
  257. return 0;
  258. }
  259. }
  260. word = string;
  261. for (;;) {
  262. if (!*string || isblank (*string)) {
  263. if (word != string) {
  264. argv = (char **) realloc ((char *) argv,
  265. (unsigned) ((i + 2) * sizeof (char *)));
  266. save = malloc ((unsigned) (string - word + 1));
  267. if (!argv || !save) {
  268. LogOutOfMem(ReadCatalog(MC_LOG_SET,
  269. MC_LOG_PARSEARGS,
  270. MC_DEF_LOG_PARSEARGS));
  271. if (argv)
  272. free ((char *) argv);
  273. if (save)
  274. free (save);
  275. return 0;
  276. }
  277. argv[i] = strncpy (save, word, string-word);
  278. argv[i][string-word] = '\0';
  279. i++;
  280. }
  281. if (!*string)
  282. break;
  283. word = string + 1;
  284. }
  285. ++string;
  286. }
  287. argv[i] = 0;
  288. return argv;
  289. }
  290. void
  291. CleanUpChild( void )
  292. {
  293. /*
  294. * On i386/i486 platforms setprrp() functions causes the mouse not
  295. * to work. Since in the daemon mode the parent daemon has already
  296. * executed a setpgrp it is a process and session leader. Since it
  297. * has also gotten rid of the controlling terminal there is no great
  298. * harm in not making the sub-daemons as leaders.
  299. */
  300. #if defined (SYSV) || defined (SVR4) || defined(__linux__)
  301. setpgrp ();
  302. #else
  303. setpgrp (0, getpid ());
  304. sigsetmask (0);
  305. #endif
  306. #ifdef SIGCHLD
  307. (void) signal (SIGCHLD, SIG_DFL);
  308. #endif
  309. (void) signal (SIGTERM, SIG_DFL);
  310. (void) signal (SIGPIPE, SIG_DFL);
  311. (void) signal (SIGALRM, SIG_DFL);
  312. (void) signal (SIGHUP, SIG_DFL);
  313. CloseOnFork ();
  314. }
  315. char * *
  316. parseEnv( char **e, char *string )
  317. {
  318. char *s1, *s2, *t1, *t2;
  319. s1 = s2 = strdup(string);
  320. while ((t1 = strtok(s1," \t")) != NULL ) {
  321. if ( (t2 = strchr(t1,'=')) != NULL ) {
  322. *t2++ = '\0';
  323. e = setEnv(e, t1, t2);
  324. }
  325. s1 = NULL;
  326. }
  327. free(s2);
  328. return (e);
  329. }
  330. /*************************************<->*************************************
  331. *
  332. * void SetHourGlassCursor
  333. *
  334. *
  335. * Description:
  336. * -----------
  337. * sets the window cursor to an hourglass
  338. *
  339. *
  340. * Inputs:
  341. * ------
  342. * dpy = display
  343. * w = window
  344. *
  345. * Outputs:
  346. * -------
  347. * None
  348. *
  349. * Comments:
  350. * --------
  351. * None. (None doesn't count as a comment)
  352. *
  353. *************************************<->***********************************/
  354. void
  355. SetHourGlassCursor( Display *dpy, Window w )
  356. {
  357. Cursor cursor;
  358. XUndefineCursor(dpy, w);
  359. cursor = _DtGetHourGlassCursor(dpy);
  360. XDefineCursor(dpy, w, cursor);
  361. XFreeCursor(dpy, cursor);
  362. XFlush(dpy);
  363. }
  364. #if !defined (ENABLE_DYNAMIC_LANGLIST)
  365. /***************************************************************************
  366. *
  367. * MakeLangList
  368. *
  369. * Generate the list of languages installed on the host.
  370. * Result is stored the global array "languageList"
  371. *
  372. ***************************************************************************/
  373. #define DELIM " \t" /* delimiters in language list */
  374. static sigjmp_buf langJump;
  375. static SIGVAL
  376. MakeLangAbort( int arg )
  377. {
  378. siglongjmp (langJump, 1);
  379. }
  380. void
  381. MakeLangList( void )
  382. {
  383. int i, j;
  384. char *lang[500]; /* sort list for languages */
  385. int nlang; /* total number of languages */
  386. char *p, *s;
  387. char *savelist;
  388. /*
  389. * build language list from set of languages installed on the host...
  390. * Wrap a timer around it so it doesn't hang things up too long.
  391. * langListTimeout resource by default is 30 seconds to scan NLS dir.
  392. */
  393. p = languageList;
  394. strcpy( p, "C");
  395. signal (SIGALRM, MakeLangAbort);
  396. alarm ((unsigned) langListTimeout);
  397. if (!sigsetjmp (langJump, 1)) {
  398. ScanNLSDir(DEF_NLS_DIR);
  399. }
  400. else {
  401. LogError(ReadCatalog(MC_LOG_SET,MC_LOG_NO_SCAN,MC_DEF_LOG_NO_SCAN),
  402. DEF_NLS_DIR, langListTimeout);
  403. }
  404. alarm (0);
  405. signal (SIGALRM, SIG_DFL);
  406. /*
  407. * sort the list to eliminate duplicates and replace in global array...
  408. */
  409. p = savelist = strdup(languageList);
  410. nlang = 0;
  411. while ( (s = strtok(p, DELIM)) != NULL ) {
  412. if ( nlang == 0 ) {
  413. lang[0] = s;
  414. lang[++nlang] = 0;
  415. p = NULL;
  416. continue;
  417. }
  418. for (i = nlang; i > 0 && strcmp(s,lang[i-1]) < 0; i--);
  419. if (i==0 || strcmp(s,lang[i-1]) != 0 ) {
  420. for (j = nlang; j > i; j--)
  421. lang[j] = lang[j-1];
  422. lang[i] = s;
  423. lang[++nlang] = 0;
  424. }
  425. p = NULL;
  426. }
  427. p = languageList;
  428. strcpy(p,"");
  429. for ( i = 0; i < nlang; i++) {
  430. strcat(p, lang[i]);
  431. strcat(p, " ");
  432. }
  433. free(savelist);
  434. }
  435. static int
  436. MatchesFileSuffix(const char *filename, const char *suffix)
  437. {
  438. int retval = 0;
  439. #if defined(_AIX) || defined(SVR4) || defined(__linux__) || defined(CSRG_BASED)
  440. int different = 1;
  441. /*
  442. * The assumption here is that the use of strrstr is
  443. * to determine if "dp->d_name" ends in ".cat".
  444. */
  445. if (strlen(filename) >= strlen(suffix)) {
  446. different = strcmp(filename + (strlen(filename) - strlen (suffix)), suffix);
  447. }
  448. return (different == 0);
  449. #else
  450. return (strrstr(filename, suffix) != NULL);
  451. #endif
  452. }
  453. /***************************************************************************
  454. *
  455. * ScanNLSDir
  456. *
  457. * Scan a directory structure to see if it contains an installed language.
  458. * If so, the name of the language is appended to a global list of languages.
  459. *
  460. * Scan method and scan directory will vary by platform.
  461. *
  462. ***************************************************************************/
  463. static void
  464. ScanNLSDir(char *dirname)
  465. #if defined(_AIX)
  466. /*
  467. * Search installed locale names for AIX 3.2.5
  468. */
  469. {
  470. DIR *dirp;
  471. struct dirent *dp;
  472. /* Search valid locales which are locale database files in
  473. * /usr/lib/nls/loc.
  474. * File name is "??_??" which can be used as LANG variable.
  475. */
  476. if((dirp = opendir(dirname)) != NULL)
  477. {
  478. while((dp = readdir(dirp)) != NULL)
  479. {
  480. if(strlen(dp->d_name) == 5 && dp->d_name[2] == '_')
  481. {
  482. if((int) strlen(languageList) + 7 < LANGLISTSIZE )
  483. {
  484. strcat(languageList, " ");
  485. strcat(languageList, dp->d_name);
  486. }
  487. }
  488. }
  489. closedir(dirp);
  490. }
  491. }
  492. #else /* !_AIX */
  493. /*
  494. * Scan for installed locales on generic platform
  495. */
  496. {
  497. DIR *dirp;
  498. struct dirent *dp;
  499. char* locale;
  500. char locale_path[MAXPATHLEN];
  501. struct stat locale_stat;
  502. int retval;
  503. /*
  504. * To determin the fully installed locale list, check several locations.
  505. */
  506. if(NULL != (dirp = opendir(dirname)))
  507. {
  508. while((dp = readdir(dirp)) != NULL)
  509. {
  510. locale = dp->d_name;
  511. if ( (strcmp(dp->d_name, ".") == 0) ||
  512. (strcmp(dp->d_name, "..") == 0) )
  513. continue;
  514. if (locale[0] != '.' &&
  515. LANGLISTSIZE > (int) (strlen(languageList)+strlen(locale)+2))
  516. {
  517. (void) snprintf(locale_path, MAXPATHLEN, "%s/%s",
  518. dirname, locale);
  519. retval = stat(locale_path, &locale_stat);
  520. if (0 == retval && S_ISDIR(locale_stat.st_mode))
  521. {
  522. strcat(languageList, " ");
  523. strcat(languageList, locale);
  524. }
  525. }
  526. }
  527. closedir(dirp);
  528. }
  529. }
  530. #endif
  531. #endif /* ENABLE_DYNAMIC_LANGLIST */
  532. #ifdef _AIX
  533. #define ENVFILE "/etc/environment"
  534. /* Refer to the LANG environment variable, first.
  535. * Or, search a line which includes "LANG=XX_XX" in /etc/environment.
  536. * If succeeded, set the value to d->language.
  537. */
  538. void
  539. SetDefaultLanguage(struct display *d)
  540. {
  541. FILE *file;
  542. char lineBuf[160];
  543. int n;
  544. char *p;
  545. char *lang = NULL;
  546. if((lang = getenv( "LANG" )) == NULL ) {
  547. if((file = fopen(ENVFILE, "r")) != NULL) {
  548. while(fgets(lineBuf, sizeof(lineBuf) - 1, file)) {
  549. n = strlen(lineBuf);
  550. if(n > 1 && lineBuf[0] != '#') {
  551. if(lineBuf[n - 1] == '\n')
  552. lineBuf[n - 1] = '\0';
  553. if((p = strstr(lineBuf, "LANG=")) != NULL) {
  554. p += 5;
  555. if(strlen(p) == 5 && p[2] == '_') {
  556. lang = p;
  557. break;
  558. }
  559. }
  560. }
  561. }
  562. fclose(file);
  563. }
  564. }
  565. if(lang != NULL && strlen(lang) > 0) {
  566. /*
  567. * If LANG is set for hft, we need to change it for X.
  568. * Currently there are four hft LANG variables.
  569. */
  570. if(strcmp(lang, "En_JP") == 0)
  571. strcpy(d->language, "Ja_JP");
  572. else if(strcmp(lang, "en_JP") == 0)
  573. strcpy(d->language, "ja_JP");
  574. else if(strcmp(lang, "en_KR") == 0)
  575. strcpy(d->language, "ko_KR");
  576. else if(strcmp(lang, "en_TW") == 0)
  577. strcpy(d->language, "zh_TW");
  578. else
  579. *(strncpy(d->language, lang, LANGUAGESIZE) + LANGUAGESIZE) = '\0';
  580. }
  581. }
  582. #endif /* _AIX */
  583. char **
  584. setLang( struct display *d, char **env , char *langptr)
  585. {
  586. char langlist[LANGLISTSIZE];
  587. int s = 0;
  588. char *element = NULL;
  589. int set_def_lang = FALSE;
  590. if (NULL != langptr)
  591. Debug("setLang(): langlist = %s\n", langptr);
  592. else
  593. Debug("setLang(): langlist = NULL\n");
  594. if (langptr)
  595. snprintf(langlist, sizeof(langlist), "%s", langptr);
  596. else
  597. snprintf(langlist, sizeof(langlist), "%s", getEnv(env, "LANGLIST"));
  598. if (strlen(langlist) > 0) {
  599. element = strtok(langlist, DELIM);
  600. while(element) {
  601. set_def_lang = FALSE;
  602. if (strcmp(element,d->language) == 0){
  603. env = setEnv(env, "LANG", d->language);
  604. break;
  605. }
  606. else
  607. set_def_lang = TRUE;
  608. s += strlen(element) +1;
  609. element = strtok(langlist+s, DELIM);
  610. }
  611. } else
  612. set_def_lang = TRUE;
  613. if (set_def_lang) {
  614. env = setEnv(env, "LANG", "C");
  615. strcpy(d->language, "C");
  616. }
  617. return env;
  618. }
  619. static char localHostbuf[256];
  620. static int gotLocalHostname;
  621. char *
  622. localHostname (void)
  623. {
  624. if (!gotLocalHostname)
  625. {
  626. XmuGetHostname (localHostbuf, sizeof (localHostbuf) - 1);
  627. gotLocalHostname = 1;
  628. }
  629. return localHostbuf;
  630. }