11914Scasper /*
2*7934SMark.Phalan@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
31914Scasper * Use is subject to license terms.
41914Scasper */
50Sstevel@tonic-gate /*
60Sstevel@tonic-gate * prof_file.c ---- routines that manipulate an individual profile file.
70Sstevel@tonic-gate */
80Sstevel@tonic-gate
90Sstevel@tonic-gate #include <autoconf.h>
10781Sgtb #include "prof_int.h"
110Sstevel@tonic-gate
120Sstevel@tonic-gate #include <stdio.h>
130Sstevel@tonic-gate #ifdef HAVE_STDLIB_H
140Sstevel@tonic-gate #include <stdlib.h>
150Sstevel@tonic-gate #endif
160Sstevel@tonic-gate #ifdef HAVE_UNISTD_H
170Sstevel@tonic-gate #include <unistd.h>
180Sstevel@tonic-gate #endif
190Sstevel@tonic-gate #include <string.h>
20781Sgtb #include <stddef.h>
210Sstevel@tonic-gate
220Sstevel@tonic-gate #include <sys/types.h>
230Sstevel@tonic-gate #include <sys/stat.h>
240Sstevel@tonic-gate #include <errno.h>
250Sstevel@tonic-gate
26781Sgtb #ifdef HAVE_PWD_H
27781Sgtb #include <pwd.h>
28781Sgtb #endif
290Sstevel@tonic-gate
30781Sgtb #if defined(_WIN32)
310Sstevel@tonic-gate #include <io.h>
320Sstevel@tonic-gate #define HAVE_STAT
330Sstevel@tonic-gate #define stat _stat
340Sstevel@tonic-gate #endif
350Sstevel@tonic-gate
36781Sgtb #include "k5-platform.h"
37781Sgtb
38781Sgtb struct global_shared_profile_data {
39781Sgtb /* This is the head of the global list of shared trees */
40781Sgtb prf_data_t trees;
41781Sgtb /* Lock for above list. */
42781Sgtb k5_mutex_t mutex;
43781Sgtb };
44781Sgtb #define g_shared_trees (krb5int_profile_shared_data.trees)
45781Sgtb #define g_shared_trees_mutex (krb5int_profile_shared_data.mutex)
46781Sgtb
47781Sgtb static struct global_shared_profile_data krb5int_profile_shared_data = {
48781Sgtb 0,
49781Sgtb K5_MUTEX_PARTIAL_INITIALIZER
50781Sgtb };
51781Sgtb
52781Sgtb MAKE_INIT_FUNCTION(profile_library_initializer);
53781Sgtb MAKE_FINI_FUNCTION(profile_library_finalizer);
540Sstevel@tonic-gate
profile_library_initializer(void)55781Sgtb int profile_library_initializer(void)
56781Sgtb {
57*7934SMark.Phalan@Sun.COM #ifdef SHOW_INITFINI_FUNCS
58*7934SMark.Phalan@Sun.COM printf("profile_library_initializer\n");
59*7934SMark.Phalan@Sun.COM #endif
60781Sgtb #if !USE_BUNDLE_ERROR_STRINGS
61781Sgtb add_error_table(&et_prof_error_table);
62781Sgtb #endif
63781Sgtb return k5_mutex_finish_init(&g_shared_trees_mutex);
64781Sgtb }
profile_library_finalizer(void)65781Sgtb void profile_library_finalizer(void)
66781Sgtb {
67*7934SMark.Phalan@Sun.COM if (! INITIALIZER_RAN(profile_library_initializer) || PROGRAM_EXITING()) {
68*7934SMark.Phalan@Sun.COM #ifdef SHOW_INITFINI_FUNCS
69*7934SMark.Phalan@Sun.COM printf("profile_library_finalizer: skipping\n");
70*7934SMark.Phalan@Sun.COM #endif
71781Sgtb return;
72*7934SMark.Phalan@Sun.COM }
73*7934SMark.Phalan@Sun.COM #ifdef SHOW_INITFINI_FUNCS
74*7934SMark.Phalan@Sun.COM printf("profile_library_finalizer\n");
75*7934SMark.Phalan@Sun.COM #endif
76781Sgtb k5_mutex_destroy(&g_shared_trees_mutex);
77781Sgtb #if !USE_BUNDLE_ERROR_STRINGS
78781Sgtb remove_error_table(&et_prof_error_table);
79781Sgtb #endif
80781Sgtb }
81781Sgtb
82781Sgtb static void profile_free_file_data(prf_data_t);
83781Sgtb
84781Sgtb #if 0
85781Sgtb
86781Sgtb #define scan_shared_trees_locked() \
87781Sgtb { \
88781Sgtb prf_data_t d; \
89781Sgtb k5_mutex_assert_locked(&g_shared_trees_mutex); \
90781Sgtb for (d = g_shared_trees; d; d = d->next) { \
91781Sgtb assert(d->magic == PROF_MAGIC_FILE_DATA); \
92781Sgtb assert((d->flags & PROFILE_FILE_SHARED) != 0); \
93781Sgtb assert(d->filespec[0] != 0); \
94781Sgtb assert(d->fslen <= 1000); /* XXX */ \
95781Sgtb assert(d->filespec[d->fslen] == 0); \
96781Sgtb assert(d->fslen = strlen(d->filespec)); \
97*7934SMark.Phalan@Sun.COM assert(d->root != NULL); \
98781Sgtb } \
99781Sgtb }
100781Sgtb
101781Sgtb #define scan_shared_trees_unlocked() \
102781Sgtb { \
103781Sgtb int r; \
104781Sgtb r = k5_mutex_lock(&g_shared_trees_mutex); \
105781Sgtb assert (r == 0); \
106781Sgtb scan_shared_trees_locked(); \
107781Sgtb k5_mutex_unlock(&g_shared_trees_mutex); \
108781Sgtb }
109781Sgtb
110781Sgtb #else
111781Sgtb
112781Sgtb #define scan_shared_trees_locked() { ; }
113781Sgtb #define scan_shared_trees_unlocked() { ; }
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate #endif
1160Sstevel@tonic-gate
rw_access(const_profile_filespec_t filespec)117781Sgtb static int rw_access(const_profile_filespec_t filespec)
1180Sstevel@tonic-gate {
1190Sstevel@tonic-gate #ifdef HAVE_ACCESS
1200Sstevel@tonic-gate if (access(filespec, W_OK) == 0)
1210Sstevel@tonic-gate return 1;
1220Sstevel@tonic-gate else
1230Sstevel@tonic-gate return 0;
1240Sstevel@tonic-gate #else
1250Sstevel@tonic-gate /*
1260Sstevel@tonic-gate * We're on a substandard OS that doesn't support access. So
1270Sstevel@tonic-gate * we kludge a test using stdio routines, and hope fopen
1280Sstevel@tonic-gate * checks the r/w permissions.
1290Sstevel@tonic-gate */
1300Sstevel@tonic-gate FILE *f;
131*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
1321914Scasper f = fopen(filespec, "r+F");
133781Sgtb if (f) {
134781Sgtb fclose(f);
135781Sgtb return 1;
136781Sgtb }
137781Sgtb return 0;
138781Sgtb #endif
139781Sgtb }
140781Sgtb
r_access(const_profile_filespec_t filespec)141781Sgtb static int r_access(const_profile_filespec_t filespec)
142781Sgtb {
143781Sgtb #ifdef HAVE_ACCESS
144781Sgtb if (access(filespec, R_OK) == 0)
145781Sgtb return 1;
146781Sgtb else
147781Sgtb return 0;
1480Sstevel@tonic-gate #else
149781Sgtb /*
150781Sgtb * We're on a substandard OS that doesn't support access. So
151781Sgtb * we kludge a test using stdio routines, and hope fopen
152781Sgtb * checks the r/w permissions.
153781Sgtb */
154781Sgtb FILE *f;
155781Sgtb
156*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
1571914Scasper f = fopen(filespec, "rF");
1580Sstevel@tonic-gate if (f) {
1590Sstevel@tonic-gate fclose(f);
1600Sstevel@tonic-gate return 1;
1610Sstevel@tonic-gate }
1620Sstevel@tonic-gate return 0;
1630Sstevel@tonic-gate #endif
1640Sstevel@tonic-gate }
1650Sstevel@tonic-gate
166781Sgtb prf_data_t
profile_make_prf_data(const char * filename)167781Sgtb profile_make_prf_data(const char *filename)
168781Sgtb {
169781Sgtb prf_data_t d;
170781Sgtb size_t len, flen, slen;
171781Sgtb char *fcopy;
172781Sgtb
173781Sgtb flen = strlen(filename);
174781Sgtb slen = offsetof(struct _prf_data_t, filespec);
175781Sgtb len = slen + flen + 1;
176781Sgtb if (len < sizeof(struct _prf_data_t))
177781Sgtb len = sizeof(struct _prf_data_t);
178781Sgtb d = malloc(len);
179781Sgtb if (d == NULL)
180781Sgtb return NULL;
181781Sgtb memset(d, 0, len);
182781Sgtb fcopy = (char *) d + slen;
183781Sgtb assert(fcopy == d->filespec);
184781Sgtb strcpy(fcopy, filename);
185781Sgtb d->refcount = 1;
186781Sgtb d->comment = NULL;
187781Sgtb d->magic = PROF_MAGIC_FILE_DATA;
188781Sgtb d->root = NULL;
189781Sgtb d->next = NULL;
190781Sgtb d->fslen = flen;
191781Sgtb return d;
192781Sgtb }
193781Sgtb
profile_open_file(const_profile_filespec_t filespec,prf_file_t * ret_prof)194781Sgtb errcode_t profile_open_file(const_profile_filespec_t filespec,
195781Sgtb prf_file_t *ret_prof)
1960Sstevel@tonic-gate {
1970Sstevel@tonic-gate prf_file_t prf;
1980Sstevel@tonic-gate errcode_t retval;
1990Sstevel@tonic-gate char *home_env = 0;
200781Sgtb unsigned int len;
201781Sgtb prf_data_t data;
202781Sgtb char *expanded_filename;
203781Sgtb
204781Sgtb retval = CALL_INIT_FUNCTION(profile_library_initializer);
205781Sgtb if (retval)
206781Sgtb return retval;
207781Sgtb
208781Sgtb scan_shared_trees_unlocked();
2090Sstevel@tonic-gate
210*7934SMark.Phalan@Sun.COM prf = malloc(sizeof(struct _prf_file_t));
2110Sstevel@tonic-gate if (!prf)
2120Sstevel@tonic-gate return ENOMEM;
2130Sstevel@tonic-gate memset(prf, 0, sizeof(struct _prf_file_t));
214781Sgtb prf->magic = PROF_MAGIC_FILE;
215781Sgtb
2160Sstevel@tonic-gate len = strlen(filespec)+1;
2170Sstevel@tonic-gate if (filespec[0] == '~' && filespec[1] == '/') {
2180Sstevel@tonic-gate home_env = getenv("HOME");
219781Sgtb #ifdef HAVE_PWD_H
220781Sgtb if (home_env == NULL) {
221781Sgtb uid_t uid;
222*7934SMark.Phalan@Sun.COM struct passwd *pw, pwx;
223781Sgtb char pwbuf[BUFSIZ];
224781Sgtb
225781Sgtb uid = getuid();
226*7934SMark.Phalan@Sun.COM if (!k5_getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw)
227*7934SMark.Phalan@Sun.COM && pw != NULL && pw->pw_dir[0] != 0)
228781Sgtb home_env = pw->pw_dir;
229781Sgtb }
230781Sgtb #endif
2310Sstevel@tonic-gate if (home_env)
2320Sstevel@tonic-gate len += strlen(home_env);
2330Sstevel@tonic-gate }
234781Sgtb expanded_filename = malloc(len);
235781Sgtb if (expanded_filename == 0)
236781Sgtb return errno;
2370Sstevel@tonic-gate if (home_env) {
238781Sgtb strcpy(expanded_filename, home_env);
239781Sgtb strcat(expanded_filename, filespec+1);
2400Sstevel@tonic-gate } else
241781Sgtb memcpy(expanded_filename, filespec, len);
242781Sgtb
243781Sgtb retval = k5_mutex_lock(&g_shared_trees_mutex);
244781Sgtb if (retval) {
245781Sgtb free(expanded_filename);
246781Sgtb free(prf);
247781Sgtb scan_shared_trees_unlocked();
248781Sgtb return retval;
249781Sgtb }
250781Sgtb scan_shared_trees_locked();
251781Sgtb for (data = g_shared_trees; data; data = data->next) {
252781Sgtb if (!strcmp(data->filespec, expanded_filename)
253781Sgtb /* Check that current uid has read access. */
254781Sgtb && r_access(data->filespec))
255781Sgtb break;
256781Sgtb }
257781Sgtb if (data) {
258781Sgtb data->refcount++;
259781Sgtb (void) k5_mutex_unlock(&g_shared_trees_mutex);
260*7934SMark.Phalan@Sun.COM retval = profile_update_file_data(data);
261781Sgtb free(expanded_filename);
262781Sgtb prf->data = data;
263781Sgtb *ret_prof = prf;
264781Sgtb scan_shared_trees_unlocked();
265781Sgtb return retval;
266781Sgtb }
267781Sgtb (void) k5_mutex_unlock(&g_shared_trees_mutex);
268781Sgtb data = profile_make_prf_data(expanded_filename);
269781Sgtb if (data == NULL) {
270781Sgtb free(prf);
271781Sgtb free(expanded_filename);
272781Sgtb return ENOMEM;
273781Sgtb }
274781Sgtb free(expanded_filename);
275781Sgtb prf->data = data;
276781Sgtb
277781Sgtb retval = k5_mutex_init(&data->lock);
278781Sgtb if (retval) {
279781Sgtb free(data);
280781Sgtb free(prf);
281781Sgtb return retval;
282781Sgtb }
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate retval = profile_update_file(prf);
2850Sstevel@tonic-gate if (retval) {
2860Sstevel@tonic-gate profile_close_file(prf);
2870Sstevel@tonic-gate return retval;
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate
290781Sgtb retval = k5_mutex_lock(&g_shared_trees_mutex);
291781Sgtb if (retval) {
292781Sgtb profile_close_file(prf);
293781Sgtb scan_shared_trees_unlocked();
294781Sgtb return retval;
295781Sgtb }
296781Sgtb scan_shared_trees_locked();
297781Sgtb data->flags |= PROFILE_FILE_SHARED;
298781Sgtb data->next = g_shared_trees;
299781Sgtb g_shared_trees = data;
300781Sgtb scan_shared_trees_locked();
301781Sgtb (void) k5_mutex_unlock(&g_shared_trees_mutex);
302781Sgtb
3030Sstevel@tonic-gate *ret_prof = prf;
3040Sstevel@tonic-gate return 0;
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate
profile_update_file_data(prf_data_t data)307781Sgtb errcode_t profile_update_file_data(prf_data_t data)
3080Sstevel@tonic-gate {
3090Sstevel@tonic-gate errcode_t retval;
3100Sstevel@tonic-gate #ifdef HAVE_STAT
3110Sstevel@tonic-gate struct stat st;
312*7934SMark.Phalan@Sun.COM unsigned long frac;
313781Sgtb time_t now;
314781Sgtb #endif
3150Sstevel@tonic-gate FILE *f;
3160Sstevel@tonic-gate
317781Sgtb retval = k5_mutex_lock(&data->lock);
318781Sgtb if (retval)
319781Sgtb return retval;
320781Sgtb
3210Sstevel@tonic-gate #ifdef HAVE_STAT
322781Sgtb now = time(0);
323*7934SMark.Phalan@Sun.COM if (now == data->last_stat && data->root != NULL) {
324781Sgtb k5_mutex_unlock(&data->lock);
325781Sgtb return 0;
326781Sgtb }
327781Sgtb if (stat(data->filespec, &st)) {
328781Sgtb retval = errno;
329781Sgtb k5_mutex_unlock(&data->lock);
330781Sgtb return retval;
3310Sstevel@tonic-gate }
332781Sgtb data->last_stat = now;
333*7934SMark.Phalan@Sun.COM #if defined HAVE_STRUCT_STAT_ST_MTIMENSEC
334*7934SMark.Phalan@Sun.COM frac = st.st_mtimensec;
335*7934SMark.Phalan@Sun.COM #elif defined HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
336*7934SMark.Phalan@Sun.COM frac = st.st_mtimespec.tv_nsec;
337*7934SMark.Phalan@Sun.COM #elif defined HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
338*7934SMark.Phalan@Sun.COM frac = st.st_mtim.tv_nsec;
339*7934SMark.Phalan@Sun.COM #else
340*7934SMark.Phalan@Sun.COM frac = 0;
341781Sgtb #endif
342*7934SMark.Phalan@Sun.COM if (st.st_mtime == data->timestamp
343*7934SMark.Phalan@Sun.COM && frac == data->frac_ts
344*7934SMark.Phalan@Sun.COM && data->root != NULL) {
345781Sgtb k5_mutex_unlock(&data->lock);
346781Sgtb return 0;
347781Sgtb }
348781Sgtb if (data->root) {
349781Sgtb profile_free_node(data->root);
350781Sgtb data->root = 0;
351781Sgtb }
352781Sgtb if (data->comment) {
353781Sgtb free(data->comment);
354781Sgtb data->comment = 0;
3550Sstevel@tonic-gate }
3560Sstevel@tonic-gate #else
3570Sstevel@tonic-gate /*
3580Sstevel@tonic-gate * If we don't have the stat() call, assume that our in-core
3590Sstevel@tonic-gate * memory image is correct. That is, we won't reread the
3600Sstevel@tonic-gate * profile file if it changes.
3610Sstevel@tonic-gate */
362781Sgtb if (data->root) {
363781Sgtb k5_mutex_unlock(&data->lock);
364781Sgtb return 0;
365781Sgtb }
3660Sstevel@tonic-gate #endif
3670Sstevel@tonic-gate errno = 0;
368*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
3691914Scasper f = fopen(data->filespec, "rF");
3700Sstevel@tonic-gate if (f == NULL) {
3710Sstevel@tonic-gate retval = errno;
372781Sgtb k5_mutex_unlock(&data->lock);
3730Sstevel@tonic-gate if (retval == 0)
3740Sstevel@tonic-gate retval = ENOENT;
3750Sstevel@tonic-gate return retval;
3760Sstevel@tonic-gate }
377781Sgtb data->upd_serial++;
378781Sgtb data->flags &= PROFILE_FILE_SHARED;
379781Sgtb if (rw_access(data->filespec))
380781Sgtb data->flags |= PROFILE_FILE_RW;
381781Sgtb retval = profile_parse_file(f, &data->root);
3820Sstevel@tonic-gate fclose(f);
383781Sgtb if (retval) {
384781Sgtb k5_mutex_unlock(&data->lock);
385781Sgtb return retval;
386781Sgtb }
387*7934SMark.Phalan@Sun.COM assert(data->root != NULL);
3880Sstevel@tonic-gate #ifdef HAVE_STAT
389781Sgtb data->timestamp = st.st_mtime;
390*7934SMark.Phalan@Sun.COM data->frac_ts = frac;
3910Sstevel@tonic-gate #endif
392781Sgtb k5_mutex_unlock(&data->lock);
3930Sstevel@tonic-gate return 0;
3940Sstevel@tonic-gate }
3950Sstevel@tonic-gate
396781Sgtb static int
make_hard_link(const char * oldpath,const char * newpath)397781Sgtb make_hard_link(const char *oldpath, const char *newpath)
3980Sstevel@tonic-gate {
399781Sgtb #ifdef _WIN32
400781Sgtb return -1;
401781Sgtb #else
402781Sgtb return link(oldpath, newpath);
403781Sgtb #endif
4040Sstevel@tonic-gate }
4050Sstevel@tonic-gate
write_data_to_file(prf_data_t data,const char * outfile,int can_create)406781Sgtb static errcode_t write_data_to_file(prf_data_t data, const char *outfile,
407781Sgtb int can_create)
4080Sstevel@tonic-gate {
4090Sstevel@tonic-gate FILE *f;
4100Sstevel@tonic-gate profile_filespec_t new_file;
4110Sstevel@tonic-gate profile_filespec_t old_file;
4120Sstevel@tonic-gate errcode_t retval = 0;
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate retval = ENOMEM;
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate new_file = old_file = 0;
417*7934SMark.Phalan@Sun.COM new_file = malloc(strlen(outfile) + 5);
4180Sstevel@tonic-gate if (!new_file)
4190Sstevel@tonic-gate goto errout;
420*7934SMark.Phalan@Sun.COM old_file = malloc(strlen(outfile) + 5);
4210Sstevel@tonic-gate if (!old_file)
4220Sstevel@tonic-gate goto errout;
4230Sstevel@tonic-gate
424781Sgtb sprintf(new_file, "%s.$$$", outfile);
425781Sgtb sprintf(old_file, "%s.bak", outfile);
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate errno = 0;
4280Sstevel@tonic-gate
429*7934SMark.Phalan@Sun.COM /* Solaris Kerberos */
4301914Scasper f = fopen(new_file, "wF");
4310Sstevel@tonic-gate if (!f) {
4320Sstevel@tonic-gate retval = errno;
4330Sstevel@tonic-gate if (retval == 0)
4340Sstevel@tonic-gate retval = PROF_FAIL_OPEN;
4350Sstevel@tonic-gate goto errout;
4360Sstevel@tonic-gate }
4370Sstevel@tonic-gate
438781Sgtb profile_write_tree_file(data->root, f);
4390Sstevel@tonic-gate if (fclose(f) != 0) {
4400Sstevel@tonic-gate retval = errno;
4410Sstevel@tonic-gate goto errout;
4420Sstevel@tonic-gate }
4430Sstevel@tonic-gate
4440Sstevel@tonic-gate unlink(old_file);
445781Sgtb if (make_hard_link(outfile, old_file) == 0) {
446781Sgtb /* Okay, got the hard link. Yay. Now we've got our
447781Sgtb backup version, so just put the new version in
448781Sgtb place. */
449781Sgtb if (rename(new_file, outfile)) {
450781Sgtb /* Weird, the rename didn't work. But the old version
451781Sgtb should still be in place, so no special cleanup is
452781Sgtb needed. */
453781Sgtb retval = errno;
454781Sgtb goto errout;
455781Sgtb }
456781Sgtb } else if (errno == ENOENT && can_create) {
457781Sgtb if (rename(new_file, outfile)) {
4580Sstevel@tonic-gate retval = errno;
4590Sstevel@tonic-gate goto errout;
460781Sgtb }
461781Sgtb } else {
462781Sgtb /* Couldn't make the hard link, so there's going to be a
463781Sgtb small window where data->filespec does not refer to
464781Sgtb either version. */
465781Sgtb #ifndef _WIN32
466781Sgtb sync();
467781Sgtb #endif
468781Sgtb if (rename(outfile, old_file)) {
4690Sstevel@tonic-gate retval = errno;
4700Sstevel@tonic-gate goto errout;
471781Sgtb }
472781Sgtb if (rename(new_file, outfile)) {
473781Sgtb retval = errno;
474781Sgtb rename(old_file, outfile); /* back out... */
475781Sgtb goto errout;
476781Sgtb }
4770Sstevel@tonic-gate }
4780Sstevel@tonic-gate
479781Sgtb data->flags = 0;
480781Sgtb if (rw_access(outfile))
481781Sgtb data->flags |= PROFILE_FILE_RW;
482781Sgtb retval = 0;
4830Sstevel@tonic-gate
4840Sstevel@tonic-gate errout:
4850Sstevel@tonic-gate if (new_file)
4860Sstevel@tonic-gate free(new_file);
4870Sstevel@tonic-gate if (old_file)
4880Sstevel@tonic-gate free(old_file);
489781Sgtb return retval;
490781Sgtb }
491781Sgtb
profile_flush_file_data_to_buffer(prf_data_t data,char ** bufp)492781Sgtb errcode_t profile_flush_file_data_to_buffer (prf_data_t data, char **bufp)
493781Sgtb {
494781Sgtb errcode_t retval;
495781Sgtb retval = k5_mutex_lock(&data->lock);
496781Sgtb if (retval)
497781Sgtb return retval;
498781Sgtb retval = profile_write_tree_to_buffer(data->root, bufp);
499781Sgtb k5_mutex_unlock(&data->lock);
5000Sstevel@tonic-gate return retval;
5010Sstevel@tonic-gate }
5020Sstevel@tonic-gate
profile_flush_file_data(prf_data_t data)503781Sgtb errcode_t profile_flush_file_data(prf_data_t data)
504781Sgtb {
505781Sgtb errcode_t retval = 0;
506781Sgtb
507781Sgtb if (!data || data->magic != PROF_MAGIC_FILE_DATA)
508781Sgtb return PROF_MAGIC_FILE_DATA;
509781Sgtb
510781Sgtb retval = k5_mutex_lock(&data->lock);
511781Sgtb if (retval)
512781Sgtb return retval;
513781Sgtb
514781Sgtb if ((data->flags & PROFILE_FILE_DIRTY) == 0) {
515781Sgtb k5_mutex_unlock(&data->lock);
516781Sgtb return 0;
517781Sgtb }
518781Sgtb
519781Sgtb retval = write_data_to_file(data, data->filespec, 0);
520781Sgtb k5_mutex_unlock(&data->lock);
521781Sgtb return retval;
522781Sgtb }
523781Sgtb
profile_flush_file_data_to_file(prf_data_t data,const char * outfile)524781Sgtb errcode_t profile_flush_file_data_to_file(prf_data_t data, const char *outfile)
525781Sgtb {
526781Sgtb errcode_t retval = 0;
527781Sgtb
528781Sgtb if (!data || data->magic != PROF_MAGIC_FILE_DATA)
529781Sgtb return PROF_MAGIC_FILE_DATA;
530781Sgtb
531781Sgtb retval = k5_mutex_lock(&data->lock);
532781Sgtb if (retval)
533781Sgtb return retval;
534781Sgtb retval = write_data_to_file(data, outfile, 1);
535781Sgtb k5_mutex_unlock(&data->lock);
536781Sgtb return retval;
537781Sgtb }
538781Sgtb
5390Sstevel@tonic-gate
540781Sgtb
profile_dereference_data(prf_data_t data)541781Sgtb void profile_dereference_data(prf_data_t data)
542781Sgtb {
543781Sgtb int err;
544781Sgtb err = k5_mutex_lock(&g_shared_trees_mutex);
545781Sgtb if (err)
546781Sgtb return;
547781Sgtb profile_dereference_data_locked(data);
548781Sgtb (void) k5_mutex_unlock(&g_shared_trees_mutex);
549781Sgtb }
profile_dereference_data_locked(prf_data_t data)550781Sgtb void profile_dereference_data_locked(prf_data_t data)
5510Sstevel@tonic-gate {
552*7934SMark.Phalan@Sun.COM scan_shared_trees_locked();
553781Sgtb data->refcount--;
554781Sgtb if (data->refcount == 0)
555781Sgtb profile_free_file_data(data);
556*7934SMark.Phalan@Sun.COM scan_shared_trees_locked();
557781Sgtb }
5580Sstevel@tonic-gate
profile_lock_global()559781Sgtb int profile_lock_global()
560781Sgtb {
561781Sgtb return k5_mutex_lock(&g_shared_trees_mutex);
562781Sgtb }
profile_unlock_global()563781Sgtb int profile_unlock_global()
564781Sgtb {
565781Sgtb return k5_mutex_unlock(&g_shared_trees_mutex);
566781Sgtb }
567781Sgtb
profile_free_file(prf_file_t prf)568781Sgtb void profile_free_file(prf_file_t prf)
569781Sgtb {
570781Sgtb profile_dereference_data(prf->data);
571781Sgtb free(prf);
5720Sstevel@tonic-gate }
5730Sstevel@tonic-gate
574781Sgtb /* Call with mutex locked! */
profile_free_file_data(prf_data_t data)575781Sgtb static void profile_free_file_data(prf_data_t data)
576781Sgtb {
577781Sgtb scan_shared_trees_locked();
578781Sgtb if (data->flags & PROFILE_FILE_SHARED) {
579781Sgtb /* Remove from linked list. */
580781Sgtb if (g_shared_trees == data)
581781Sgtb g_shared_trees = data->next;
582781Sgtb else {
583781Sgtb prf_data_t prev, next;
584781Sgtb prev = g_shared_trees;
585781Sgtb next = prev->next;
586781Sgtb while (next) {
587781Sgtb if (next == data) {
588781Sgtb prev->next = next->next;
589781Sgtb break;
590781Sgtb }
591781Sgtb prev = next;
592781Sgtb next = next->next;
593781Sgtb }
594781Sgtb }
595781Sgtb }
596781Sgtb if (data->root)
597781Sgtb profile_free_node(data->root);
598781Sgtb if (data->comment)
599781Sgtb free(data->comment);
600781Sgtb data->magic = 0;
601781Sgtb k5_mutex_destroy(&data->lock);
602781Sgtb free(data);
603781Sgtb scan_shared_trees_locked();
604781Sgtb }
605781Sgtb
profile_close_file(prf_file_t prf)606781Sgtb errcode_t profile_close_file(prf_file_t prf)
6070Sstevel@tonic-gate {
6080Sstevel@tonic-gate errcode_t retval;
6090Sstevel@tonic-gate
6100Sstevel@tonic-gate retval = profile_flush_file(prf);
6110Sstevel@tonic-gate if (retval)
6120Sstevel@tonic-gate return retval;
6130Sstevel@tonic-gate profile_free_file(prf);
6140Sstevel@tonic-gate return 0;
6150Sstevel@tonic-gate }
616