2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 //%% (c) Copyright 1993, 1994 Hewlett-Packard Company
24 //%% (c) Copyright 1993, 1994 International Business Machines Corp.
25 //%% (c) Copyright 1993, 1994 Sun Microsystems, Inc.
26 //%% (c) Copyright 1993, 1994 Novell, Inc.
27 //%% $TOG: mp_typedb.C /main/5 1998/03/20 14:29:07 mgreess $
29 * @(#)mp_typedb.C 1.54 93/07/29 SMI
31 * mp_typedb.cc - _Tt_typedb represents the database of ToolTalk types
33 * Copyright (c) 1990,1992 by Sun Microsystems, Inc.
37 // Contains methods for reading and writing type databases which can be
38 // stored either as Classing Engine databases or a native xdr format
43 # include <g++/minmax.h>
48 #include "tt_options.h"
49 #include "mp/mp_arg.h"
53 #include "mp_typedb.h"
54 #include "api/c/api_api.h"
55 #include "tttk/tttk.h"
59 #include "mp_ce_attrs.h"
60 #ifdef OPT_CLASSING_ENGINE
62 * See the comments in ./ce.h for why local includes are used instead of
70 #include "util/tt_enumname.h"
71 #include "util/tt_port.h"
72 #include "util/tt_gettext.h"
73 #include "util/tt_global_env.h"
74 #include "util/tt_xdr_version.h"
77 extern "C" void xdrstdio_create(XDR *, FILE *, enum xdr_op);
81 enum _Tt_typedb_flags {
89 #ifdef OPT_CLASSING_ENGINE
91 # include <util/tt_ldpath.h>
94 typedef void *(*_Tt_cefn_ptr)(...);
95 // Function-table for all Classing Engine functions used. Note
96 // that it is important that the function slots be named the
97 // same as the corresponding Classing Engine function. This is
98 // so the CALLCE macro works properly.
101 _Tt_cefn_ptr ce_abort_write;
102 _Tt_cefn_ptr ce_add_attribute;
103 _Tt_cefn_ptr ce_add_entry;
104 _Tt_cefn_ptr ce_add_namespace;
105 _Tt_cefn_ptr ce_alloc_entry;
106 _Tt_cefn_ptr ce_alloc_ns_entry;
107 _Tt_cefn_ptr ce_begin;
108 _Tt_cefn_ptr ce_commit_write;
109 _Tt_cefn_ptr ce_get_attribute;
110 _Tt_cefn_ptr ce_get_attribute_id;
111 _Tt_cefn_ptr ce_get_attribute_name;
112 _Tt_cefn_ptr ce_get_attribute_type;
113 _Tt_cefn_ptr ce_get_entry_db_info;
114 _Tt_cefn_ptr ce_get_namespace_id;
115 _Tt_cefn_ptr ce_map_through_attrs;
116 _Tt_cefn_ptr ce_map_through_entries;
117 _Tt_cefn_ptr ce_remove_entry;
118 _Tt_cefn_ptr ce_start_write;
121 // define CALLCE such that it indirects through a function
122 // slot in _tt_celib which will be filled in by dlsyming
123 // entry points from a dynamically loaded libce.so
125 # define CALLCE(fn) (*_tt_celib . fn)
127 // assume libce.so is linked in so CALLCE just becomes a
129 # define CALLCE(fn) fn
130 # endif // OPT_DLOPEN_CE
132 * Handle to the Type namespace
134 static CE_NAMESPACE _ce_type_ns = (CE_NAMESPACE)0;
136 * Set of CE attributes used to avoid having to do string comparisons for
137 * string fields in the CE databases. Each CE namespace assigns unique
138 * numeric ids to all attribute names in order to provide a cheap way for
139 * clients to compare against attribute names.
141 static CE_ATTRIBUTE _tt_attrs[_TT_CE_ATTR_LAST];
142 static CE_NAMESPACE _ce_write_ns = (CE_NAMESPACE)0;
143 #endif // OPT_CLASSING_ENGINE
146 #ifdef OPT_CLASSING_ENGINE
148 _Tt_typedb(char *ce_dir)
153 _Tt_typedb(char * /* ce_dir */)
157 ptable = new _Tt_ptype_table(_tt_ptype_ptid);
158 otable = new _Tt_otype_table(_tt_otype_otid);
159 ceDB2Use = TypedbAll;
170 // XDR's a _Tt_typedb object.
174 if (!ptable.xdr(xdrs)) {
178 if (!otable.xdr(xdrs)) {
182 if (xdrs->x_op == XDR_DECODE) {
184 // We have to be sure that a null ptable or otable are
185 // NEVER passed into the _Tt_object_table::xdr. XXX.
187 if (ptable.is_null()) {
188 ptable = new _Tt_ptype_table(_tt_ptype_ptid);
190 if (otable.is_null()) {
191 otable = new _Tt_otype_table(_tt_otype_otid);
201 // This function returns the full pathnames to the user database, system
202 // database, and network databases in udb, sdb, and ndb respectively.
203 // This three-level model of databases is intended to be similar to the
204 // Classing Engine model. The intent is that types in the user database
205 // shadow types in the system and network databases and that the types in
206 // the system database shadow the types in the network database. In order
207 // to provide some user-configurability, we provide an
208 // environment variable TTPATH that is a three-path list separated by ":"
209 // pointing to the user,system, and network databases. This function
210 // looks at that variable and returns the paths.
212 // If TTPATH isn't set this function should returns
213 // $HOME/.tt/types.xdr for the user database, /etc/tt/types.xdr for the
214 // system database, and $OPENWINHOME/etc/tt/types.xdr for the network
218 _tt_map_xdr_dbpaths(_Tt_string &udb, _Tt_string &sdb, _Tt_string &ndb)
220 _Tt_string_list_ptr path = _Tt_typedb::tt_path();
221 if (path.is_null()) return 1;
222 _Tt_string_list_cursor pathC( path );
223 if (! pathC.next()) {
227 if (! pathC.next()) {
231 if (! pathC.next()) {
239 _Tt_typedb::tt_path()
241 _Tt_string_list *pathlist = new _Tt_string_list;
242 if (pathlist == 0) return 0;
243 _Tt_string path = getenv("TTPATH");
244 if (path.len() <= 0) {
245 _Tt_string home = getenv("HOME");
246 pathlist->append(home.cat("/.tt/types.xdr"));
247 pathlist->append(_Tt_string("/etc/tt/types.xdr"));
249 _Tt_string("/usr/dt/appconfig/tttypes/types.xdr"));
250 home = getenv("OPENWINHOME");
251 if (home.len() == 0) {
252 home = "/usr/openwin";
254 pathlist->append(home.cat(_Tt_string("/etc/tt/types.xdr")));
256 // parse the user:system:network from path variable
262 pathname = path.left(n);
263 if (pathname.len() == 0) break;
264 path = path.right(path.len() - n - 1);
269 if (_tt_isdir(pathname)) {
270 pathname = pathname.cat("/types.xdr");
272 pathlist->append( pathname );
279 Tt_status _Tt_typedb::
280 init_xdr(const _Tt_string &compiled_file)
283 // A temporary is needed because
284 // a types file is an XDRed _Tt_typedb_ptr, (XXX)
285 // instead of an XDRed _Tt_typedb, and
286 // _Tt_typedb_ptr::xdr() creates a new _Tt_typedb.
287 // This was a bad choice, but we are stuck with it.
289 _Tt_typedb_ptr tmpdb;
292 // Need to remember what kind of _Tt_typedb we are,
293 // in case we are asked to remove or merge types.
295 _flags |= (1<<_TT_TYPEDB_XDR_MODE);
297 status = merge_from(compiled_file, tmpdb);
298 if (status != TT_OK) {
302 // Now snare a reference to the tables of the temp db.
303 // The temp db goes away, but we keep its tables.
305 if (!tmpdb.is_null()) {
306 ptable = tmpdb->ptable;
307 otable = tmpdb->otable;
312 Tt_status _Tt_typedb::
315 _Tt_typedb_ptr tmpdb;
319 _flags |= (1<<_TT_TYPEDB_XDR_MODE);
321 status = merge_from(f, tmpdb, version);
322 if (status != TT_OK) {
326 if (!tmpdb.is_null()) {
327 ptable = tmpdb->ptable;
328 otable = tmpdb->otable;
334 // Initializes this object from the given xdr database.
336 // TT_ERR_PATH Bad $TTPATH
337 // TT_ERR_NO_MATCH version mismatch
338 // TT_ERR_DBCONSIST XDR failure, corrupt database
340 Tt_status _Tt_typedb::
341 init_xdr(_Tt_typedbLevel xdb)
343 _Tt_typedb_ptr tmpdb;
346 if (! _tt_map_xdr_dbpaths(user_db, system_db, network_db)) {
347 _tt_syslog(stderr, LOG_ERR, "$TTPATH: %s", strerror(EINVAL));
351 _flags |= (1<<_TT_TYPEDB_XDR_MODE);
353 // type files are read in in reverse order of TTPATH
354 // variable so that entries in databases to the left
355 // of others in TTPATH shadow those to the right.
357 _Tt_string_list_ptr path;
362 if (path.is_null()) {
363 status = TT_ERR_NOMEM;
365 _Tt_string_list_cursor pathC( path );
367 while (pathC.prev() && (status == TT_OK)) {
368 status = merge_from(*pathC, tmpdb);
370 if (status == TT_OK) {
371 _flags |= (1<<_TT_TYPEDB_NETWORK);
372 _flags |= (1<<_TT_TYPEDB_SYSTEM);
373 _flags |= (1<<_TT_TYPEDB_USER);
378 if (network_db.len()) {
379 status = merge_from(network_db, tmpdb);
380 if (status == TT_OK) {
381 _flags |= (1<<_TT_TYPEDB_NETWORK);
384 _tt_syslog(stderr, LOG_ERR, "!network_db.len()");
385 status = TT_ERR_INTERNAL;
389 if (system_db.len()) {
390 status = merge_from(system_db, tmpdb);
391 if (status == TT_OK) {
392 _flags |= (1<<_TT_TYPEDB_SYSTEM);
395 _tt_syslog(stderr, LOG_ERR, "!system_db.len()");
396 status = TT_ERR_INTERNAL;
401 status = merge_from(user_db, tmpdb);
402 if (status == TT_OK) {
403 _flags |= (1<<_TT_TYPEDB_USER);
405 } else if (xdb != TypedbAll) {
406 _tt_syslog(stderr, LOG_ERR, "!user_db.len()");
407 status = TT_ERR_INTERNAL;
411 if (status != TT_OK) {
414 if (!tmpdb.is_null()) {
415 ptable = tmpdb->ptable;
416 otable = tmpdb->otable;
423 // Merges (or reads) types from dbpath into a (new) _Tt_typedb in tdb
425 Tt_status _Tt_typedb::
426 merge_from(const _Tt_string &dbpath, _Tt_typedb_ptr &tdb)
432 // The automatic converter (ttce2xdr) will just touch the
433 // user\'s .tt/types.xdr if there were no ToolTalk types in the
434 // classing engine db. This means that a zero-length file
435 // is perfectly OK, it just contains no types.
437 struct stat stat_buf;
438 if (stat( (char *)dbpath, &stat_buf ) == 0) {
439 if (stat_buf.st_size == 0) {
444 if (f = fopen((char *)dbpath, "r")) {
445 fcntl(fileno(f), F_SETFD, 1); /* close on exec */
446 result = merge_from(f, tdb, version);
449 // It is OK for the database not to exist, ToolTalk runs
450 // even if there are no types.
454 if (result == TT_ERR_NO_MATCH) {
455 // This file is newer than we are, so we cannot
457 _tt_syslog(stderr, LOG_ERR,
458 catgets(_ttcatd, 2, 9,
459 "%s is a version %d types "
460 "database, and this version "
461 "can only read versions %d and earlier"),
462 (char *)dbpath, version,
463 TT_PUSH_ROTATE_XDR_VERSION);
464 } else if (result == TT_ERR_DBCONSIST) {
465 _tt_syslog(stderr, LOG_ERR,
466 catgets(_ttcatd, 2, 10,
467 "could not decode types from types "
468 "database: %s. It may be damaged."),
477 // Merges (or reads) types from f into a (new) _Tt_typedb in tdb
479 Tt_status _Tt_typedb::
480 merge_from(FILE *f, _Tt_typedb_ptr &tdb, int &version)
484 xdrstdio_create(&xdrs, f, XDR_DECODE);
485 return merge_from(&xdrs, tdb, version);
489 // Merges (or reads) types from xdrs into a (new) _Tt_typedb in tdb
491 // Picks the version off the xdr xstream and then invokes the
492 // xdr method on the given _Tt_typedb object to merge in the types.
493 // Used both by merge_from above to read in files and to handle
494 // the types sent over from clients via tt_session_types_load().
496 Tt_status _Tt_typedb::
497 merge_from(XDR *xdrs, _Tt_typedb_ptr &tdb, int &version)
500 if (! xdr_int(xdrs, &version)) {
501 return TT_ERR_DBCONSIST;
503 if (version > TT_PUSH_ROTATE_XDR_VERSION) {
504 // This file is newer than we are, so we cannot
506 return TT_ERR_NO_MATCH;
509 _Tt_xdr_version xvers(version);
511 if (! tdb.xdr(xdrs)) {
512 return TT_ERR_DBCONSIST;
517 #ifdef OPT_CLASSING_ENGINE
520 // Function that prints out the given Classing Engine error code to
524 print_ce_error(int ce_err)
526 _tt_syslog(stderr, LOG_ERR, "Classing Engine: %d (%s)",
527 ce_err, _tt_enumname( (_Tt_ce_status)ce_err ));
529 #endif // OPT_CLASSING_ENGINE
533 // Aborts a write transaction to a databse. If this is a write to an xdr
534 // database then the lock file is removed. Otherwise it is a Classing
535 // Engine database and the appropiate abort function is invoked.
540 #ifdef OPT_CLASSING_ENGINE
541 if (_flags&(1<<_TT_TYPEDB_XDR_MODE)) {
544 (void)unlink((char *)_lock_file);
547 #ifdef OPT_CLASSING_ENGINE
551 ce_err = (int)CALLCE(ce_abort_write)(0);
555 #endif // !OPT_CLASSING_ENGINE
560 // Removes an otype with id otid from the database either in xdr format
561 // or in Classing Engine format. If the database is in xdr format then
562 // this method just removes the otype from the in-memory otype table
563 // since it is assumed that a subsequent _Tt_typedb::end_write will cause
564 // the in-memory otype table to supersede the one on disk. If the
565 // database is a Classing Engine database then we remove it using the
566 // appropiate Classing Engine routines.
569 remove_otype(_Tt_string otid)
572 if (! otable->lookup(otid,ot)) {
576 #ifdef OPT_CLASSING_ENGINE
577 char *db_name, *db_path;
579 if (! (_flags&(1<<_TT_TYPEDB_XDR_MODE))) {
581 _Tt_signature_list_cursor sigs;
583 // remove the otype entry from the ce database
584 // XXX: shouldn't this be done only if this entry was
585 // in the database we have open for write?? (see how
586 // this is done below in removing signatures)
587 ce_err = (int)CALLCE(ce_remove_entry)(_ce_type_ns,
588 (CE_ENTRY)ot->ce_entry);
590 // remove all the observer signatures (which are
591 // separate entries) from the ce databse.
592 sigs.reset(ot->_osigs);
593 while (ce_err == 0 && sigs.next()) {
594 // get the db info for this ce entry.
595 ce_err = (int)CALLCE(ce_get_entry_db_info)(_ce_type_ns,
596 (CE_ENTRY)sigs->ce_entry,
598 if (ce_err==0 && _ce_dir==db_name) {
599 // if this entry was in the ce
600 // database we have open for write
602 ce_err = (int)CALLCE(ce_remove_entry)(_ce_type_ns,
603 (CE_ENTRY)sigs->ce_entry);
607 // remove all the handler signatures (which are
608 // separate entries) from the ce databse.
609 sigs.reset(ot->_hsigs);
610 while (ce_err == 0 && sigs.next()) {
611 // get the db info for this ce entry.
612 ce_err = (int)CALLCE(ce_get_entry_db_info)(_ce_type_ns,
613 (CE_ENTRY)sigs->ce_entry,
615 if (ce_err==0 && _ce_dir==db_name) {
616 // if this entry was in the ce
617 // database we have open for write
619 ce_err = (int)CALLCE(ce_remove_entry)(_ce_type_ns,
620 (CE_ENTRY)sigs->ce_entry);
624 print_ce_error(ce_err);
628 #endif // OPT_CLASSING_ENGINE
630 otable->remove(otid);
637 // Removes an ptype with id ptid from the database either in xdr format
638 // or in Classing Engine format. If the database is in xdr format then
639 // this method just removes the ptype from the in-memory ptype table
640 // since it is assumed that a subsequent _Tt_typedb::end_write will cause
641 // the in-memory ptype table to supersede the one on disk. If the
642 // database is a Classing Engine database then we remove it using the
643 // appropiate Classing Engine routines.
646 remove_ptype(_Tt_string ptid)
649 if (! ptable->lookup(ptid,pt)) {
653 #ifdef OPT_CLASSING_ENGINE
654 char *db_name, *db_path;
656 if (! (_flags&(1<<_TT_TYPEDB_XDR_MODE))) {
658 _Tt_signature_list_cursor sigs;
660 // remove the ptype entry from the database
661 // XXX: shouldn't this be done only if this entry was
662 // in the database we have open for write?? (see how
663 // this is done below in removing signatures)
664 ce_err = (int)CALLCE(ce_remove_entry)(_ce_type_ns,
665 (CE_ENTRY)pt->ce_entry);
667 // remove the ptype's observer signatures from the
669 sigs.reset(pt->_osigs);
670 while (ce_err==0 && sigs.next()) {
671 // get the db info for this ce entry.
672 ce_err = (int)CALLCE(ce_get_entry_db_info)(_ce_type_ns,
673 (CE_ENTRY)sigs->ce_entry,
675 if (ce_err==0 && _ce_dir==db_name) {
676 // if this entry was in the ce
677 // database we have open for write
679 ce_err = (int)CALLCE(ce_remove_entry)(_ce_type_ns,
680 (CE_ENTRY)sigs->ce_entry);
684 // remove the ptype's handler signatures from the database.
685 sigs.reset(pt->_hsigs);
686 while (ce_err==0 && sigs.next()) {
687 // get the db info for this ce entry.
688 ce_err = (int)CALLCE(ce_get_entry_db_info)(_ce_type_ns,
689 (CE_ENTRY)sigs->ce_entry,
691 if (ce_err==0 && _ce_dir==db_name) {
692 // if this entry was in the ce
693 // database we have open for write
695 ce_err = (int)CALLCE(ce_remove_entry)(_ce_type_ns,
696 (CE_ENTRY)sigs->ce_entry);
700 print_ce_error(ce_err);
704 #endif // OPT_CLASSING_ENGINE
706 ptable->remove(ptid);
712 // Inserts a new ptype into the ptype table for this type database. If
713 // this database is stored in xdr format then this method just inserts
714 // the object into the in-memory table since it assumes a subsequent
715 // invocation of _Tt_typedb::end_write will write out the new table to
716 // disk. In Classing Engine format we create a Classing Engine entry and
717 // then use the appropiate ce functions to insert it into the database.
720 insert(_Tt_ptype_ptr &pt)
726 #ifndef OPT_CLASSING_ENGINE
729 if (_flags&(1<<_TT_TYPEDB_XDR_MODE)) {
734 _Tt_signature_list_cursor sigs;
736 pt->ce_entry = make_ce_entry(pt);
737 ce_err = (int)CALLCE(ce_add_entry)(_ce_write_ns, pt->ce_entry);
739 // insert all observer signatures as separate classing engine
741 sigs.reset(pt->_osigs);
742 while (ce_err==0 && sigs.next()) {
743 if (sigs->otid().len()) {
746 sigs->ce_entry = (void *)make_ce_entry(*sigs);
747 if (sigs->ce_entry == (void *)0) {
750 ce_err = (int)CALLCE(ce_add_entry)(_ce_write_ns,
751 (CE_ENTRY)sigs->ce_entry);
754 // insert all handler signatures as separate classing engine
756 sigs.reset(pt->_hsigs);
757 while (ce_err==0 && sigs.next()) {
758 if (sigs->otid().len()) {
761 sigs->ce_entry = (void *)make_ce_entry(*sigs);
762 if (sigs->ce_entry == (void *)0) {
765 ce_err = (int)CALLCE(ce_add_entry)(_ce_write_ns,
766 (CE_ENTRY)sigs->ce_entry);
769 print_ce_error(ce_err);
774 #endif // !OPT_CLASSING_ENGINE
780 // Inserts a new otype into the ptype table for this type database. If
781 // this database is stored in xdr format then this method just inserts
782 // the object into the in-memory table since it assumes a subsequent
783 // invocation of _Tt_typedb::end_write will write out the new table to
784 // disk. In Classing Engine format we create a Classing Engine entry and
785 // then use the appropiate ce functions to insert it into the database.
788 insert(_Tt_otype_ptr &ot)
793 #ifndef OPT_CLASSING_ENGINE
796 if (_flags&(1<<_TT_TYPEDB_XDR_MODE)) {
801 _Tt_signature_list_cursor sigs;
803 ot->ce_entry = make_ce_entry(ot);
804 if (ot->ce_entry == (void *)0) {
807 ce_err = (int)CALLCE(ce_add_entry)(_ce_write_ns, ot->ce_entry);
809 // insert all the otype's observer signatures as separate
811 sigs.reset(ot->_osigs);
812 while (ce_err==0 && sigs.next()) {
813 sigs->ce_entry = (void *)make_ce_entry(*sigs);
814 if (sigs->ce_entry == (void *)0) {
817 ce_err = (int)CALLCE(ce_add_entry)(_ce_write_ns,
818 (CE_ENTRY)sigs->ce_entry);
821 // insert all the otype's handler signatures as separate
823 sigs.reset(ot->_hsigs);
824 while (ce_err==0 && sigs.next()) {
825 sigs->ce_entry = (void *)make_ce_entry(*sigs);
826 if (sigs->ce_entry == (void *)0) {
829 ce_err = (int)CALLCE(ce_add_entry)(_ce_write_ns,
830 (CE_ENTRY)sigs->ce_entry);
833 print_ce_error(ce_err);
838 #endif // !OPT_CLASSING_ENGINE
843 // Prepares the database to be written out to disk. In Classing Engine
844 // mode this means we have to add the ToolTalk namespace to the database
845 // if it doesn't exist and invoke the appropiate Classing Engine function
846 // to start the write transaction. In xdr mode, we have to acquire the
847 // lock file to write out the database.
850 #ifdef OPT_CLASSING_ENGINE
851 begin_write(_Tt_typedbLevel db)
853 begin_write(_Tt_typedbLevel /* db */)
856 #ifdef OPT_CLASSING_ENGINE
857 if (! (_flags&(1<<_TT_TYPEDB_XDR_MODE))) {
862 int namespace_created = 0;
864 ce_err = (int)CALLCE(ce_start_write)(level_name(db));
866 print_ce_error(ce_err);
869 ce_err = (int)CALLCE(ce_add_namespace)(TT_NS_NAME, &_ce_write_ns);
872 // namespace not already there add it
873 ce_err = (int)CALLCE(ce_alloc_ns_entry)(_ce_write_ns, &cn);
875 print_ce_error(ce_err);
878 val = "$CEPATH/tns_mgr.so";
879 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
883 for (i=0; ce_err == 0 && i < _TT_CE_ATTR_LAST; i++) {
884 ce_err = (int)CALLCE(ce_alloc_entry)(_ce_write_ns,
889 val = "$CEPATH/tns_mgr.so";
890 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns,
892 _tt_ce_attr_string((_Tt_ce_attr)i), "string", "attr", strlen("attr"));
895 print_ce_error(ce_err);
898 namespace_created = 1;
899 // fall into next case
900 case CE_ERR_NAMESPACE_EXISTS:
901 if (!namespace_created) {
902 _ce_write_ns = _ce_type_ns;
904 _ce_dir = level_name(db);
907 print_ce_error(ce_err);
913 #endif // OPT_CLASSING_ENGINE
920 // acquire a write lock
921 if (_flags&(1<<_TT_TYPEDB_USER)) {
923 } else if (_flags&(1<<_TT_TYPEDB_SYSTEM)) {
925 } else if (_flags&(1<<_TT_TYPEDB_NETWORK)) {
929 n = path.rindex('/');
933 dir_path = path.left(n);
936 _lock_file = dir_path.cat("/.tt_lock");
939 // mkdir in case the "tt" or ".tt" subdirectory doesn't exist.
941 (void)mkdir((char *)dir_path, 0777); // ignore errors, probably EEXIST
943 while ((fd = open((char *)_lock_file,
944 O_WRONLY|O_CREAT|O_EXCL, 0777) == -1)
947 _tt_syslog(stderr, LOG_ERR, "%s: %m",
948 (char *)_lock_file, strerror(EEXIST));
950 _flags &= ~(1<<_TT_TYPEDB_LOCKED);
956 close(fd); // Cleanup
958 _flags |= (1<<_TT_TYPEDB_LOCKED);
964 // Commits the write transaction to the database. In Classing Engine mode
965 // we just call the ce_commit_write function. In xdr mode we write out
966 // the database to a temporary file and then rename the file to be the
972 #ifdef OPT_CLASSING_ENGINE
973 if (! (_flags&(1<<_TT_TYPEDB_XDR_MODE))) {
974 int ce_err = (int)CALLCE(ce_commit_write)(0);
977 print_ce_error(ce_err);
983 #endif // OPT_CLASSING_ENGINE
986 _Tt_string dbpath_tmp;
989 if (!(_flags&(1<<_TT_TYPEDB_LOCKED))) {
992 if (_flags&(1<<_TT_TYPEDB_USER)) {
994 } else if (_flags&(1<<_TT_TYPEDB_SYSTEM)) {
996 } else if (_flags&(1<<_TT_TYPEDB_NETWORK)) {
999 dbpath_tmp = dbpath.cat("_tmp");
1000 success = write(dbpath_tmp) == TT_OK;
1002 (void)unlink((char *)dbpath_tmp);
1003 (void)unlink((char *)_lock_file);
1007 success = (0 == rename((char *)dbpath_tmp, (char *)dbpath));
1009 send_saved( dbpath );
1010 _tt_syslog(stdout, LOG_INFO,
1011 catgets(_ttcatd, 2, 11, "Overwrote %s"),
1014 _tt_syslog(stderr, LOG_ERR,
1015 "rename( \"%s\", \"%s\" ): %m",
1016 (char *)dbpath_tmp, (char *)dbpath);
1018 (void)unlink((char *)_lock_file);
1019 (void)unlink((char *)dbpath_tmp);
1023 Tt_status _Tt_typedb::
1024 write(const _Tt_string &outfile)
1026 if (outfile.len() == 0) {
1027 return TT_DESKTOP_ENOENT;
1029 FILE *f = fopen((char *)outfile,"w");
1031 _tt_syslog(stderr, LOG_ERR, "%s: %m", (char *)outfile);
1032 return _tt_errno_status( errno );
1034 fcntl(fileno(f), F_SETFD, 1); /* Close on exec */
1035 Tt_status status = write( f );
1040 Tt_status _Tt_typedb::
1041 write(FILE *outfile)
1045 _Tt_typedb_ptr tdb_ptr = this;
1047 // For maximum compatibility, only write out types files
1048 // using the new XDR routines if the signatures have
1050 xdr_version = xdr_version_required();
1051 _Tt_xdr_version xvers(xdr_version);
1053 xdrstdio_create(&xdrs, outfile, XDR_ENCODE);
1054 if (! xdr_int(&xdrs, &xdr_version) || ! tdb_ptr.xdr(&xdrs)) {
1055 _tt_syslog(stderr, LOG_ERR, "! _Tt_typedb_ptr::xdr()" );
1062 // Do a tt_open() (if needed) and a ttdt_file_notice(), syslog()ing any error.
1064 Tt_status _Tt_typedb::
1065 send_saved(const _Tt_string &savedfile)
1067 const char *default_opt = "Saved";
1069 char *procid = tt_default_procid();
1070 Tt_status status = tt_ptr_error( procid );
1078 status = tt_ptr_error( procid );
1079 if (status == TT_OK) {
1083 if (status != TT_OK) {
1085 // No default session from which to send the notice,
1086 // so silently omit it. In principle libtt can send
1087 // a file-scoped notice without having a default session,
1088 // but the API does not permit this.
1093 // The HP linker thinks that ttdt_file_notice() ultimately
1094 // depends on some Xt symbols. The HP linker is wrong.
1095 // The AIX linker knows better. On SunOS, of course, we
1098 Tt_message msg = tt_message_create();
1099 tt_message_class_set( msg, TT_NOTICE );
1100 tt_message_scope_set( msg, TT_FILE );
1101 tt_message_address_set( msg, TT_PROCEDURE );
1102 tt_message_op_set( msg, default_opt );
1103 status = tt_message_file_set( msg, savedfile );
1104 if (status != TT_OK) {
1105 _tt_syslog(stderr, LOG_ERR,
1106 "tt_message_file_set(): %s", tt_status_message(status));
1108 tt_message_arg_add( msg, TT_IN, "File", 0 );
1109 status = tt_message_send( msg );
1110 if (status != TT_OK) {
1111 _tt_syslog(stderr, LOG_ERR,
1112 "tt_message_send(): %s", tt_status_message(status));
1117 #ifdef OPT_CLASSING_ENGINE
1120 // Creates a Classing Engine entry from a pointer to a _Tt_ptype
1121 // object. A CE entry is essentially an attribute/value list. The
1122 // names of the attributes are derived from the function
1123 // _tt_ce_attr_string which returns a string from an enum describing
1124 // the attribute that is to be written out.
1127 make_ce_entry(_Tt_ptype_ptr &pt)
1133 _Tt_ptype_prop_list_cursor props;
1135 ce_err = (int)CALLCE(ce_alloc_entry)(_ce_write_ns, &cn);
1137 print_ce_error(ce_err);
1140 val = (char *)pt->ptid();
1141 len = pt->ptid().len();
1142 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1143 _tt_ce_attr_string(_TYPE_NAME),
1144 _tt_ce_attr_string(_TT_TOOLTALK_PTYPE),
1147 print_ce_error(ce_err);
1150 val = _tt_ce_attr_string(_TT_TOOLTALK_PTYPE);
1152 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1153 _tt_ce_attr_string(_TT_TOOLTALK_TYPE),
1156 print_ce_error(ce_err);
1159 props.reset(pt->_props);
1160 while (props.next()) {
1161 val = (char *)props->value();
1162 len = props->value().len();
1163 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1164 (char *)props->name(),
1165 "string", val, len);
1167 print_ce_error(ce_err);
1176 // Creates a Classing Engine entry from a pointer to a _Tt_otype
1177 // object. A CE entry is essentially an attribute/value list. The
1178 // names of the attributes are derived from the function
1179 // _tt_ce_attr_string which returns a string from an enum describing
1180 // the attribute that is to be written out.
1183 make_ce_entry(_Tt_otype_ptr &ot)
1187 _Tt_string_list_cursor anc;
1191 ce_err = (int)CALLCE(ce_alloc_entry)(_ce_write_ns, &cn);
1193 print_ce_error(ce_err);
1196 val = (char *)ot->_otid;
1197 len = ot->_otid.len();
1198 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1199 _tt_ce_attr_string(_TYPE_NAME),
1200 _tt_ce_attr_string(_TT_TOOLTALK_OTYPE),
1203 print_ce_error(ce_err);
1206 val = _tt_ce_attr_string(_TT_TOOLTALK_OTYPE);
1208 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1209 _tt_ce_attr_string(_TT_TOOLTALK_TYPE),
1210 "string", val, len);
1212 print_ce_error(ce_err);
1215 if (! ot->_ancestors.is_null()) {
1216 anc.reset(ot->_ancestors);
1217 while (anc.next()) {
1220 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1221 _tt_ce_attr_string(_TT_PARENT),
1225 print_ce_error(ce_err);
1236 // Creates a Classing Engine entry from a pointer to a _Tt_signature
1237 // object. A CE entry is essentially an attribute/value list. The
1238 // names of the attributes are derived from the function
1239 // _tt_ce_attr_string which returns a string from an enum describing
1240 // the attribute that is to be written out.
1243 make_ce_entry(_Tt_signature_ptr &st)
1247 _Tt_arg_list_cursor argc;
1252 ce_err = (int)CALLCE(ce_alloc_entry)(_ce_write_ns, &cn);
1254 print_ce_error(ce_err);
1257 if (st->_mangled_args.len() == 0) {
1258 // in order to uniquely name this signature we have to
1259 // play the same tricks that C++ does and write out
1260 // the ptype or otype, the operation name of the
1261 // signature and then an encoding of the signature
1262 // argument types to distinguish it in the case of
1265 st->_mangled_args = "_";
1266 argc.reset(st->_args);
1267 while (argc.next()) {
1268 amode = argc->mode();
1269 st->_mangled_args = st->_mangled_args.cat(_tt_enumname(amode)).cat(argc->type()).cat("_");
1273 val = ((st->_otid.len()) ? st->_otid : st->_ptid);
1274 val = val.cat("::").cat(st->_op).cat(st->_mangled_args);
1275 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1276 _tt_ce_attr_string(_TYPE_NAME),
1277 _tt_ce_attr_string(_TT_TOOLTALK_TYPE),
1278 (char *)val, val.len());
1280 print_ce_error(ce_err);
1283 val = _tt_ce_attr_string(_TT_TOOLTALK_SIGNATURE);
1284 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1285 _tt_ce_attr_string(_TT_TOOLTALK_TYPE),
1286 "string", (char *)val, val.len());
1288 print_ce_error(ce_err);
1293 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1294 _tt_ce_attr_string(_TT_OP),
1295 "string", (char *)val, val.len());
1297 print_ce_error(ce_err);
1301 val = _tt_enumname(st->_pattern_category);
1302 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1303 _tt_ce_attr_string(_TT_CATEGORY),
1304 "string", (char *)val, val.len());
1306 print_ce_error(ce_err);
1310 argc.reset(st->_args);
1312 _Tt_string argc_type;
1314 (char *)malloc(strlen(_tt_ce_attr_string(_TT_ARG)) + 5);
1315 char *attrnamenum = attrname+strlen(_tt_ce_attr_string(_TT_ARG));
1316 strcpy(attrname,_tt_ce_attr_string(_TT_ARG));
1318 while (argc.next()) {
1319 sprintf((char *)attrnamenum, "%d", argn);
1320 val = _tt_enumname(argc->mode());
1321 argc_type = argc->type();
1322 val = val.cat(" ").cat(argc_type).cat(" ").cat(argc->name());
1323 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1326 (char *)val, val.len());
1328 print_ce_error(ce_err);
1335 name = ((st->_otid.len()) ? _tt_ce_attr_string(_TT_MSET_SCOPE) :
1336 _tt_ce_attr_string(_TT_SCOPE));
1337 val = _tt_enumname(st->_scope);
1338 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn, name, "string",
1339 (char *)val, val.len());
1341 print_ce_error(ce_err);
1345 val = _tt_enumname(st->_message_class);
1346 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1347 _tt_ce_attr_string(_TT_CLASS),
1348 "string", (char *)val, val.len());
1350 print_ce_error(ce_err);
1353 _Tt_string attr_typename = "string";
1354 switch (st->_reliability) {
1355 case TT_START+TT_QUEUE:
1356 #ifdef NOT_BACKWARD_COMPATIBLE
1357 val = _tt_ce_attr_string( _TT_START );
1358 val = val.cat( "+" ).cat( _tt_ce_attr_string( _TT_QUEUE ));
1359 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1360 _tt_ce_attr_string(_TT_MSET_DISPOSITION),
1361 (char *)attr_typename,
1362 (char *)val, val.len());
1364 print_ce_error(ce_err);
1370 // Version 1.0 can only handle finding start, queue,
1371 // or discard in the disposition attribute (bug
1372 // 1082628). So we will hide a clue that we are
1373 // something else in the typename of this attribute.
1374 // This works because in 1.0 _tt_convert_signature_attrs()
1375 // assumes the typename is "string", and never checks it.
1378 attr_typename.cat( ":" )
1379 .cat( _tt_ce_attr_string( _TT_START ))
1381 .cat( _tt_ce_attr_string( _TT_QUEUE ));
1383 // Now pretend it was START, so that we put start reliability
1384 // where 1.0 versions will find it. We assume here
1385 // that starting is more important than queueing.
1388 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1389 _tt_ce_attr_string(_TT_MSET_DISPOSITION),
1390 (char *)attr_typename,
1391 (char *)val, val.len());
1393 print_ce_error(ce_err);
1397 #endif /* NOT_BACKWARD_COMPATIBLE */
1400 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1401 _tt_ce_attr_string(_TT_MSET_DISPOSITION),
1402 (char *)attr_typename,
1403 (char *)val, val.len());
1405 print_ce_error(ce_err);
1411 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1412 _tt_ce_attr_string(_TT_MSET_DISPOSITION),
1413 (char *)attr_typename,
1414 (char *)val, val.len());
1416 print_ce_error(ce_err);
1423 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1424 _tt_ce_attr_string(_TT_MSET_DISPOSITION),
1425 (char *)attr_typename,
1426 (char *)val, val.len());
1428 print_ce_error(ce_err);
1433 char opnumstring[40];
1434 sprintf(opnumstring,"%d", st->_opnum);
1436 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1437 _tt_ce_attr_string(_TT_MSET_OPNUM),
1438 "string", (char *)val, val.len());
1440 print_ce_error(ce_err);
1445 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1446 _tt_ce_attr_string(_TT_MSET_HANDLER_PTYPE),
1447 "string", (char *)val, val.len());
1449 print_ce_error(ce_err);
1453 if (st->_otid.len()) {
1455 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1456 _tt_ce_attr_string(_TT_MSET_OTYPE),
1457 "string", (char *)val, val.len());
1459 print_ce_error(ce_err);
1469 // This function is passed in as a callback to ce_map_through_attrs by
1470 // _tt_ce_entry_to_ptype. It's function is to process a ptype
1471 // attribute. This involves determining which attribute it is and then
1472 // modifying the _Tt_ptype object (which is passed in as arg by the
1473 // ce_map_through_atts call).
1476 _tt_convert_ptype_attrs(CE_ATTRIBUTE attr, char *value, void *arg)
1481 _Tt_ptype *p = (_Tt_ptype *)arg;
1483 if (attr == _tt_attrs[_TYPE_NAME] ||
1484 attr == _tt_attrs[_TT_TOOLTALK_TYPE]) {
1487 name = (char *)CALLCE(ce_get_attribute_name)(attr);
1489 if (p->getprop(name_s, value_s)) {
1492 // add property to ptype.
1494 p->appendprop(name_s, value_s);
1501 // This function is passed in as a callback to ce_map_through_attrs by
1502 // _tt_ce_entry_to_otype. Its function is to process the given
1503 // attribute and modify the _Tt_otype object appropiately. This object
1504 // is passed in as arg by ce_map_through_attrs. If this callback
1505 // returns anything other than (void *)0, then it causes
1506 // ce_map_through_attrs to return immediately without processing the
1507 // rest of the current entry's attributes. This signals an error to
1508 // _tt_ce_entry_to_otype. The attribute is mapped to the appropiate
1509 // tooltalk attribute by way of the _tt_attrs table (this avoid having
1510 // to do repeated strcmps on the attribute's name).
1513 _tt_convert_otype_attrs(CE_ATTRIBUTE attr, char *value, void *arg)
1515 _Tt_string_list_ptr ancs;
1516 _Tt_string_list_cursor anc_c;
1517 _Tt_otype *o = (_Tt_otype *)arg;
1519 if (attr == _tt_attrs[_TYPE_NAME] ||
1520 attr == _tt_attrs[_TT_TOOLTALK_TYPE]) {
1523 if (attr == _tt_attrs[_TT_PARENT]) {
1524 ancs = o->parents();
1525 if (ancs.is_null()) {
1526 ancs = new _Tt_string_list();
1527 o->set_ancestors(ancs);
1530 while (anc_c.next()) {
1531 if (*anc_c == value) {
1535 ancs->push(_Tt_string(value));
1543 // This function is passed in as a callback to ce_map_through_attrs by
1544 // _tt_ce_entry_to_signature. It's function is to process the
1545 // attribute and modify the _Tt_signature object (passed in as arg by
1546 // ce_map_through_attrs). If this function returns anything other than
1547 // (void *)0 then ce_map_through_attrs will return immediately with
1548 // this value and _tt_ce_entry_to_signature will return an error.
1549 // The attribute is mapped to the appropiate tooltalk attribute by way
1550 // of the _tt_attrs table (this avoid having to do repeated strcmps on
1551 // the attribute's name).
1554 _tt_convert_signature_attrs(CE_ATTRIBUTE attr, char *value, void *arg)
1557 _Tt_signature *s = (_Tt_signature *)arg;
1558 _Tt_arg_list_ptr args;
1560 _Tt_string valstring;
1564 CE_ATTRIBUTE val_id;
1566 if (attr == _tt_attrs[_TYPE_NAME] ||
1567 attr == _tt_attrs[_TT_TOOLTALK_TYPE]) {
1569 } else if (attr == _tt_attrs[_TT_OP]) {
1573 } else if (attr == _tt_attrs[_TT_CLASS]) {
1575 val_id = CALLCE(ce_get_attribute_id)(_ce_type_ns, value);
1576 if (val_id == _tt_attrs[_TT_REQUEST]) {
1577 s->set_message_class(TT_REQUEST);
1578 } else if (val_id == _tt_attrs[_TT_NOTICE]) {
1579 s->set_message_class(TT_NOTICE);
1581 // XXX: assume TT_CLASS_UNDEFINED
1582 s->set_message_class(TT_CLASS_UNDEFINED);
1585 } else if ((attr == _tt_attrs[_TT_SCOPE])
1586 || (attr == _tt_attrs[_TT_MSET_SCOPE])) {
1588 val_id = CALLCE(ce_get_attribute_id)(_ce_type_ns, value);
1589 if (val_id == _tt_attrs[_TT_SESSION]) {
1590 s->set_scope(TT_SESSION);
1591 } else if (val_id == _tt_attrs[_TT_FILE]) {
1592 s->set_scope(TT_FILE);
1593 } else if (val_id == _tt_attrs[_TT_BOTH]) {
1594 s->set_scope(TT_BOTH);
1595 } else if (val_id == _tt_attrs[_TT_FILE_IN_SESSION]) {
1596 s->set_scope(TT_FILE_IN_SESSION);
1601 } else if ((attr == _tt_attrs[_TT_DISPOSITION]) ||
1602 (attr == _tt_attrs[_TT_MSET_DISPOSITION])) {
1604 _Tt_string typename = (char *)CALLCE(ce_get_attribute_type)(
1606 s->ce_entry, attr );
1607 if (typename == "string") {
1608 val_id = CALLCE(ce_get_attribute_id)(_ce_type_ns, value);
1609 if (val_id == _tt_attrs[_TT_DISCARD]) {
1610 s->set_reliability(TT_DISCARD);
1611 } else if (val_id == _tt_attrs[_TT_QUEUE]) {
1612 s->set_reliability(TT_QUEUE);
1613 } else if (val_id == _tt_attrs[_TT_START]) {
1614 s->set_reliability(TT_START);
1616 Tt_disposition disp= TT_DISCARD;
1617 _Tt_string valstring = value;
1618 _Tt_string left, right;
1620 while (valstring.len() > 0) {
1621 right = valstring.split('+', left);
1622 if (left.len() <= 0) {
1623 // XXX change split's behavior
1628 _tt_ce_attr_string(_TT_START)) {
1629 disp = (Tt_disposition)
1632 _tt_ce_attr_string(_TT_QUEUE)) {
1633 disp = (Tt_disposition)
1638 s->set_reliability( disp );
1641 _Tt_string hack = "string:";
1642 hack = hack.cat( _tt_ce_attr_string( _TT_START ))
1644 .cat( _tt_ce_attr_string( _TT_QUEUE ));
1645 if (typename == hack) {
1646 s->set_reliability (TT_START);
1647 s->set_reliability (TT_QUEUE);
1653 } else if (attr == _tt_attrs[_TT_MSET_HANDLER_PTYPE]) {
1657 } else if (attr == _tt_attrs[_TT_MSET_OTYPE]) {
1661 } else if (attr == _tt_attrs[_TT_MSET_OPNUM]) {
1663 s->set_opnum(atoi(value));
1665 } else if (attr == _tt_attrs[_TT_CATEGORY]) {
1667 val_id = CALLCE(ce_get_attribute_id)(_ce_type_ns, value);
1668 if (val_id == _tt_attrs[_TT_OBSERVE]) {
1669 s->set_pattern_category(TT_OBSERVE);
1670 } else if (val_id == _tt_attrs[_TT_HANDLE]) {
1671 s->set_pattern_category(TT_HANDLE);
1678 // none of the above, check for TT_ARG%d which is
1679 // an argument specifier.
1681 name = (char *)CALLCE(ce_get_attribute_name)(attr);
1683 _tt_ce_attr_string(_TT_ARG),
1684 strlen(_tt_ce_attr_string(_TT_ARG)))) {
1685 narg = new _Tt_arg();
1687 valstring = valstring.split(' ',mstring);
1688 nstring = valstring.split(' ',tstring);
1689 val_id = CALLCE(ce_get_attribute_id)(_ce_type_ns,
1691 if (val_id == _tt_attrs[_TT_OUT]) {
1692 narg->set_mode(TT_OUT);
1693 } else if (val_id == _tt_attrs[_TT_IN]) {
1694 narg->set_mode(TT_IN);
1695 } else if (val_id == _tt_attrs[_TT_INOUT]) {
1696 narg->set_mode(TT_INOUT);
1700 narg->set_type(tstring);
1701 narg->set_name(nstring);
1702 s->append_arg(narg);
1704 _tt_syslog(stderr, LOG_ERR,
1705 catgets(_ttcatd, 2, 12,
1706 "Ignoring unknown attribute <%s> "
1707 "of ToolTalk signature..."), name );
1715 // Called by _tt_collect_types_in_cedb to produce a _Tt_ptype object from
1716 // the given Classing Engine entry. Uses the _tt_convert_ptype_attrs
1717 // function as a callback to ce_map_through_attrs to do the real work.
1720 _tt_ce_entry_to_ptype(_Tt_ptype *p, CE_ENTRY ne)
1722 p->ce_entry = (void *)ne;
1723 return(0==CALLCE(ce_map_through_attrs)(_ce_type_ns, ne,
1724 _tt_convert_ptype_attrs, p));
1729 // Called by _tt_collect_types_in_cedb to produce a _Tt_otype object from
1730 // the given Classing Engine entry. Uses the _tt_convert_otype_attrs
1731 // function as a callback to ce_map_through_attrs to do the real work.
1734 _tt_ce_entry_to_otype(_Tt_otype *o, CE_ENTRY ne)
1736 o->ce_entry = (void *)ne;
1737 return(0==CALLCE(ce_map_through_attrs)(_ce_type_ns, ne,
1738 _tt_convert_otype_attrs, o));
1743 // Called by _tt_collect_types_in_cedb to produce a _Tt_signature object from
1744 // the given Classing Engine entry. Uses the _tt_convert_signature_attrs
1745 // function as a callback to ce_map_through_attrs to do the real work.
1748 _tt_ce_entry_to_signature(_Tt_signature *s, CE_ENTRY ne)
1750 s->ce_entry = (void *)ne;
1751 return(0==CALLCE(ce_map_through_attrs)(_ce_type_ns, ne,
1752 _tt_convert_signature_attrs,
1758 // This function is a callback passed in to ce_map_though_entries. It
1759 // is applied to each entry in the ToolTalk namespace in a Classing
1760 // Engine database. Each entry specifies either a ptype, otype or
1761 // signature. For each class of entry the appropiate _tt_ce_entry_to_*
1762 // function is invoked.
1765 _tt_collect_types_in_cedb(CE_NAMESPACE ns, CE_ENTRY ne, void *t)
1769 _Tt_signature_ptr s;
1770 _Tt_typedb *tdb = (_Tt_typedb *)t;
1772 CE_ATTRIBUTE type_id;
1775 int insert_required = 0;
1777 // XXX: should use ce_get_attribute_type when it's implemented
1779 // type = CALLCE(ce_get_attribute_type)(ne, _TT_TYPE_NAME);
1781 if (tdb->ceDB2Use != TypedbAll) {
1783 // We have been restricted to a single CE database.
1784 // Ignore this entry if it is not from the right database.
1785 // XXX CE should have had a better way to do this, such
1786 // as a parameter to ce_begin().
1788 char *db_name, *db_path;
1789 int ceStatus = (int)CALLCE(ce_get_entry_db_info)(
1790 ns, ne, &db_name, &db_path );
1791 if (ceStatus != 0) {
1794 if (_Tt_typedb::level( db_name ) != tdb->ceDB2Use) {
1799 type = (char *)CALLCE(ce_get_attribute)(ns, ne, _tt_attrs[_TT_TOOLTALK_TYPE]);
1800 if (type == (char *)0) {
1803 type_id = CALLCE(ce_get_attribute_id)(_ce_type_ns, type);
1804 if (type_id == _tt_attrs[_TT_TOOLTALK_PTYPE]) {
1808 ptid = (char *)CALLCE(ce_get_attribute)(ns, ne,
1809 _tt_attrs[_TYPE_NAME]);
1810 if (tdb->ptable.is_null()) {
1811 tdb->ptable = new _Tt_ptype_table(_tt_ptype_ptid);
1813 if (! tdb->ptable->lookup(ptid,p)) {
1814 p = new _Tt_ptype();
1816 insert_required = 1;
1818 if (!_tt_ce_entry_to_ptype(p.c_pointer(), ne)) {
1821 if (insert_required) {
1822 tdb->ptable->insert(p);
1826 } else if (type_id == _tt_attrs[_TT_TOOLTALK_OTYPE]) {
1830 otid = (char *)CALLCE(ce_get_attribute)(ns, ne,
1831 _tt_attrs[_TYPE_NAME]);
1832 if (tdb->otable.is_null()) {
1833 tdb->otable = new _Tt_otype_table(_tt_otype_otid);
1835 if (! tdb->otable->lookup(otid,o)) {
1836 o = new _Tt_otype(otid);
1837 insert_required = 1;
1839 if (!_tt_ce_entry_to_otype(o.c_pointer(), ne)) {
1842 if (insert_required) {
1843 tdb->otable->insert(o);
1845 } else if (type_id == _tt_attrs[_TT_TOOLTALK_SIGNATURE]) {
1849 _Tt_signature_list_ptr sp;
1851 s = new _Tt_signature();
1852 if (! _tt_ce_entry_to_signature(s.c_pointer(), ne)) {
1853 // failed to decode signature
1856 // first insert the signature into the relevant
1858 if (! tdb->ptable->lookup(s->ptid(),p)) {
1859 p = new _Tt_ptype();
1860 p->set_ptid(s->ptid());
1861 tdb->ptable->insert(p);
1863 switch (s->category()) {
1868 case TT_HANDLE_PUSH:
1869 case TT_HANDLE_ROTATE:
1870 p->append_hsig(s, s->category());
1873 if (s->otid().len() > 0) {
1875 if (tdb->otable.is_null()) {
1876 tdb->otable = new _Tt_otype_table(_tt_otype_otid);
1878 if (! tdb->otable->lookup(s->otid(),o)) {
1879 o = new _Tt_otype(s->otid());
1880 tdb->otable->insert(o);
1882 switch (s->category()) {
1887 case TT_HANDLE_PUSH:
1888 case TT_HANDLE_ROTATE:
1889 o->append_hsig(s, s->category());
1891 default: // inherited
1900 #endif // OPT_CLASSING_ENGINE
1904 Tt_status _Tt_typedb::
1906 #if defined(OPT_CLASSING_ENGINE)
1914 #ifndef OPT_CLASSING_ENGINE
1915 _tt_syslog(stderr, LOG_ERR, "_Tt_typedb::init_ce()!");
1916 return(TT_ERR_INTERNAL);
1922 #ifdef OPT_DLOPEN_CE
1923 int load_celib_environment();
1925 if (! load_celib_environment()) {
1926 _tt_syslog(stderr, LOG_ERR,
1927 "dlopen( \"libce.so\", 1 ): %s", dlerror());
1928 return(TT_ERR_INTERNAL);
1930 #endif // OPT_DLOPEN_CE
1933 if ((ce_err = (int)CALLCE(ce_begin)(0)) != 0) {
1934 print_ce_error(ce_err);
1935 return(TT_ERR_INTERNAL);
1937 _ce_type_ns = CALLCE(ce_get_namespace_id)(TT_NS_NAME);
1938 if (_ce_type_ns == (CE_NAMESPACE)0) {
1939 return(TT_ERR_DBEXIST);
1941 // Initialize the ce attributes relevant to ToolTalk types
1942 for (i = 0; i < _TT_CE_ATTR_LAST; i++) {
1943 c = CALLCE(ce_get_attribute_id)(_ce_type_ns,
1944 _tt_ce_attr_string((_Tt_ce_attr)i));
1945 // if c==0 then we can continue reading the database
1946 // since it just means we've encountered an attribute
1947 // not present in any of the namespace entries.
1950 if (0 != CALLCE(ce_map_through_entries)(_ce_type_ns,
1951 _tt_collect_types_in_cedb,
1953 return(TT_ERR_INTERNAL);
1956 #endif // !OPT_CLASSING_ENGINE
1960 Tt_status _Tt_typedb::
1963 struct stat xdrStat, ceStat;
1970 home = getenv( "HOME" );
1971 xdrdb = home.cat( "/.tt/types.xdr" );
1972 status = stat( (char *)xdrdb, &xdrStat );
1975 } else if (errno != ENOENT) {
1976 _tt_syslog( 0, LOG_ERR, "$HOME/.tt/types.xdr: %m" );
1979 cedb = home.cat( "/.cetables/cetables" );
1980 status = stat( (char *)cedb, &ceStat );
1982 if (errno == ENOENT) {
1983 // No cetables to convert
1986 _tt_syslog( 0, LOG_ERR,
1987 "$HOME/.cetables/cetables: %m" );
1992 if (ceStat.st_mtime <= xdrStat.st_mtime) {
1993 // XDR database is newer
1997 status = system( "ttce2xdr -d user &" );
1998 if (WIFEXITED(status)) {
1999 if (WEXITSTATUS(status) == 0) {
2002 _tt_syslog(stderr, LOG_ERR,
2003 catgets(_ttcatd, 2, 13,
2004 "ttce2xdr failed (status=%d); types"
2005 " in Classing Engine \"user\" "
2006 "database not converted..."),
2007 WEXITSTATUS(status) );
2008 return TT_ERR_PTYPE_START;
2011 _tt_syslog(stderr, LOG_ERR, "system(\"ttce2xdr -d user\"): %d",
2013 return TT_ERR_PTYPE_START;
2017 _Tt_typedbLevel _Tt_typedb::
2018 level( const _Tt_string &dbname )
2020 if (dbname == "user") {
2022 } else if (dbname == "system") {
2023 return TypedbSystem;
2024 } else if (dbname == "network") {
2025 return TypedbNetwork;
2031 const char * _Tt_typedb::
2032 level_name( _Tt_typedbLevel db )
2048 xdr_version_required() const
2050 int version = TT_TYPESDB_DEFAULT_XDR_VERSION;
2051 _Tt_ptype_table_cursor ptypes(ptable);
2052 while (ptypes.next()) {
2053 version = max(version, ptypes->xdr_version_required());
2055 _Tt_otype_table_cursor otypes(otable);
2056 while (otypes.next()) {
2057 version = max(version, otypes->xdr_version_required());
2064 write_out_tt_attrs(const _Tt_ostream &os)
2068 FILE *fs = os.theFILE();
2069 for (i=0; i < _TT_CE_ATTR_LAST; i++) {
2070 fprintf(fs,"\t\t(%s,string,<attr>)\n",
2071 _tt_ce_attr_string((_Tt_ce_attr)i));
2078 pretty_print(const _Tt_ostream &os) const
2080 _Tt_ptype_table_cursor ptypes(ptable);
2081 while (ptypes.next()) {
2082 ptypes->pretty_print(os);
2085 _Tt_otype_table_cursor otypes(otable);
2086 while (otypes.next()) {
2087 otypes->pretty_print(os);
2095 print(const _Tt_ostream &os) const
2097 if (write_ce_header(os)) {
2098 os << "\nNS_ENTRIES= (\n\t(\t";
2099 write_out_tt_attrs(os);
2100 ptable->print(_tt_ptype_print, os);
2101 otable->print(_tt_otype_print, os);
2108 write_ce_header(const _Tt_ostream &os) const
2110 os << "{\nNS_NAME=" << TT_NS_NAME
2111 << "\nNS_ATTR=(\n\t\t(NS_MANAGER,string,"
2112 "<$CEPATH/tns_mgr.so>)\n\t)";
2118 #if defined(OPT_DLOPEN_CE) && defined(OPT_CLASSING_ENGINE)
2120 /**************************************************************************
2121 * This section contains functions for dynamically loading in the
2122 * necessary ce functions. This avoids the need for applications to link
2123 * in libce. Note that all of this section is ifdefd with OPT_DLOPEN_CE so
2124 * only functions relevant to dynamic loading of ce should be included.
2125 **************************************************************************/
2130 load_celib_environment()
2132 int load_celib_fns_from_handle(void *);
2136 // first try opening the current executable to see if the
2137 // functions have already been defined
2138 dlhandle = dlopen((char *)0, 1);
2139 if (load_celib_fns_from_handle(dlhandle)) {
2143 #if defined(OPT_BUG_SUNOS_4)
2144 // Not strictly a bug, but SunOS 4.x doesn't do what we want.
2145 if (! tt_ldpath("libce.so", path)) {
2149 // SVR4 version of dlopen does the path searching for us
2154 #if defined(OPT_BUG_SUNOS_4)
2155 // SunOS 4 knows nothing of RTLD options
2156 dlhandle = dlopen((char *)path, 1);
2158 // XXX: In theory, RTLD_LAZY (the default) is the preferred way of
2159 // using dlopen. However, there were some bugs in early 5.0 versions
2160 // that made dlopen slow down considerably if RTLD_LAZY is used.
2161 // For now, we'll use RTLD_NOW which seems to get rid of the
2162 // behavior but perhaps not the cause.
2163 // Next time we do performance tuning we should retry with
2165 dlhandle = dlopen((char *)path, RTLD_NOW);
2167 if (dlhandle == (void *)0) {
2171 return(load_celib_fns_from_handle(dlhandle));
2176 * XXX: This is sort of ugly. dlopen doesn't make the symbol available
2177 * for normal dynamic linking. This means that if the library that is
2178 * dlopened itself uses some of the symbols that are made available by
2179 * the use of dlsym then the library needs to be linked in with the
2180 * executable. We circumvent this by defining those symbols directly
2181 * here. This is unfortunately sensitive to the implementation of libce
2182 * changing. Ie. if it is changed to use more symbols than
2183 * ce_get_attribute_id and ce_get_attribute then libce will have to be
2184 * linked in regardless of whether it is dlopened or not.
2186 * All of a sudden we're getting infinite loops here, under ce_begin().
2187 * So I'm commenting these two puppies out. Brian 8/05/92
2190 ce_get_attribute_id(CE_NAMESPACE ns, char *a)
2192 return((CE_ATTRIBUTE)CALLCE(ce_get_attribute_id)(ns,a));
2196 ce_get_attribute(CE_NAMESPACE ns, CE_ENTRY e, CE_ATTRIBUTE a)
2198 return((char *)CALLCE(ce_get_attribute)(ns,e,a));
2204 load_celib_fns_from_handle(void *dlhandle)
2206 #if defined(__STDC__)
2207 #define DLINK_FN(fn)\
2208 _tt_celib . fn = (_Tt_cefn_ptr)dlsym(dlhandle, #fn); \
2209 if (_tt_celib . fn == (_Tt_cefn_ptr)0) { \
2213 #define DLINK_FN(fn)\
2214 _tt_celib . fn = (_Tt_cefn_ptr)dlsym(dlhandle, "fn"); \
2215 if (_tt_celib . fn == (_Tt_cefn_ptr)0) { \
2218 #endif /* __STDC__ */
2220 DLINK_FN(ce_abort_write)
2221 DLINK_FN(ce_add_attribute)
2222 DLINK_FN(ce_add_entry)
2223 DLINK_FN(ce_add_namespace)
2224 DLINK_FN(ce_alloc_entry)
2225 DLINK_FN(ce_alloc_ns_entry)
2226 DLINK_FN(ce_get_attribute_id)
2228 DLINK_FN(ce_commit_write)
2229 DLINK_FN(ce_get_attribute)
2230 DLINK_FN(ce_get_attribute_name)
2231 DLINK_FN(ce_get_attribute_type)
2232 DLINK_FN(ce_get_entry_db_info)
2233 DLINK_FN(ce_get_namespace_id)
2234 DLINK_FN(ce_map_through_attrs)
2235 DLINK_FN(ce_map_through_entries)
2236 DLINK_FN(ce_remove_entry)
2237 DLINK_FN(ce_start_write)
2242 #endif // OPT_DLOPEN_CE && OPT_CLASSING_ENGINE