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 libraries 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
42 #if defined(__linux__) || defined(CSRG_BASED)
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 enum _Tt_typedb_flags {
85 #ifdef OPT_CLASSING_ENGINE
87 # include <util/tt_ldpath.h>
90 typedef void *(*_Tt_cefn_ptr)(...);
91 // Function-table for all Classing Engine functions used. Note
92 // that it is important that the function slots be named the
93 // same as the corresponding Classing Engine function. This is
94 // so the CALLCE macro works properly.
97 _Tt_cefn_ptr ce_abort_write;
98 _Tt_cefn_ptr ce_add_attribute;
99 _Tt_cefn_ptr ce_add_entry;
100 _Tt_cefn_ptr ce_add_namespace;
101 _Tt_cefn_ptr ce_alloc_entry;
102 _Tt_cefn_ptr ce_alloc_ns_entry;
103 _Tt_cefn_ptr ce_begin;
104 _Tt_cefn_ptr ce_commit_write;
105 _Tt_cefn_ptr ce_get_attribute;
106 _Tt_cefn_ptr ce_get_attribute_id;
107 _Tt_cefn_ptr ce_get_attribute_name;
108 _Tt_cefn_ptr ce_get_attribute_type;
109 _Tt_cefn_ptr ce_get_entry_db_info;
110 _Tt_cefn_ptr ce_get_namespace_id;
111 _Tt_cefn_ptr ce_map_through_attrs;
112 _Tt_cefn_ptr ce_map_through_entries;
113 _Tt_cefn_ptr ce_remove_entry;
114 _Tt_cefn_ptr ce_start_write;
117 // define CALLCE such that it indirects through a function
118 // slot in _tt_celib which will be filled in by dlsyming
119 // entry points from a dynamically loaded libce.so
121 # define CALLCE(fn) (*_tt_celib . fn)
123 // assume libce.so is linked in so CALLCE just becomes a
125 # define CALLCE(fn) fn
126 # endif // OPT_DLOPEN_CE
128 * Handle to the Type namespace
130 static CE_NAMESPACE _ce_type_ns = (CE_NAMESPACE)0;
132 * Set of CE attributes used to avoid having to do string comparisons for
133 * string fields in the CE databases. Each CE namespace assigns unique
134 * numeric ids to all attribute names in order to provide a cheap way for
135 * clients to compare against attribute names.
137 static CE_ATTRIBUTE _tt_attrs[_TT_CE_ATTR_LAST];
138 static CE_NAMESPACE _ce_write_ns = (CE_NAMESPACE)0;
139 #endif // OPT_CLASSING_ENGINE
142 #ifdef OPT_CLASSING_ENGINE
144 _Tt_typedb(char *ce_dir)
149 _Tt_typedb(char * /* ce_dir */)
153 ptable = new _Tt_ptype_table(_tt_ptype_ptid);
154 otable = new _Tt_otype_table(_tt_otype_otid);
155 ceDB2Use = TypedbAll;
166 // XDR's a _Tt_typedb object.
170 if (!ptable.xdr(xdrs)) {
174 if (!otable.xdr(xdrs)) {
178 if (xdrs->x_op == XDR_DECODE) {
180 // We have to be sure that a null ptable or otable are
181 // NEVER passed into the _Tt_object_table::xdr. XXX.
183 if (ptable.is_null()) {
184 ptable = new _Tt_ptype_table(_tt_ptype_ptid);
186 if (otable.is_null()) {
187 otable = new _Tt_otype_table(_tt_otype_otid);
197 // This function returns the full pathnames to the user database, system
198 // database, and network databases in udb, sdb, and ndb respectively.
199 // This three-level model of databases is intended to be similar to the
200 // Classing Engine model. The intent is that types in the user database
201 // shadow types in the system and network databases and that the types in
202 // the system database shadow the types in the network database. In order
203 // to provide some user-configurability, we provide an
204 // environment variable TTPATH that is a three-path list separated by ":"
205 // pointing to the user,system, and network databases. This function
206 // looks at that variable and returns the paths.
208 // If TTPATH isn't set this function should returns
209 // $HOME/.tt/types.xdr for the user database, /etc/tt/types.xdr for the
210 // system database, and $OPENWINHOME/etc/tt/types.xdr for the network
214 _tt_map_xdr_dbpaths(_Tt_string &udb, _Tt_string &sdb, _Tt_string &ndb)
216 _Tt_string_list_ptr path = _Tt_typedb::tt_path();
217 if (path.is_null()) return 1;
218 _Tt_string_list_cursor pathC( path );
219 if (! pathC.next()) {
223 if (! pathC.next()) {
227 if (! pathC.next()) {
235 _Tt_typedb::tt_path()
237 _Tt_string_list *pathlist = new _Tt_string_list;
238 if (pathlist == 0) return 0;
239 _Tt_string path = getenv("TTPATH");
240 if (path.len() <= 0) {
241 _Tt_string home = getenv("HOME");
242 pathlist->append(home.cat("/.tt/types.xdr"));
243 pathlist->append(_Tt_string("/etc/tt/types.xdr"));
245 _Tt_string("/usr/dt/appconfig/tttypes/types.xdr"));
246 home = getenv("OPENWINHOME");
247 if (home.len() == 0) {
248 home = "/usr/openwin";
250 pathlist->append(home.cat(_Tt_string("/etc/tt/types.xdr")));
252 // parse the user:system:network from path variable
258 pathname = path.left(n);
259 if (pathname.len() == 0) break;
260 path = path.right(path.len() - n - 1);
265 if (_tt_isdir(pathname)) {
266 pathname = pathname.cat("/types.xdr");
268 pathlist->append( pathname );
275 Tt_status _Tt_typedb::
276 init_xdr(const _Tt_string &compiled_file)
279 // A temporary is needed because
280 // a types file is an XDRed _Tt_typedb_ptr, (XXX)
281 // instead of an XDRed _Tt_typedb, and
282 // _Tt_typedb_ptr::xdr() creates a new _Tt_typedb.
283 // This was a bad choice, but we are stuck with it.
285 _Tt_typedb_ptr tmpdb;
288 // Need to remember what kind of _Tt_typedb we are,
289 // in case we are asked to remove or merge types.
291 _flags |= (1<<_TT_TYPEDB_XDR_MODE);
293 status = merge_from(compiled_file, tmpdb);
294 if (status != TT_OK) {
298 // Now snare a reference to the tables of the temp db.
299 // The temp db goes away, but we keep its tables.
301 if (!tmpdb.is_null()) {
302 ptable = tmpdb->ptable;
303 otable = tmpdb->otable;
308 Tt_status _Tt_typedb::
311 _Tt_typedb_ptr tmpdb;
315 _flags |= (1<<_TT_TYPEDB_XDR_MODE);
317 status = merge_from(f, tmpdb, version);
318 if (status != TT_OK) {
322 if (!tmpdb.is_null()) {
323 ptable = tmpdb->ptable;
324 otable = tmpdb->otable;
330 // Initializes this object from the given xdr database.
332 // TT_ERR_PATH Bad $TTPATH
333 // TT_ERR_NO_MATCH version mismatch
334 // TT_ERR_DBCONSIST XDR failure, corrupt database
336 Tt_status _Tt_typedb::
337 init_xdr(_Tt_typedbLevel xdb)
339 _Tt_typedb_ptr tmpdb;
342 if (! _tt_map_xdr_dbpaths(user_db, system_db, network_db)) {
343 _tt_syslog(stderr, LOG_ERR, "$TTPATH: %s", strerror(EINVAL));
347 _flags |= (1<<_TT_TYPEDB_XDR_MODE);
349 // type files are read in in reverse order of TTPATH
350 // variable so that entries in databases to the left
351 // of others in TTPATH shadow those to the right.
353 _Tt_string_list_ptr path;
358 if (path.is_null()) {
359 status = TT_ERR_NOMEM;
361 _Tt_string_list_cursor pathC( path );
363 while (pathC.prev() && (status == TT_OK)) {
364 status = merge_from(*pathC, tmpdb);
366 if (status == TT_OK) {
367 _flags |= (1<<_TT_TYPEDB_NETWORK);
368 _flags |= (1<<_TT_TYPEDB_SYSTEM);
369 _flags |= (1<<_TT_TYPEDB_USER);
374 if (network_db.len()) {
375 status = merge_from(network_db, tmpdb);
376 if (status == TT_OK) {
377 _flags |= (1<<_TT_TYPEDB_NETWORK);
380 _tt_syslog(stderr, LOG_ERR, "!network_db.len()");
381 status = TT_ERR_INTERNAL;
385 if (system_db.len()) {
386 status = merge_from(system_db, tmpdb);
387 if (status == TT_OK) {
388 _flags |= (1<<_TT_TYPEDB_SYSTEM);
391 _tt_syslog(stderr, LOG_ERR, "!system_db.len()");
392 status = TT_ERR_INTERNAL;
397 status = merge_from(user_db, tmpdb);
398 if (status == TT_OK) {
399 _flags |= (1<<_TT_TYPEDB_USER);
401 } else if (xdb != TypedbAll) {
402 _tt_syslog(stderr, LOG_ERR, "!user_db.len()");
403 status = TT_ERR_INTERNAL;
407 if (status != TT_OK) {
410 if (!tmpdb.is_null()) {
411 ptable = tmpdb->ptable;
412 otable = tmpdb->otable;
419 // Merges (or reads) types from dbpath into a (new) _Tt_typedb in tdb
421 Tt_status _Tt_typedb::
422 merge_from(const _Tt_string &dbpath, _Tt_typedb_ptr &tdb)
428 // The automatic converter (ttce2xdr) will just touch the
429 // user\'s .tt/types.xdr if there were no ToolTalk types in the
430 // classing engine db. This means that a zero-length file
431 // is perfectly OK, it just contains no types.
433 struct stat stat_buf;
434 if (stat( (char *)dbpath, &stat_buf ) == 0) {
435 if (stat_buf.st_size == 0) {
440 if (f = fopen((char *)dbpath, "r")) {
441 fcntl(fileno(f), F_SETFD, 1); /* close on exec */
442 result = merge_from(f, tdb, version);
445 // It is OK for the database not to exist, ToolTalk runs
446 // even if there are no types.
450 if (result == TT_ERR_NO_MATCH) {
451 // This file is newer than we are, so we cannot
453 _tt_syslog(stderr, LOG_ERR,
454 catgets(_ttcatd, 2, 9,
455 "%s is a version %d types "
456 "database, and this version "
457 "can only read versions %d and earlier"),
458 (char *)dbpath, version,
459 TT_PUSH_ROTATE_XDR_VERSION);
460 } else if (result == TT_ERR_DBCONSIST) {
461 _tt_syslog(stderr, LOG_ERR,
462 catgets(_ttcatd, 2, 10,
463 "could not decode types from types "
464 "database: %s. It may be damaged."),
473 // Merges (or reads) types from f into a (new) _Tt_typedb in tdb
475 Tt_status _Tt_typedb::
476 merge_from(FILE *f, _Tt_typedb_ptr &tdb, int &version)
480 xdrstdio_create(&xdrs, f, XDR_DECODE);
481 return merge_from(&xdrs, tdb, version);
485 // Merges (or reads) types from xdrs into a (new) _Tt_typedb in tdb
487 // Picks the version off the xdr xstream and then invokes the
488 // xdr method on the given _Tt_typedb object to merge in the types.
489 // Used both by merge_from above to read in files and to handle
490 // the types sent over from clients via tt_session_types_load().
492 Tt_status _Tt_typedb::
493 merge_from(XDR *xdrs, _Tt_typedb_ptr &tdb, int &version)
496 if (! xdr_int(xdrs, &version)) {
497 return TT_ERR_DBCONSIST;
499 if (version > TT_PUSH_ROTATE_XDR_VERSION) {
500 // This file is newer than we are, so we cannot
502 return TT_ERR_NO_MATCH;
505 _Tt_xdr_version xvers(version);
507 if (! tdb.xdr(xdrs)) {
508 return TT_ERR_DBCONSIST;
513 #ifdef OPT_CLASSING_ENGINE
516 // Function that prints out the given Classing Engine error code to
520 print_ce_error(int ce_err)
522 _tt_syslog(stderr, LOG_ERR, "Classing Engine: %d (%s)",
523 ce_err, _tt_enumname( (_Tt_ce_status)ce_err ));
525 #endif // OPT_CLASSING_ENGINE
529 // Aborts a write transaction to a databse. If this is a write to an xdr
530 // database then the lock file is removed. Otherwise it is a Classing
531 // Engine database and the appropiate abort function is invoked.
536 #ifdef OPT_CLASSING_ENGINE
537 if (_flags&(1<<_TT_TYPEDB_XDR_MODE)) {
540 (void)unlink((char *)_lock_file);
543 #ifdef OPT_CLASSING_ENGINE
547 ce_err = (int)CALLCE(ce_abort_write)(0);
551 #endif // !OPT_CLASSING_ENGINE
556 // Removes an otype with id otid from the database either in xdr format
557 // or in Classing Engine format. If the database is in xdr format then
558 // this method just removes the otype from the in-memory otype table
559 // since it is assumed that a subsequent _Tt_typedb::end_write will cause
560 // the in-memory otype table to supersede the one on disk. If the
561 // database is a Classing Engine database then we remove it using the
562 // appropiate Classing Engine routines.
565 remove_otype(_Tt_string otid)
568 if (! otable->lookup(otid,ot)) {
572 #ifdef OPT_CLASSING_ENGINE
573 char *db_name, *db_path;
575 if (! (_flags&(1<<_TT_TYPEDB_XDR_MODE))) {
577 _Tt_signature_list_cursor sigs;
579 // remove the otype entry from the ce database
580 // XXX: shouldn't this be done only if this entry was
581 // in the database we have open for write?? (see how
582 // this is done below in removing signatures)
583 ce_err = (int)CALLCE(ce_remove_entry)(_ce_type_ns,
584 (CE_ENTRY)ot->ce_entry);
586 // remove all the observer signatures (which are
587 // separate entries) from the ce databse.
588 sigs.reset(ot->_osigs);
589 while (ce_err == 0 && sigs.next()) {
590 // get the db info for this ce entry.
591 ce_err = (int)CALLCE(ce_get_entry_db_info)(_ce_type_ns,
592 (CE_ENTRY)sigs->ce_entry,
594 if (ce_err==0 && _ce_dir==db_name) {
595 // if this entry was in the ce
596 // database we have open for write
598 ce_err = (int)CALLCE(ce_remove_entry)(_ce_type_ns,
599 (CE_ENTRY)sigs->ce_entry);
603 // remove all the handler signatures (which are
604 // separate entries) from the ce databse.
605 sigs.reset(ot->_hsigs);
606 while (ce_err == 0 && sigs.next()) {
607 // get the db info for this ce entry.
608 ce_err = (int)CALLCE(ce_get_entry_db_info)(_ce_type_ns,
609 (CE_ENTRY)sigs->ce_entry,
611 if (ce_err==0 && _ce_dir==db_name) {
612 // if this entry was in the ce
613 // database we have open for write
615 ce_err = (int)CALLCE(ce_remove_entry)(_ce_type_ns,
616 (CE_ENTRY)sigs->ce_entry);
620 print_ce_error(ce_err);
624 #endif // OPT_CLASSING_ENGINE
626 otable->remove(otid);
633 // Removes an ptype with id ptid from the database either in xdr format
634 // or in Classing Engine format. If the database is in xdr format then
635 // this method just removes the ptype from the in-memory ptype table
636 // since it is assumed that a subsequent _Tt_typedb::end_write will cause
637 // the in-memory ptype table to supersede the one on disk. If the
638 // database is a Classing Engine database then we remove it using the
639 // appropiate Classing Engine routines.
642 remove_ptype(_Tt_string ptid)
645 if (! ptable->lookup(ptid,pt)) {
649 #ifdef OPT_CLASSING_ENGINE
650 char *db_name, *db_path;
652 if (! (_flags&(1<<_TT_TYPEDB_XDR_MODE))) {
654 _Tt_signature_list_cursor sigs;
656 // remove the ptype entry from the database
657 // XXX: shouldn't this be done only if this entry was
658 // in the database we have open for write?? (see how
659 // this is done below in removing signatures)
660 ce_err = (int)CALLCE(ce_remove_entry)(_ce_type_ns,
661 (CE_ENTRY)pt->ce_entry);
663 // remove the ptype's observer signatures from the
665 sigs.reset(pt->_osigs);
666 while (ce_err==0 && sigs.next()) {
667 // get the db info for this ce entry.
668 ce_err = (int)CALLCE(ce_get_entry_db_info)(_ce_type_ns,
669 (CE_ENTRY)sigs->ce_entry,
671 if (ce_err==0 && _ce_dir==db_name) {
672 // if this entry was in the ce
673 // database we have open for write
675 ce_err = (int)CALLCE(ce_remove_entry)(_ce_type_ns,
676 (CE_ENTRY)sigs->ce_entry);
680 // remove the ptype's handler signatures from the database.
681 sigs.reset(pt->_hsigs);
682 while (ce_err==0 && sigs.next()) {
683 // get the db info for this ce entry.
684 ce_err = (int)CALLCE(ce_get_entry_db_info)(_ce_type_ns,
685 (CE_ENTRY)sigs->ce_entry,
687 if (ce_err==0 && _ce_dir==db_name) {
688 // if this entry was in the ce
689 // database we have open for write
691 ce_err = (int)CALLCE(ce_remove_entry)(_ce_type_ns,
692 (CE_ENTRY)sigs->ce_entry);
696 print_ce_error(ce_err);
700 #endif // OPT_CLASSING_ENGINE
702 ptable->remove(ptid);
708 // Inserts a new ptype into the ptype table for this type database. If
709 // this database is stored in xdr format then this method just inserts
710 // the object into the in-memory table since it assumes a subsequent
711 // invocation of _Tt_typedb::end_write will write out the new table to
712 // disk. In Classing Engine format we create a Classing Engine entry and
713 // then use the appropiate ce functions to insert it into the database.
716 insert(_Tt_ptype_ptr &pt)
722 #ifndef OPT_CLASSING_ENGINE
725 if (_flags&(1<<_TT_TYPEDB_XDR_MODE)) {
730 _Tt_signature_list_cursor sigs;
732 pt->ce_entry = make_ce_entry(pt);
733 ce_err = (int)CALLCE(ce_add_entry)(_ce_write_ns, pt->ce_entry);
735 // insert all observer signatures as separate classing engine
737 sigs.reset(pt->_osigs);
738 while (ce_err==0 && sigs.next()) {
739 if (sigs->otid().len()) {
742 sigs->ce_entry = (void *)make_ce_entry(*sigs);
743 if (sigs->ce_entry == (void *)0) {
746 ce_err = (int)CALLCE(ce_add_entry)(_ce_write_ns,
747 (CE_ENTRY)sigs->ce_entry);
750 // insert all handler signatures as separate classing engine
752 sigs.reset(pt->_hsigs);
753 while (ce_err==0 && sigs.next()) {
754 if (sigs->otid().len()) {
757 sigs->ce_entry = (void *)make_ce_entry(*sigs);
758 if (sigs->ce_entry == (void *)0) {
761 ce_err = (int)CALLCE(ce_add_entry)(_ce_write_ns,
762 (CE_ENTRY)sigs->ce_entry);
765 print_ce_error(ce_err);
770 #endif // !OPT_CLASSING_ENGINE
776 // Inserts a new otype into the ptype table for this type database. If
777 // this database is stored in xdr format then this method just inserts
778 // the object into the in-memory table since it assumes a subsequent
779 // invocation of _Tt_typedb::end_write will write out the new table to
780 // disk. In Classing Engine format we create a Classing Engine entry and
781 // then use the appropiate ce functions to insert it into the database.
784 insert(_Tt_otype_ptr &ot)
789 #ifndef OPT_CLASSING_ENGINE
792 if (_flags&(1<<_TT_TYPEDB_XDR_MODE)) {
797 _Tt_signature_list_cursor sigs;
799 ot->ce_entry = make_ce_entry(ot);
800 if (ot->ce_entry == (void *)0) {
803 ce_err = (int)CALLCE(ce_add_entry)(_ce_write_ns, ot->ce_entry);
805 // insert all the otype's observer signatures as separate
807 sigs.reset(ot->_osigs);
808 while (ce_err==0 && sigs.next()) {
809 sigs->ce_entry = (void *)make_ce_entry(*sigs);
810 if (sigs->ce_entry == (void *)0) {
813 ce_err = (int)CALLCE(ce_add_entry)(_ce_write_ns,
814 (CE_ENTRY)sigs->ce_entry);
817 // insert all the otype's handler signatures as separate
819 sigs.reset(ot->_hsigs);
820 while (ce_err==0 && sigs.next()) {
821 sigs->ce_entry = (void *)make_ce_entry(*sigs);
822 if (sigs->ce_entry == (void *)0) {
825 ce_err = (int)CALLCE(ce_add_entry)(_ce_write_ns,
826 (CE_ENTRY)sigs->ce_entry);
829 print_ce_error(ce_err);
834 #endif // !OPT_CLASSING_ENGINE
839 // Prepares the database to be written out to disk. In Classing Engine
840 // mode this means we have to add the ToolTalk namespace to the database
841 // if it doesn't exist and invoke the appropiate Classing Engine function
842 // to start the write transaction. In xdr mode, we have to acquire the
843 // lock file to write out the database.
846 #ifdef OPT_CLASSING_ENGINE
847 begin_write(_Tt_typedbLevel db)
849 begin_write(_Tt_typedbLevel /* db */)
852 #ifdef OPT_CLASSING_ENGINE
853 if (! (_flags&(1<<_TT_TYPEDB_XDR_MODE))) {
858 int namespace_created = 0;
860 ce_err = (int)CALLCE(ce_start_write)(level_name(db));
862 print_ce_error(ce_err);
865 ce_err = (int)CALLCE(ce_add_namespace)(TT_NS_NAME, &_ce_write_ns);
868 // namespace not already there add it
869 ce_err = (int)CALLCE(ce_alloc_ns_entry)(_ce_write_ns, &cn);
871 print_ce_error(ce_err);
874 val = "$CEPATH/tns_mgr.so";
875 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
879 for (i=0; ce_err == 0 && i < _TT_CE_ATTR_LAST; i++) {
880 ce_err = (int)CALLCE(ce_alloc_entry)(_ce_write_ns,
885 val = "$CEPATH/tns_mgr.so";
886 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns,
888 _tt_ce_attr_string((_Tt_ce_attr)i), "string", "attr", strlen("attr"));
891 print_ce_error(ce_err);
894 namespace_created = 1;
895 // fall into next case
896 case CE_ERR_NAMESPACE_EXISTS:
897 if (!namespace_created) {
898 _ce_write_ns = _ce_type_ns;
900 _ce_dir = level_name(db);
903 print_ce_error(ce_err);
909 #endif // OPT_CLASSING_ENGINE
916 // acquire a write lock
917 if (_flags&(1<<_TT_TYPEDB_USER)) {
919 } else if (_flags&(1<<_TT_TYPEDB_SYSTEM)) {
921 } else if (_flags&(1<<_TT_TYPEDB_NETWORK)) {
925 n = path.rindex('/');
929 dir_path = path.left(n);
932 _lock_file = dir_path.cat("/.tt_lock");
935 // mkdir in case the "tt" or ".tt" subdirectory doesn't exist.
937 (void)mkdir((char *)dir_path, 0777); // ignore errors, probably EEXIST
939 while ((fd = open((char *)_lock_file,
940 O_WRONLY|O_CREAT|O_EXCL, 0777) == -1)
943 _tt_syslog(stderr, LOG_ERR, "%s: %m",
944 (char *)_lock_file, strerror(EEXIST));
946 _flags &= ~(1<<_TT_TYPEDB_LOCKED);
952 close(fd); // Cleanup
954 _flags |= (1<<_TT_TYPEDB_LOCKED);
960 // Commits the write transaction to the database. In Classing Engine mode
961 // we just call the ce_commit_write function. In xdr mode we write out
962 // the database to a temporary file and then rename the file to be the
968 #ifdef OPT_CLASSING_ENGINE
969 if (! (_flags&(1<<_TT_TYPEDB_XDR_MODE))) {
970 int ce_err = (int)CALLCE(ce_commit_write)(0);
973 print_ce_error(ce_err);
979 #endif // OPT_CLASSING_ENGINE
982 _Tt_string dbpath_tmp;
985 if (!(_flags&(1<<_TT_TYPEDB_LOCKED))) {
988 if (_flags&(1<<_TT_TYPEDB_USER)) {
990 } else if (_flags&(1<<_TT_TYPEDB_SYSTEM)) {
992 } else if (_flags&(1<<_TT_TYPEDB_NETWORK)) {
995 dbpath_tmp = dbpath.cat("_tmp");
996 success = write(dbpath_tmp) == TT_OK;
998 (void)unlink((char *)dbpath_tmp);
999 (void)unlink((char *)_lock_file);
1003 success = (0 == rename((char *)dbpath_tmp, (char *)dbpath));
1005 send_saved( dbpath );
1006 _tt_syslog(stdout, LOG_INFO,
1007 catgets(_ttcatd, 2, 11, "Overwrote %s"),
1010 _tt_syslog(stderr, LOG_ERR,
1011 "rename( \"%s\", \"%s\" ): %m",
1012 (char *)dbpath_tmp, (char *)dbpath);
1014 (void)unlink((char *)_lock_file);
1015 (void)unlink((char *)dbpath_tmp);
1019 Tt_status _Tt_typedb::
1020 write(const _Tt_string &outfile)
1022 if (outfile.len() == 0) {
1023 return TT_DESKTOP_ENOENT;
1025 FILE *f = fopen((char *)outfile,"w");
1027 _tt_syslog(stderr, LOG_ERR, "%s: %m", (char *)outfile);
1028 return _tt_errno_status( errno );
1030 fcntl(fileno(f), F_SETFD, 1); /* Close on exec */
1031 Tt_status status = write( f );
1036 Tt_status _Tt_typedb::
1037 write(FILE *outfile)
1041 _Tt_typedb_ptr tdb_ptr = this;
1043 // For maximum compatibility, only write out types files
1044 // using the new XDR routines if the signatures have
1046 xdr_version = xdr_version_required();
1047 _Tt_xdr_version xvers(xdr_version);
1049 xdrstdio_create(&xdrs, outfile, XDR_ENCODE);
1050 if (! xdr_int(&xdrs, &xdr_version) || ! tdb_ptr.xdr(&xdrs)) {
1051 _tt_syslog(stderr, LOG_ERR, "! _Tt_typedb_ptr::xdr()" );
1058 // Do a tt_open() (if needed) and a ttdt_file_notice(), syslog()ing any error.
1060 Tt_status _Tt_typedb::
1061 send_saved(const _Tt_string &savedfile)
1063 const char *default_opt = "Saved";
1065 char *procid = tt_default_procid();
1066 Tt_status status = tt_ptr_error( procid );
1074 status = tt_ptr_error( procid );
1075 if (status == TT_OK) {
1079 if (status != TT_OK) {
1081 // No default session from which to send the notice,
1082 // so silently omit it. In principle libtt can send
1083 // a file-scoped notice without having a default session,
1084 // but the API does not permit this.
1089 // The HP linker thinks that ttdt_file_notice() ultimately
1090 // depends on some Xt symbols. The HP linker is wrong.
1091 // The AIX linker knows better. On SunOS, of course, we
1094 Tt_message msg = tt_message_create();
1095 tt_message_class_set( msg, TT_NOTICE );
1096 tt_message_scope_set( msg, TT_FILE );
1097 tt_message_address_set( msg, TT_PROCEDURE );
1098 tt_message_op_set( msg, default_opt );
1099 status = tt_message_file_set( msg, savedfile );
1100 if (status != TT_OK) {
1101 _tt_syslog(stderr, LOG_ERR,
1102 "tt_message_file_set(): %s", tt_status_message(status));
1104 tt_message_arg_add( msg, TT_IN, "File", 0 );
1105 status = tt_message_send( msg );
1106 if (status != TT_OK) {
1107 _tt_syslog(stderr, LOG_ERR,
1108 "tt_message_send(): %s", tt_status_message(status));
1113 #ifdef OPT_CLASSING_ENGINE
1116 // Creates a Classing Engine entry from a pointer to a _Tt_ptype
1117 // object. A CE entry is essentially an attribute/value list. The
1118 // names of the attributes are derived from the function
1119 // _tt_ce_attr_string which returns a string from an enum describing
1120 // the attribute that is to be written out.
1123 make_ce_entry(_Tt_ptype_ptr &pt)
1129 _Tt_ptype_prop_list_cursor props;
1131 ce_err = (int)CALLCE(ce_alloc_entry)(_ce_write_ns, &cn);
1133 print_ce_error(ce_err);
1136 val = (char *)pt->ptid();
1137 len = pt->ptid().len();
1138 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1139 _tt_ce_attr_string(_TYPE_NAME),
1140 _tt_ce_attr_string(_TT_TOOLTALK_PTYPE),
1143 print_ce_error(ce_err);
1146 val = _tt_ce_attr_string(_TT_TOOLTALK_PTYPE);
1148 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1149 _tt_ce_attr_string(_TT_TOOLTALK_TYPE),
1152 print_ce_error(ce_err);
1155 props.reset(pt->_props);
1156 while (props.next()) {
1157 val = (char *)props->value();
1158 len = props->value().len();
1159 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1160 (char *)props->name(),
1161 "string", val, len);
1163 print_ce_error(ce_err);
1172 // Creates a Classing Engine entry from a pointer to a _Tt_otype
1173 // object. A CE entry is essentially an attribute/value list. The
1174 // names of the attributes are derived from the function
1175 // _tt_ce_attr_string which returns a string from an enum describing
1176 // the attribute that is to be written out.
1179 make_ce_entry(_Tt_otype_ptr &ot)
1183 _Tt_string_list_cursor anc;
1187 ce_err = (int)CALLCE(ce_alloc_entry)(_ce_write_ns, &cn);
1189 print_ce_error(ce_err);
1192 val = (char *)ot->_otid;
1193 len = ot->_otid.len();
1194 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1195 _tt_ce_attr_string(_TYPE_NAME),
1196 _tt_ce_attr_string(_TT_TOOLTALK_OTYPE),
1199 print_ce_error(ce_err);
1202 val = _tt_ce_attr_string(_TT_TOOLTALK_OTYPE);
1204 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1205 _tt_ce_attr_string(_TT_TOOLTALK_TYPE),
1206 "string", val, len);
1208 print_ce_error(ce_err);
1211 if (! ot->_ancestors.is_null()) {
1212 anc.reset(ot->_ancestors);
1213 while (anc.next()) {
1216 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1217 _tt_ce_attr_string(_TT_PARENT),
1221 print_ce_error(ce_err);
1232 // Creates a Classing Engine entry from a pointer to a _Tt_signature
1233 // object. A CE entry is essentially an attribute/value list. The
1234 // names of the attributes are derived from the function
1235 // _tt_ce_attr_string which returns a string from an enum describing
1236 // the attribute that is to be written out.
1239 make_ce_entry(_Tt_signature_ptr &st)
1243 _Tt_arg_list_cursor argc;
1248 ce_err = (int)CALLCE(ce_alloc_entry)(_ce_write_ns, &cn);
1250 print_ce_error(ce_err);
1253 if (st->_mangled_args.len() == 0) {
1254 // in order to uniquely name this signature we have to
1255 // play the same tricks that C++ does and write out
1256 // the ptype or otype, the operation name of the
1257 // signature and then an encoding of the signature
1258 // argument types to distinguish it in the case of
1261 st->_mangled_args = "_";
1262 argc.reset(st->_args);
1263 while (argc.next()) {
1264 amode = argc->mode();
1265 st->_mangled_args = st->_mangled_args.cat(_tt_enumname(amode)).cat(argc->type()).cat("_");
1269 val = ((st->_otid.len()) ? st->_otid : st->_ptid);
1270 val = val.cat("::").cat(st->_op).cat(st->_mangled_args);
1271 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1272 _tt_ce_attr_string(_TYPE_NAME),
1273 _tt_ce_attr_string(_TT_TOOLTALK_TYPE),
1274 (char *)val, val.len());
1276 print_ce_error(ce_err);
1279 val = _tt_ce_attr_string(_TT_TOOLTALK_SIGNATURE);
1280 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1281 _tt_ce_attr_string(_TT_TOOLTALK_TYPE),
1282 "string", (char *)val, val.len());
1284 print_ce_error(ce_err);
1289 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1290 _tt_ce_attr_string(_TT_OP),
1291 "string", (char *)val, val.len());
1293 print_ce_error(ce_err);
1297 val = _tt_enumname(st->_pattern_category);
1298 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1299 _tt_ce_attr_string(_TT_CATEGORY),
1300 "string", (char *)val, val.len());
1302 print_ce_error(ce_err);
1306 argc.reset(st->_args);
1308 _Tt_string argc_type;
1310 (char *)malloc(strlen(_tt_ce_attr_string(_TT_ARG)) + 5);
1311 char *attrnamenum = attrname+strlen(_tt_ce_attr_string(_TT_ARG));
1312 strcpy(attrname,_tt_ce_attr_string(_TT_ARG));
1314 while (argc.next()) {
1315 sprintf((char *)attrnamenum, "%d", argn);
1316 val = _tt_enumname(argc->mode());
1317 argc_type = argc->type();
1318 val = val.cat(" ").cat(argc_type).cat(" ").cat(argc->name());
1319 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1322 (char *)val, val.len());
1324 print_ce_error(ce_err);
1331 name = ((st->_otid.len()) ? _tt_ce_attr_string(_TT_MSET_SCOPE) :
1332 _tt_ce_attr_string(_TT_SCOPE));
1333 val = _tt_enumname(st->_scope);
1334 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn, name, "string",
1335 (char *)val, val.len());
1337 print_ce_error(ce_err);
1341 val = _tt_enumname(st->_message_class);
1342 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1343 _tt_ce_attr_string(_TT_CLASS),
1344 "string", (char *)val, val.len());
1346 print_ce_error(ce_err);
1349 _Tt_string attr_typename = "string";
1350 switch (st->_reliability) {
1351 case TT_START+TT_QUEUE:
1352 #ifdef NOT_BACKWARD_COMPATIBLE
1353 val = _tt_ce_attr_string( _TT_START );
1354 val = val.cat( "+" ).cat( _tt_ce_attr_string( _TT_QUEUE ));
1355 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1356 _tt_ce_attr_string(_TT_MSET_DISPOSITION),
1357 (char *)attr_typename,
1358 (char *)val, val.len());
1360 print_ce_error(ce_err);
1366 // Version 1.0 can only handle finding start, queue,
1367 // or discard in the disposition attribute (bug
1368 // 1082628). So we will hide a clue that we are
1369 // something else in the typename of this attribute.
1370 // This works because in 1.0 _tt_convert_signature_attrs()
1371 // assumes the typename is "string", and never checks it.
1374 attr_typename.cat( ":" )
1375 .cat( _tt_ce_attr_string( _TT_START ))
1377 .cat( _tt_ce_attr_string( _TT_QUEUE ));
1379 // Now pretend it was START, so that we put start reliability
1380 // where 1.0 versions will find it. We assume here
1381 // that starting is more important than queueing.
1384 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1385 _tt_ce_attr_string(_TT_MSET_DISPOSITION),
1386 (char *)attr_typename,
1387 (char *)val, val.len());
1389 print_ce_error(ce_err);
1393 #endif /* NOT_BACKWARD_COMPATIBLE */
1396 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1397 _tt_ce_attr_string(_TT_MSET_DISPOSITION),
1398 (char *)attr_typename,
1399 (char *)val, val.len());
1401 print_ce_error(ce_err);
1407 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1408 _tt_ce_attr_string(_TT_MSET_DISPOSITION),
1409 (char *)attr_typename,
1410 (char *)val, val.len());
1412 print_ce_error(ce_err);
1419 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1420 _tt_ce_attr_string(_TT_MSET_DISPOSITION),
1421 (char *)attr_typename,
1422 (char *)val, val.len());
1424 print_ce_error(ce_err);
1429 char opnumstring[40];
1430 sprintf(opnumstring,"%d", st->_opnum);
1432 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1433 _tt_ce_attr_string(_TT_MSET_OPNUM),
1434 "string", (char *)val, val.len());
1436 print_ce_error(ce_err);
1441 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1442 _tt_ce_attr_string(_TT_MSET_HANDLER_PTYPE),
1443 "string", (char *)val, val.len());
1445 print_ce_error(ce_err);
1449 if (st->_otid.len()) {
1451 ce_err = (int)CALLCE(ce_add_attribute)(_ce_write_ns, &cn,
1452 _tt_ce_attr_string(_TT_MSET_OTYPE),
1453 "string", (char *)val, val.len());
1455 print_ce_error(ce_err);
1465 // This function is passed in as a callback to ce_map_through_attrs by
1466 // _tt_ce_entry_to_ptype. It's function is to process a ptype
1467 // attribute. This involves determining which attribute it is and then
1468 // modifying the _Tt_ptype object (which is passed in as arg by the
1469 // ce_map_through_atts call).
1472 _tt_convert_ptype_attrs(CE_ATTRIBUTE attr, char *value, void *arg)
1477 _Tt_ptype *p = (_Tt_ptype *)arg;
1479 if (attr == _tt_attrs[_TYPE_NAME] ||
1480 attr == _tt_attrs[_TT_TOOLTALK_TYPE]) {
1483 name = (char *)CALLCE(ce_get_attribute_name)(attr);
1485 if (p->getprop(name_s, value_s)) {
1488 // add property to ptype.
1490 p->appendprop(name_s, value_s);
1497 // This function is passed in as a callback to ce_map_through_attrs by
1498 // _tt_ce_entry_to_otype. Its function is to process the given
1499 // attribute and modify the _Tt_otype object appropiately. This object
1500 // is passed in as arg by ce_map_through_attrs. If this callback
1501 // returns anything other than (void *)0, then it causes
1502 // ce_map_through_attrs to return immediately without processing the
1503 // rest of the current entry's attributes. This signals an error to
1504 // _tt_ce_entry_to_otype. The attribute is mapped to the appropiate
1505 // tooltalk attribute by way of the _tt_attrs table (this avoid having
1506 // to do repeated strcmps on the attribute's name).
1509 _tt_convert_otype_attrs(CE_ATTRIBUTE attr, char *value, void *arg)
1511 _Tt_string_list_ptr ancs;
1512 _Tt_string_list_cursor anc_c;
1513 _Tt_otype *o = (_Tt_otype *)arg;
1515 if (attr == _tt_attrs[_TYPE_NAME] ||
1516 attr == _tt_attrs[_TT_TOOLTALK_TYPE]) {
1519 if (attr == _tt_attrs[_TT_PARENT]) {
1520 ancs = o->parents();
1521 if (ancs.is_null()) {
1522 ancs = new _Tt_string_list();
1523 o->set_ancestors(ancs);
1526 while (anc_c.next()) {
1527 if (*anc_c == value) {
1531 ancs->push(_Tt_string(value));
1539 // This function is passed in as a callback to ce_map_through_attrs by
1540 // _tt_ce_entry_to_signature. It's function is to process the
1541 // attribute and modify the _Tt_signature object (passed in as arg by
1542 // ce_map_through_attrs). If this function returns anything other than
1543 // (void *)0 then ce_map_through_attrs will return immediately with
1544 // this value and _tt_ce_entry_to_signature will return an error.
1545 // The attribute is mapped to the appropiate tooltalk attribute by way
1546 // of the _tt_attrs table (this avoid having to do repeated strcmps on
1547 // the attribute's name).
1550 _tt_convert_signature_attrs(CE_ATTRIBUTE attr, char *value, void *arg)
1553 _Tt_signature *s = (_Tt_signature *)arg;
1554 _Tt_arg_list_ptr args;
1556 _Tt_string valstring;
1560 CE_ATTRIBUTE val_id;
1562 if (attr == _tt_attrs[_TYPE_NAME] ||
1563 attr == _tt_attrs[_TT_TOOLTALK_TYPE]) {
1565 } else if (attr == _tt_attrs[_TT_OP]) {
1569 } else if (attr == _tt_attrs[_TT_CLASS]) {
1571 val_id = CALLCE(ce_get_attribute_id)(_ce_type_ns, value);
1572 if (val_id == _tt_attrs[_TT_REQUEST]) {
1573 s->set_message_class(TT_REQUEST);
1574 } else if (val_id == _tt_attrs[_TT_NOTICE]) {
1575 s->set_message_class(TT_NOTICE);
1577 // XXX: assume TT_CLASS_UNDEFINED
1578 s->set_message_class(TT_CLASS_UNDEFINED);
1581 } else if ((attr == _tt_attrs[_TT_SCOPE])
1582 || (attr == _tt_attrs[_TT_MSET_SCOPE])) {
1584 val_id = CALLCE(ce_get_attribute_id)(_ce_type_ns, value);
1585 if (val_id == _tt_attrs[_TT_SESSION]) {
1586 s->set_scope(TT_SESSION);
1587 } else if (val_id == _tt_attrs[_TT_FILE]) {
1588 s->set_scope(TT_FILE);
1589 } else if (val_id == _tt_attrs[_TT_BOTH]) {
1590 s->set_scope(TT_BOTH);
1591 } else if (val_id == _tt_attrs[_TT_FILE_IN_SESSION]) {
1592 s->set_scope(TT_FILE_IN_SESSION);
1597 } else if ((attr == _tt_attrs[_TT_DISPOSITION]) ||
1598 (attr == _tt_attrs[_TT_MSET_DISPOSITION])) {
1600 _Tt_string typename = (char *)CALLCE(ce_get_attribute_type)(
1602 s->ce_entry, attr );
1603 if (typename == "string") {
1604 val_id = CALLCE(ce_get_attribute_id)(_ce_type_ns, value);
1605 if (val_id == _tt_attrs[_TT_DISCARD]) {
1606 s->set_reliability(TT_DISCARD);
1607 } else if (val_id == _tt_attrs[_TT_QUEUE]) {
1608 s->set_reliability(TT_QUEUE);
1609 } else if (val_id == _tt_attrs[_TT_START]) {
1610 s->set_reliability(TT_START);
1612 Tt_disposition disp= TT_DISCARD;
1613 _Tt_string valstring = value;
1614 _Tt_string left, right;
1616 while (valstring.len() > 0) {
1617 right = valstring.split('+', left);
1618 if (left.len() <= 0) {
1619 // XXX change split's behavior
1624 _tt_ce_attr_string(_TT_START)) {
1625 disp = (Tt_disposition)
1628 _tt_ce_attr_string(_TT_QUEUE)) {
1629 disp = (Tt_disposition)
1634 s->set_reliability( disp );
1637 _Tt_string hack = "string:";
1638 hack = hack.cat( _tt_ce_attr_string( _TT_START ))
1640 .cat( _tt_ce_attr_string( _TT_QUEUE ));
1641 if (typename == hack) {
1642 s->set_reliability (TT_START);
1643 s->set_reliability (TT_QUEUE);
1649 } else if (attr == _tt_attrs[_TT_MSET_HANDLER_PTYPE]) {
1653 } else if (attr == _tt_attrs[_TT_MSET_OTYPE]) {
1657 } else if (attr == _tt_attrs[_TT_MSET_OPNUM]) {
1659 s->set_opnum(atoi(value));
1661 } else if (attr == _tt_attrs[_TT_CATEGORY]) {
1663 val_id = CALLCE(ce_get_attribute_id)(_ce_type_ns, value);
1664 if (val_id == _tt_attrs[_TT_OBSERVE]) {
1665 s->set_pattern_category(TT_OBSERVE);
1666 } else if (val_id == _tt_attrs[_TT_HANDLE]) {
1667 s->set_pattern_category(TT_HANDLE);
1674 // none of the above, check for TT_ARG%d which is
1675 // an argument specifier.
1677 name = (char *)CALLCE(ce_get_attribute_name)(attr);
1679 _tt_ce_attr_string(_TT_ARG),
1680 strlen(_tt_ce_attr_string(_TT_ARG)))) {
1681 narg = new _Tt_arg();
1683 valstring = valstring.split(' ',mstring);
1684 nstring = valstring.split(' ',tstring);
1685 val_id = CALLCE(ce_get_attribute_id)(_ce_type_ns,
1687 if (val_id == _tt_attrs[_TT_OUT]) {
1688 narg->set_mode(TT_OUT);
1689 } else if (val_id == _tt_attrs[_TT_IN]) {
1690 narg->set_mode(TT_IN);
1691 } else if (val_id == _tt_attrs[_TT_INOUT]) {
1692 narg->set_mode(TT_INOUT);
1696 narg->set_type(tstring);
1697 narg->set_name(nstring);
1698 s->append_arg(narg);
1700 _tt_syslog(stderr, LOG_ERR,
1701 catgets(_ttcatd, 2, 12,
1702 "Ignoring unknown attribute <%s> "
1703 "of ToolTalk signature..."), name );
1711 // Called by _tt_collect_types_in_cedb to produce a _Tt_ptype object from
1712 // the given Classing Engine entry. Uses the _tt_convert_ptype_attrs
1713 // function as a callback to ce_map_through_attrs to do the real work.
1716 _tt_ce_entry_to_ptype(_Tt_ptype *p, CE_ENTRY ne)
1718 p->ce_entry = (void *)ne;
1719 return(0==CALLCE(ce_map_through_attrs)(_ce_type_ns, ne,
1720 _tt_convert_ptype_attrs, p));
1725 // Called by _tt_collect_types_in_cedb to produce a _Tt_otype object from
1726 // the given Classing Engine entry. Uses the _tt_convert_otype_attrs
1727 // function as a callback to ce_map_through_attrs to do the real work.
1730 _tt_ce_entry_to_otype(_Tt_otype *o, CE_ENTRY ne)
1732 o->ce_entry = (void *)ne;
1733 return(0==CALLCE(ce_map_through_attrs)(_ce_type_ns, ne,
1734 _tt_convert_otype_attrs, o));
1739 // Called by _tt_collect_types_in_cedb to produce a _Tt_signature object from
1740 // the given Classing Engine entry. Uses the _tt_convert_signature_attrs
1741 // function as a callback to ce_map_through_attrs to do the real work.
1744 _tt_ce_entry_to_signature(_Tt_signature *s, CE_ENTRY ne)
1746 s->ce_entry = (void *)ne;
1747 return(0==CALLCE(ce_map_through_attrs)(_ce_type_ns, ne,
1748 _tt_convert_signature_attrs,
1754 // This function is a callback passed in to ce_map_though_entries. It
1755 // is applied to each entry in the ToolTalk namespace in a Classing
1756 // Engine database. Each entry specifies either a ptype, otype or
1757 // signature. For each class of entry the appropiate _tt_ce_entry_to_*
1758 // function is invoked.
1761 _tt_collect_types_in_cedb(CE_NAMESPACE ns, CE_ENTRY ne, void *t)
1765 _Tt_signature_ptr s;
1766 _Tt_typedb *tdb = (_Tt_typedb *)t;
1768 CE_ATTRIBUTE type_id;
1771 int insert_required = 0;
1773 // XXX: should use ce_get_attribute_type when it's implemented
1775 // type = CALLCE(ce_get_attribute_type)(ne, _TT_TYPE_NAME);
1777 if (tdb->ceDB2Use != TypedbAll) {
1779 // We have been restricted to a single CE database.
1780 // Ignore this entry if it is not from the right database.
1781 // XXX CE should have had a better way to do this, such
1782 // as a parameter to ce_begin().
1784 char *db_name, *db_path;
1785 int ceStatus = (int)CALLCE(ce_get_entry_db_info)(
1786 ns, ne, &db_name, &db_path );
1787 if (ceStatus != 0) {
1790 if (_Tt_typedb::level( db_name ) != tdb->ceDB2Use) {
1795 type = (char *)CALLCE(ce_get_attribute)(ns, ne, _tt_attrs[_TT_TOOLTALK_TYPE]);
1796 if (type == (char *)0) {
1799 type_id = CALLCE(ce_get_attribute_id)(_ce_type_ns, type);
1800 if (type_id == _tt_attrs[_TT_TOOLTALK_PTYPE]) {
1804 ptid = (char *)CALLCE(ce_get_attribute)(ns, ne,
1805 _tt_attrs[_TYPE_NAME]);
1806 if (tdb->ptable.is_null()) {
1807 tdb->ptable = new _Tt_ptype_table(_tt_ptype_ptid);
1809 if (! tdb->ptable->lookup(ptid,p)) {
1810 p = new _Tt_ptype();
1812 insert_required = 1;
1814 if (!_tt_ce_entry_to_ptype(p.c_pointer(), ne)) {
1817 if (insert_required) {
1818 tdb->ptable->insert(p);
1822 } else if (type_id == _tt_attrs[_TT_TOOLTALK_OTYPE]) {
1826 otid = (char *)CALLCE(ce_get_attribute)(ns, ne,
1827 _tt_attrs[_TYPE_NAME]);
1828 if (tdb->otable.is_null()) {
1829 tdb->otable = new _Tt_otype_table(_tt_otype_otid);
1831 if (! tdb->otable->lookup(otid,o)) {
1832 o = new _Tt_otype(otid);
1833 insert_required = 1;
1835 if (!_tt_ce_entry_to_otype(o.c_pointer(), ne)) {
1838 if (insert_required) {
1839 tdb->otable->insert(o);
1841 } else if (type_id == _tt_attrs[_TT_TOOLTALK_SIGNATURE]) {
1845 _Tt_signature_list_ptr sp;
1847 s = new _Tt_signature();
1848 if (! _tt_ce_entry_to_signature(s.c_pointer(), ne)) {
1849 // failed to decode signature
1852 // first insert the signature into the relevant
1854 if (! tdb->ptable->lookup(s->ptid(),p)) {
1855 p = new _Tt_ptype();
1856 p->set_ptid(s->ptid());
1857 tdb->ptable->insert(p);
1859 switch (s->category()) {
1864 case TT_HANDLE_PUSH:
1865 case TT_HANDLE_ROTATE:
1866 p->append_hsig(s, s->category());
1869 if (s->otid().len() > 0) {
1871 if (tdb->otable.is_null()) {
1872 tdb->otable = new _Tt_otype_table(_tt_otype_otid);
1874 if (! tdb->otable->lookup(s->otid(),o)) {
1875 o = new _Tt_otype(s->otid());
1876 tdb->otable->insert(o);
1878 switch (s->category()) {
1883 case TT_HANDLE_PUSH:
1884 case TT_HANDLE_ROTATE:
1885 o->append_hsig(s, s->category());
1887 default: // inherited
1896 #endif // OPT_CLASSING_ENGINE
1900 Tt_status _Tt_typedb::
1902 #if defined(OPT_CLASSING_ENGINE)
1910 #ifndef OPT_CLASSING_ENGINE
1911 _tt_syslog(stderr, LOG_ERR, "_Tt_typedb::init_ce()!");
1912 return(TT_ERR_INTERNAL);
1918 #ifdef OPT_DLOPEN_CE
1919 int load_celib_environment();
1921 if (! load_celib_environment()) {
1922 _tt_syslog(stderr, LOG_ERR,
1923 "dlopen( \"libce.so\", 1 ): %s", dlerror());
1924 return(TT_ERR_INTERNAL);
1926 #endif // OPT_DLOPEN_CE
1929 if ((ce_err = (int)CALLCE(ce_begin)(0)) != 0) {
1930 print_ce_error(ce_err);
1931 return(TT_ERR_INTERNAL);
1933 _ce_type_ns = CALLCE(ce_get_namespace_id)(TT_NS_NAME);
1934 if (_ce_type_ns == (CE_NAMESPACE)0) {
1935 return(TT_ERR_DBEXIST);
1937 // Initialize the ce attributes relevant to ToolTalk types
1938 for (i = 0; i < _TT_CE_ATTR_LAST; i++) {
1939 c = CALLCE(ce_get_attribute_id)(_ce_type_ns,
1940 _tt_ce_attr_string((_Tt_ce_attr)i));
1941 // if c==0 then we can continue reading the database
1942 // since it just means we've encountered an attribute
1943 // not present in any of the namespace entries.
1946 if (0 != CALLCE(ce_map_through_entries)(_ce_type_ns,
1947 _tt_collect_types_in_cedb,
1949 return(TT_ERR_INTERNAL);
1952 #endif // !OPT_CLASSING_ENGINE
1956 Tt_status _Tt_typedb::
1959 struct stat xdrStat, ceStat;
1966 home = getenv( "HOME" );
1967 xdrdb = home.cat( "/.tt/types.xdr" );
1968 status = stat( (char *)xdrdb, &xdrStat );
1971 } else if (errno != ENOENT) {
1972 _tt_syslog( 0, LOG_ERR, "$HOME/.tt/types.xdr: %m" );
1975 cedb = home.cat( "/.cetables/cetables" );
1976 status = stat( (char *)cedb, &ceStat );
1978 if (errno == ENOENT) {
1979 // No cetables to convert
1982 _tt_syslog( 0, LOG_ERR,
1983 "$HOME/.cetables/cetables: %m" );
1988 if (ceStat.st_mtime <= xdrStat.st_mtime) {
1989 // XDR database is newer
1993 status = system( "ttce2xdr -d user &" );
1994 if (WIFEXITED(status)) {
1995 if (WEXITSTATUS(status) == 0) {
1998 _tt_syslog(stderr, LOG_ERR,
1999 catgets(_ttcatd, 2, 13,
2000 "ttce2xdr failed (status=%d); types"
2001 " in Classing Engine \"user\" "
2002 "database not converted..."),
2003 WEXITSTATUS(status) );
2004 return TT_ERR_PTYPE_START;
2007 _tt_syslog(stderr, LOG_ERR, "system(\"ttce2xdr -d user\"): %d",
2009 return TT_ERR_PTYPE_START;
2013 _Tt_typedbLevel _Tt_typedb::
2014 level( const _Tt_string &dbname )
2016 if (dbname == "user") {
2018 } else if (dbname == "system") {
2019 return TypedbSystem;
2020 } else if (dbname == "network") {
2021 return TypedbNetwork;
2027 const char * _Tt_typedb::
2028 level_name( _Tt_typedbLevel db )
2044 xdr_version_required() const
2046 int version = TT_TYPESDB_DEFAULT_XDR_VERSION;
2047 _Tt_ptype_table_cursor ptypes(ptable);
2048 while (ptypes.next()) {
2049 if(ptypes->xdr_version_required() > version) {
2050 version = ptypes->xdr_version_required();
2052 // version = max(version, ptypes->xdr_version_required());
2054 _Tt_otype_table_cursor otypes(otable);
2055 while (otypes.next()) {
2056 if(otypes->xdr_version_required() > version) {
2057 version = otypes->xdr_version_required();
2059 // version = max(version, otypes->xdr_version_required());
2066 write_out_tt_attrs(const _Tt_ostream &os)
2070 FILE *fs = os.theFILE();
2071 for (i=0; i < _TT_CE_ATTR_LAST; i++) {
2072 fprintf(fs,"\t\t(%s,string,<attr>)\n",
2073 _tt_ce_attr_string((_Tt_ce_attr)i));
2080 pretty_print(const _Tt_ostream &os) const
2082 _Tt_ptype_table_cursor ptypes(ptable);
2083 while (ptypes.next()) {
2084 ptypes->pretty_print(os);
2087 _Tt_otype_table_cursor otypes(otable);
2088 while (otypes.next()) {
2089 otypes->pretty_print(os);
2097 print(const _Tt_ostream &os) const
2099 if (write_ce_header(os)) {
2100 os << "\nNS_ENTRIES= (\n\t(\t";
2101 write_out_tt_attrs(os);
2102 ptable->print(_tt_ptype_print, os);
2103 otable->print(_tt_otype_print, os);
2110 write_ce_header(const _Tt_ostream &os) const
2112 os << "{\nNS_NAME=" << TT_NS_NAME
2113 << "\nNS_ATTR=(\n\t\t(NS_MANAGER,string,"
2114 "<$CEPATH/tns_mgr.so>)\n\t)";
2120 #if defined(OPT_DLOPEN_CE) && defined(OPT_CLASSING_ENGINE)
2122 /**************************************************************************
2123 * This section contains functions for dynamically loading in the
2124 * necessary ce functions. This avoids the need for applications to link
2125 * in libce. Note that all of this section is ifdefd with OPT_DLOPEN_CE so
2126 * only functions relevant to dynamic loading of ce should be included.
2127 **************************************************************************/
2132 load_celib_environment()
2134 int load_celib_fns_from_handle(void *);
2138 // first try opening the current executable to see if the
2139 // functions have already been defined
2140 dlhandle = dlopen((char *)0, 1);
2141 if (load_celib_fns_from_handle(dlhandle)) {
2145 #if defined(OPT_BUG_SUNOS_4)
2146 // Not strictly a bug, but SunOS 4.x doesn't do what we want.
2147 if (! tt_ldpath("libce.so", path)) {
2151 // SVR4 version of dlopen does the path searching for us
2156 #if defined(OPT_BUG_SUNOS_4)
2157 // SunOS 4 knows nothing of RTLD options
2158 dlhandle = dlopen((char *)path, 1);
2160 // XXX: In theory, RTLD_LAZY (the default) is the preferred way of
2161 // using dlopen. However, there were some bugs in early 5.0 versions
2162 // that made dlopen slow down considerably if RTLD_LAZY is used.
2163 // For now, we'll use RTLD_NOW which seems to get rid of the
2164 // behavior but perhaps not the cause.
2165 // Next time we do performance tuning we should retry with
2167 dlhandle = dlopen((char *)path, RTLD_NOW);
2169 if (dlhandle == (void *)0) {
2173 return(load_celib_fns_from_handle(dlhandle));
2178 * XXX: This is sort of ugly. dlopen doesn't make the symbol available
2179 * for normal dynamic linking. This means that if the library that is
2180 * dlopened itself uses some of the symbols that are made available by
2181 * the use of dlsym then the library needs to be linked in with the
2182 * executable. We circumvent this by defining those symbols directly
2183 * here. This is unfortunately sensitive to the implementation of libce
2184 * changing. Ie. if it is changed to use more symbols than
2185 * ce_get_attribute_id and ce_get_attribute then libce will have to be
2186 * linked in regardless of whether it is dlopened or not.
2188 * All of a sudden we're getting infinite loops here, under ce_begin().
2189 * So I'm commenting these two puppies out. Brian 8/05/92
2192 ce_get_attribute_id(CE_NAMESPACE ns, char *a)
2194 return((CE_ATTRIBUTE)CALLCE(ce_get_attribute_id)(ns,a));
2198 ce_get_attribute(CE_NAMESPACE ns, CE_ENTRY e, CE_ATTRIBUTE a)
2200 return((char *)CALLCE(ce_get_attribute)(ns,e,a));
2206 load_celib_fns_from_handle(void *dlhandle)
2208 #if defined(__STDC__)
2209 #define DLINK_FN(fn)\
2210 _tt_celib . fn = (_Tt_cefn_ptr)dlsym(dlhandle, #fn); \
2211 if (_tt_celib . fn == (_Tt_cefn_ptr)0) { \
2215 #define DLINK_FN(fn)\
2216 _tt_celib . fn = (_Tt_cefn_ptr)dlsym(dlhandle, "fn"); \
2217 if (_tt_celib . fn == (_Tt_cefn_ptr)0) { \
2220 #endif /* __STDC__ */
2222 DLINK_FN(ce_abort_write)
2223 DLINK_FN(ce_add_attribute)
2224 DLINK_FN(ce_add_entry)
2225 DLINK_FN(ce_add_namespace)
2226 DLINK_FN(ce_alloc_entry)
2227 DLINK_FN(ce_alloc_ns_entry)
2228 DLINK_FN(ce_get_attribute_id)
2230 DLINK_FN(ce_commit_write)
2231 DLINK_FN(ce_get_attribute)
2232 DLINK_FN(ce_get_attribute_name)
2233 DLINK_FN(ce_get_attribute_type)
2234 DLINK_FN(ce_get_entry_db_info)
2235 DLINK_FN(ce_get_namespace_id)
2236 DLINK_FN(ce_map_through_attrs)
2237 DLINK_FN(ce_map_through_entries)
2238 DLINK_FN(ce_remove_entry)
2239 DLINK_FN(ce_start_write)
2244 #endif // OPT_DLOPEN_CE && OPT_CLASSING_ENGINE