1004388ebScasper /* 2*159d09a2SMark Phalan * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 3004388ebScasper * Use is subject to license terms. 4004388ebScasper */ 57c478bd9Sstevel@tonic-gate /* 67c478bd9Sstevel@tonic-gate * prof_file.c ---- routines that manipulate an individual profile file. 77c478bd9Sstevel@tonic-gate */ 87c478bd9Sstevel@tonic-gate 97c478bd9Sstevel@tonic-gate #include <autoconf.h> 10505d05c7Sgtb #include "prof_int.h" 117c478bd9Sstevel@tonic-gate 127c478bd9Sstevel@tonic-gate #include <stdio.h> 137c478bd9Sstevel@tonic-gate #ifdef HAVE_STDLIB_H 147c478bd9Sstevel@tonic-gate #include <stdlib.h> 157c478bd9Sstevel@tonic-gate #endif 167c478bd9Sstevel@tonic-gate #ifdef HAVE_UNISTD_H 177c478bd9Sstevel@tonic-gate #include <unistd.h> 187c478bd9Sstevel@tonic-gate #endif 197c478bd9Sstevel@tonic-gate #include <string.h> 20505d05c7Sgtb #include <stddef.h> 217c478bd9Sstevel@tonic-gate 227c478bd9Sstevel@tonic-gate #include <sys/types.h> 237c478bd9Sstevel@tonic-gate #include <sys/stat.h> 247c478bd9Sstevel@tonic-gate #include <errno.h> 257c478bd9Sstevel@tonic-gate 26505d05c7Sgtb #ifdef HAVE_PWD_H 27505d05c7Sgtb #include <pwd.h> 28505d05c7Sgtb #endif 297c478bd9Sstevel@tonic-gate 30505d05c7Sgtb #if defined(_WIN32) 317c478bd9Sstevel@tonic-gate #include <io.h> 327c478bd9Sstevel@tonic-gate #define HAVE_STAT 337c478bd9Sstevel@tonic-gate #define stat _stat 347c478bd9Sstevel@tonic-gate #endif 357c478bd9Sstevel@tonic-gate 36505d05c7Sgtb #include "k5-platform.h" 37505d05c7Sgtb 38505d05c7Sgtb struct global_shared_profile_data { 39505d05c7Sgtb /* This is the head of the global list of shared trees */ 40505d05c7Sgtb prf_data_t trees; 41505d05c7Sgtb /* Lock for above list. */ 42505d05c7Sgtb k5_mutex_t mutex; 43505d05c7Sgtb }; 44505d05c7Sgtb #define g_shared_trees (krb5int_profile_shared_data.trees) 45505d05c7Sgtb #define g_shared_trees_mutex (krb5int_profile_shared_data.mutex) 46505d05c7Sgtb 47505d05c7Sgtb static struct global_shared_profile_data krb5int_profile_shared_data = { 48505d05c7Sgtb 0, 49505d05c7Sgtb K5_MUTEX_PARTIAL_INITIALIZER 50505d05c7Sgtb }; 51505d05c7Sgtb 52505d05c7Sgtb MAKE_INIT_FUNCTION(profile_library_initializer); 53505d05c7Sgtb MAKE_FINI_FUNCTION(profile_library_finalizer); 54505d05c7Sgtb 55505d05c7Sgtb int profile_library_initializer(void) 56505d05c7Sgtb { 57*159d09a2SMark Phalan #ifdef SHOW_INITFINI_FUNCS 58*159d09a2SMark Phalan printf("profile_library_initializer\n"); 59*159d09a2SMark Phalan #endif 60505d05c7Sgtb #if !USE_BUNDLE_ERROR_STRINGS 61505d05c7Sgtb add_error_table(&et_prof_error_table); 62505d05c7Sgtb #endif 63505d05c7Sgtb return k5_mutex_finish_init(&g_shared_trees_mutex); 64505d05c7Sgtb } 65505d05c7Sgtb void profile_library_finalizer(void) 66505d05c7Sgtb { 67*159d09a2SMark Phalan if (! INITIALIZER_RAN(profile_library_initializer) || PROGRAM_EXITING()) { 68*159d09a2SMark Phalan #ifdef SHOW_INITFINI_FUNCS 69*159d09a2SMark Phalan printf("profile_library_finalizer: skipping\n"); 70*159d09a2SMark Phalan #endif 71505d05c7Sgtb return; 72*159d09a2SMark Phalan } 73*159d09a2SMark Phalan #ifdef SHOW_INITFINI_FUNCS 74*159d09a2SMark Phalan printf("profile_library_finalizer\n"); 75*159d09a2SMark Phalan #endif 76505d05c7Sgtb k5_mutex_destroy(&g_shared_trees_mutex); 77505d05c7Sgtb #if !USE_BUNDLE_ERROR_STRINGS 78505d05c7Sgtb remove_error_table(&et_prof_error_table); 79505d05c7Sgtb #endif 80505d05c7Sgtb } 81505d05c7Sgtb 82505d05c7Sgtb static void profile_free_file_data(prf_data_t); 83505d05c7Sgtb 84505d05c7Sgtb #if 0 85505d05c7Sgtb 86505d05c7Sgtb #define scan_shared_trees_locked() \ 87505d05c7Sgtb { \ 88505d05c7Sgtb prf_data_t d; \ 89505d05c7Sgtb k5_mutex_assert_locked(&g_shared_trees_mutex); \ 90505d05c7Sgtb for (d = g_shared_trees; d; d = d->next) { \ 91505d05c7Sgtb assert(d->magic == PROF_MAGIC_FILE_DATA); \ 92505d05c7Sgtb assert((d->flags & PROFILE_FILE_SHARED) != 0); \ 93505d05c7Sgtb assert(d->filespec[0] != 0); \ 94505d05c7Sgtb assert(d->fslen <= 1000); /* XXX */ \ 95505d05c7Sgtb assert(d->filespec[d->fslen] == 0); \ 96505d05c7Sgtb assert(d->fslen = strlen(d->filespec)); \ 97*159d09a2SMark Phalan assert(d->root != NULL); \ 98505d05c7Sgtb } \ 99505d05c7Sgtb } 100505d05c7Sgtb 101505d05c7Sgtb #define scan_shared_trees_unlocked() \ 102505d05c7Sgtb { \ 103505d05c7Sgtb int r; \ 104505d05c7Sgtb r = k5_mutex_lock(&g_shared_trees_mutex); \ 105505d05c7Sgtb assert (r == 0); \ 106505d05c7Sgtb scan_shared_trees_locked(); \ 107505d05c7Sgtb k5_mutex_unlock(&g_shared_trees_mutex); \ 108505d05c7Sgtb } 109505d05c7Sgtb 110505d05c7Sgtb #else 1117c478bd9Sstevel@tonic-gate 112505d05c7Sgtb #define scan_shared_trees_locked() { ; } 113505d05c7Sgtb #define scan_shared_trees_unlocked() { ; } 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate #endif 1167c478bd9Sstevel@tonic-gate 117505d05c7Sgtb static int rw_access(const_profile_filespec_t filespec) 1187c478bd9Sstevel@tonic-gate { 1197c478bd9Sstevel@tonic-gate #ifdef HAVE_ACCESS 1207c478bd9Sstevel@tonic-gate if (access(filespec, W_OK) == 0) 1217c478bd9Sstevel@tonic-gate return 1; 1227c478bd9Sstevel@tonic-gate else 1237c478bd9Sstevel@tonic-gate return 0; 1247c478bd9Sstevel@tonic-gate #else 1257c478bd9Sstevel@tonic-gate /* 1267c478bd9Sstevel@tonic-gate * We're on a substandard OS that doesn't support access. So 1277c478bd9Sstevel@tonic-gate * we kludge a test using stdio routines, and hope fopen 1287c478bd9Sstevel@tonic-gate * checks the r/w permissions. 1297c478bd9Sstevel@tonic-gate */ 1307c478bd9Sstevel@tonic-gate FILE *f; 131*159d09a2SMark Phalan /* Solaris Kerberos */ 132004388ebScasper f = fopen(filespec, "r+F"); 133505d05c7Sgtb if (f) { 134505d05c7Sgtb fclose(f); 135505d05c7Sgtb return 1; 136505d05c7Sgtb } 137505d05c7Sgtb return 0; 1387c478bd9Sstevel@tonic-gate #endif 139505d05c7Sgtb } 140505d05c7Sgtb 141505d05c7Sgtb static int r_access(const_profile_filespec_t filespec) 142505d05c7Sgtb { 143505d05c7Sgtb #ifdef HAVE_ACCESS 144505d05c7Sgtb if (access(filespec, R_OK) == 0) 145505d05c7Sgtb return 1; 146505d05c7Sgtb else 147505d05c7Sgtb return 0; 148505d05c7Sgtb #else 149505d05c7Sgtb /* 150505d05c7Sgtb * We're on a substandard OS that doesn't support access. So 151505d05c7Sgtb * we kludge a test using stdio routines, and hope fopen 152505d05c7Sgtb * checks the r/w permissions. 153505d05c7Sgtb */ 154505d05c7Sgtb FILE *f; 155505d05c7Sgtb 156*159d09a2SMark Phalan /* Solaris Kerberos */ 157004388ebScasper f = fopen(filespec, "rF"); 1587c478bd9Sstevel@tonic-gate if (f) { 1597c478bd9Sstevel@tonic-gate fclose(f); 1607c478bd9Sstevel@tonic-gate return 1; 1617c478bd9Sstevel@tonic-gate } 1627c478bd9Sstevel@tonic-gate return 0; 1637c478bd9Sstevel@tonic-gate #endif 1647c478bd9Sstevel@tonic-gate } 1657c478bd9Sstevel@tonic-gate 166505d05c7Sgtb prf_data_t 167505d05c7Sgtb profile_make_prf_data(const char *filename) 168505d05c7Sgtb { 169505d05c7Sgtb prf_data_t d; 170505d05c7Sgtb size_t len, flen, slen; 171505d05c7Sgtb char *fcopy; 172505d05c7Sgtb 173505d05c7Sgtb flen = strlen(filename); 174505d05c7Sgtb slen = offsetof(struct _prf_data_t, filespec); 175505d05c7Sgtb len = slen + flen + 1; 176505d05c7Sgtb if (len < sizeof(struct _prf_data_t)) 177505d05c7Sgtb len = sizeof(struct _prf_data_t); 178505d05c7Sgtb d = malloc(len); 179505d05c7Sgtb if (d == NULL) 180505d05c7Sgtb return NULL; 181505d05c7Sgtb memset(d, 0, len); 182505d05c7Sgtb fcopy = (char *) d + slen; 183505d05c7Sgtb assert(fcopy == d->filespec); 184505d05c7Sgtb strcpy(fcopy, filename); 185505d05c7Sgtb d->refcount = 1; 186505d05c7Sgtb d->comment = NULL; 187505d05c7Sgtb d->magic = PROF_MAGIC_FILE_DATA; 188505d05c7Sgtb d->root = NULL; 189505d05c7Sgtb d->next = NULL; 190505d05c7Sgtb d->fslen = flen; 191505d05c7Sgtb return d; 192505d05c7Sgtb } 193505d05c7Sgtb 194505d05c7Sgtb errcode_t profile_open_file(const_profile_filespec_t filespec, 195505d05c7Sgtb prf_file_t *ret_prof) 1967c478bd9Sstevel@tonic-gate { 1977c478bd9Sstevel@tonic-gate prf_file_t prf; 1987c478bd9Sstevel@tonic-gate errcode_t retval; 1997c478bd9Sstevel@tonic-gate char *home_env = 0; 200505d05c7Sgtb unsigned int len; 201505d05c7Sgtb prf_data_t data; 202505d05c7Sgtb char *expanded_filename; 203505d05c7Sgtb 204505d05c7Sgtb retval = CALL_INIT_FUNCTION(profile_library_initializer); 205505d05c7Sgtb if (retval) 206505d05c7Sgtb return retval; 207505d05c7Sgtb 208505d05c7Sgtb scan_shared_trees_unlocked(); 2097c478bd9Sstevel@tonic-gate 210*159d09a2SMark Phalan prf = malloc(sizeof(struct _prf_file_t)); 2117c478bd9Sstevel@tonic-gate if (!prf) 2127c478bd9Sstevel@tonic-gate return ENOMEM; 2137c478bd9Sstevel@tonic-gate memset(prf, 0, sizeof(struct _prf_file_t)); 214505d05c7Sgtb prf->magic = PROF_MAGIC_FILE; 215505d05c7Sgtb 2167c478bd9Sstevel@tonic-gate len = strlen(filespec)+1; 2177c478bd9Sstevel@tonic-gate if (filespec[0] == '~' && filespec[1] == '/') { 2187c478bd9Sstevel@tonic-gate home_env = getenv("HOME"); 219505d05c7Sgtb #ifdef HAVE_PWD_H 220505d05c7Sgtb if (home_env == NULL) { 221505d05c7Sgtb uid_t uid; 222*159d09a2SMark Phalan struct passwd *pw, pwx; 223505d05c7Sgtb char pwbuf[BUFSIZ]; 224505d05c7Sgtb 225505d05c7Sgtb uid = getuid(); 226*159d09a2SMark Phalan if (!k5_getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw) 227*159d09a2SMark Phalan && pw != NULL && pw->pw_dir[0] != 0) 228505d05c7Sgtb home_env = pw->pw_dir; 229505d05c7Sgtb } 230505d05c7Sgtb #endif 2317c478bd9Sstevel@tonic-gate if (home_env) 2327c478bd9Sstevel@tonic-gate len += strlen(home_env); 2337c478bd9Sstevel@tonic-gate } 234505d05c7Sgtb expanded_filename = malloc(len); 235505d05c7Sgtb if (expanded_filename == 0) 236505d05c7Sgtb return errno; 2377c478bd9Sstevel@tonic-gate if (home_env) { 238505d05c7Sgtb strcpy(expanded_filename, home_env); 239505d05c7Sgtb strcat(expanded_filename, filespec+1); 2407c478bd9Sstevel@tonic-gate } else 241505d05c7Sgtb memcpy(expanded_filename, filespec, len); 242505d05c7Sgtb 243505d05c7Sgtb retval = k5_mutex_lock(&g_shared_trees_mutex); 244505d05c7Sgtb if (retval) { 245505d05c7Sgtb free(expanded_filename); 246505d05c7Sgtb free(prf); 247505d05c7Sgtb scan_shared_trees_unlocked(); 248505d05c7Sgtb return retval; 249505d05c7Sgtb } 250505d05c7Sgtb scan_shared_trees_locked(); 251505d05c7Sgtb for (data = g_shared_trees; data; data = data->next) { 252505d05c7Sgtb if (!strcmp(data->filespec, expanded_filename) 253505d05c7Sgtb /* Check that current uid has read access. */ 254505d05c7Sgtb && r_access(data->filespec)) 255505d05c7Sgtb break; 256505d05c7Sgtb } 257505d05c7Sgtb if (data) { 258505d05c7Sgtb data->refcount++; 259505d05c7Sgtb (void) k5_mutex_unlock(&g_shared_trees_mutex); 260*159d09a2SMark Phalan retval = profile_update_file_data(data); 261505d05c7Sgtb free(expanded_filename); 262505d05c7Sgtb prf->data = data; 263505d05c7Sgtb *ret_prof = prf; 264505d05c7Sgtb scan_shared_trees_unlocked(); 265505d05c7Sgtb return retval; 266505d05c7Sgtb } 267505d05c7Sgtb (void) k5_mutex_unlock(&g_shared_trees_mutex); 268505d05c7Sgtb data = profile_make_prf_data(expanded_filename); 269505d05c7Sgtb if (data == NULL) { 270505d05c7Sgtb free(prf); 271505d05c7Sgtb free(expanded_filename); 272505d05c7Sgtb return ENOMEM; 273505d05c7Sgtb } 274505d05c7Sgtb free(expanded_filename); 275505d05c7Sgtb prf->data = data; 276505d05c7Sgtb 277505d05c7Sgtb retval = k5_mutex_init(&data->lock); 278505d05c7Sgtb if (retval) { 279505d05c7Sgtb free(data); 280505d05c7Sgtb free(prf); 281505d05c7Sgtb return retval; 282505d05c7Sgtb } 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate retval = profile_update_file(prf); 2857c478bd9Sstevel@tonic-gate if (retval) { 2867c478bd9Sstevel@tonic-gate profile_close_file(prf); 2877c478bd9Sstevel@tonic-gate return retval; 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 290505d05c7Sgtb retval = k5_mutex_lock(&g_shared_trees_mutex); 291505d05c7Sgtb if (retval) { 292505d05c7Sgtb profile_close_file(prf); 293505d05c7Sgtb scan_shared_trees_unlocked(); 294505d05c7Sgtb return retval; 295505d05c7Sgtb } 296505d05c7Sgtb scan_shared_trees_locked(); 297505d05c7Sgtb data->flags |= PROFILE_FILE_SHARED; 298505d05c7Sgtb data->next = g_shared_trees; 299505d05c7Sgtb g_shared_trees = data; 300505d05c7Sgtb scan_shared_trees_locked(); 301505d05c7Sgtb (void) k5_mutex_unlock(&g_shared_trees_mutex); 302505d05c7Sgtb 3037c478bd9Sstevel@tonic-gate *ret_prof = prf; 3047c478bd9Sstevel@tonic-gate return 0; 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 307505d05c7Sgtb errcode_t profile_update_file_data(prf_data_t data) 3087c478bd9Sstevel@tonic-gate { 3097c478bd9Sstevel@tonic-gate errcode_t retval; 3107c478bd9Sstevel@tonic-gate #ifdef HAVE_STAT 3117c478bd9Sstevel@tonic-gate struct stat st; 312*159d09a2SMark Phalan unsigned long frac; 313505d05c7Sgtb time_t now; 3147c478bd9Sstevel@tonic-gate #endif 3157c478bd9Sstevel@tonic-gate FILE *f; 3167c478bd9Sstevel@tonic-gate 317505d05c7Sgtb retval = k5_mutex_lock(&data->lock); 318505d05c7Sgtb if (retval) 319505d05c7Sgtb return retval; 320505d05c7Sgtb 3217c478bd9Sstevel@tonic-gate #ifdef HAVE_STAT 322505d05c7Sgtb now = time(0); 323*159d09a2SMark Phalan if (now == data->last_stat && data->root != NULL) { 324505d05c7Sgtb k5_mutex_unlock(&data->lock); 325505d05c7Sgtb return 0; 3267c478bd9Sstevel@tonic-gate } 327505d05c7Sgtb if (stat(data->filespec, &st)) { 328505d05c7Sgtb retval = errno; 329505d05c7Sgtb k5_mutex_unlock(&data->lock); 330505d05c7Sgtb return retval; 331505d05c7Sgtb } 332505d05c7Sgtb data->last_stat = now; 333*159d09a2SMark Phalan #if defined HAVE_STRUCT_STAT_ST_MTIMENSEC 334*159d09a2SMark Phalan frac = st.st_mtimensec; 335*159d09a2SMark Phalan #elif defined HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 336*159d09a2SMark Phalan frac = st.st_mtimespec.tv_nsec; 337*159d09a2SMark Phalan #elif defined HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 338*159d09a2SMark Phalan frac = st.st_mtim.tv_nsec; 339*159d09a2SMark Phalan #else 340*159d09a2SMark Phalan frac = 0; 341505d05c7Sgtb #endif 342*159d09a2SMark Phalan if (st.st_mtime == data->timestamp 343*159d09a2SMark Phalan && frac == data->frac_ts 344*159d09a2SMark Phalan && data->root != NULL) { 345505d05c7Sgtb k5_mutex_unlock(&data->lock); 346505d05c7Sgtb return 0; 347505d05c7Sgtb } 348505d05c7Sgtb if (data->root) { 349505d05c7Sgtb profile_free_node(data->root); 350505d05c7Sgtb data->root = 0; 351505d05c7Sgtb } 352505d05c7Sgtb if (data->comment) { 353505d05c7Sgtb free(data->comment); 354505d05c7Sgtb data->comment = 0; 3557c478bd9Sstevel@tonic-gate } 3567c478bd9Sstevel@tonic-gate #else 3577c478bd9Sstevel@tonic-gate /* 3587c478bd9Sstevel@tonic-gate * If we don't have the stat() call, assume that our in-core 3597c478bd9Sstevel@tonic-gate * memory image is correct. That is, we won't reread the 3607c478bd9Sstevel@tonic-gate * profile file if it changes. 3617c478bd9Sstevel@tonic-gate */ 362505d05c7Sgtb if (data->root) { 363505d05c7Sgtb k5_mutex_unlock(&data->lock); 364505d05c7Sgtb return 0; 365505d05c7Sgtb } 3667c478bd9Sstevel@tonic-gate #endif 3677c478bd9Sstevel@tonic-gate errno = 0; 368*159d09a2SMark Phalan /* Solaris Kerberos */ 369004388ebScasper f = fopen(data->filespec, "rF"); 3707c478bd9Sstevel@tonic-gate if (f == NULL) { 3717c478bd9Sstevel@tonic-gate retval = errno; 372505d05c7Sgtb k5_mutex_unlock(&data->lock); 3737c478bd9Sstevel@tonic-gate if (retval == 0) 3747c478bd9Sstevel@tonic-gate retval = ENOENT; 3757c478bd9Sstevel@tonic-gate return retval; 3767c478bd9Sstevel@tonic-gate } 377505d05c7Sgtb data->upd_serial++; 378505d05c7Sgtb data->flags &= PROFILE_FILE_SHARED; 379505d05c7Sgtb if (rw_access(data->filespec)) 380505d05c7Sgtb data->flags |= PROFILE_FILE_RW; 381505d05c7Sgtb retval = profile_parse_file(f, &data->root); 3827c478bd9Sstevel@tonic-gate fclose(f); 383505d05c7Sgtb if (retval) { 384505d05c7Sgtb k5_mutex_unlock(&data->lock); 385505d05c7Sgtb return retval; 386505d05c7Sgtb } 387*159d09a2SMark Phalan assert(data->root != NULL); 3887c478bd9Sstevel@tonic-gate #ifdef HAVE_STAT 389505d05c7Sgtb data->timestamp = st.st_mtime; 390*159d09a2SMark Phalan data->frac_ts = frac; 3917c478bd9Sstevel@tonic-gate #endif 392505d05c7Sgtb k5_mutex_unlock(&data->lock); 3937c478bd9Sstevel@tonic-gate return 0; 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 396505d05c7Sgtb static int 397505d05c7Sgtb make_hard_link(const char *oldpath, const char *newpath) 3987c478bd9Sstevel@tonic-gate { 399505d05c7Sgtb #ifdef _WIN32 400505d05c7Sgtb return -1; 401505d05c7Sgtb #else 402505d05c7Sgtb return link(oldpath, newpath); 4037c478bd9Sstevel@tonic-gate #endif 404505d05c7Sgtb } 4057c478bd9Sstevel@tonic-gate 406505d05c7Sgtb static errcode_t write_data_to_file(prf_data_t data, const char *outfile, 407505d05c7Sgtb int can_create) 4087c478bd9Sstevel@tonic-gate { 4097c478bd9Sstevel@tonic-gate FILE *f; 4107c478bd9Sstevel@tonic-gate profile_filespec_t new_file; 4117c478bd9Sstevel@tonic-gate profile_filespec_t old_file; 4127c478bd9Sstevel@tonic-gate errcode_t retval = 0; 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate retval = ENOMEM; 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate new_file = old_file = 0; 417*159d09a2SMark Phalan new_file = malloc(strlen(outfile) + 5); 4187c478bd9Sstevel@tonic-gate if (!new_file) 4197c478bd9Sstevel@tonic-gate goto errout; 420*159d09a2SMark Phalan old_file = malloc(strlen(outfile) + 5); 4217c478bd9Sstevel@tonic-gate if (!old_file) 4227c478bd9Sstevel@tonic-gate goto errout; 4237c478bd9Sstevel@tonic-gate 424505d05c7Sgtb sprintf(new_file, "%s.$$$", outfile); 425505d05c7Sgtb sprintf(old_file, "%s.bak", outfile); 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate errno = 0; 4287c478bd9Sstevel@tonic-gate 429*159d09a2SMark Phalan /* Solaris Kerberos */ 430004388ebScasper f = fopen(new_file, "wF"); 4317c478bd9Sstevel@tonic-gate if (!f) { 4327c478bd9Sstevel@tonic-gate retval = errno; 4337c478bd9Sstevel@tonic-gate if (retval == 0) 4347c478bd9Sstevel@tonic-gate retval = PROF_FAIL_OPEN; 4357c478bd9Sstevel@tonic-gate goto errout; 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate 438505d05c7Sgtb profile_write_tree_file(data->root, f); 4397c478bd9Sstevel@tonic-gate if (fclose(f) != 0) { 4407c478bd9Sstevel@tonic-gate retval = errno; 4417c478bd9Sstevel@tonic-gate goto errout; 4427c478bd9Sstevel@tonic-gate } 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate unlink(old_file); 445505d05c7Sgtb if (make_hard_link(outfile, old_file) == 0) { 446505d05c7Sgtb /* Okay, got the hard link. Yay. Now we've got our 447505d05c7Sgtb backup version, so just put the new version in 448505d05c7Sgtb place. */ 449505d05c7Sgtb if (rename(new_file, outfile)) { 450505d05c7Sgtb /* Weird, the rename didn't work. But the old version 451505d05c7Sgtb should still be in place, so no special cleanup is 452505d05c7Sgtb needed. */ 4537c478bd9Sstevel@tonic-gate retval = errno; 4547c478bd9Sstevel@tonic-gate goto errout; 455505d05c7Sgtb } 456505d05c7Sgtb } else if (errno == ENOENT && can_create) { 457505d05c7Sgtb if (rename(new_file, outfile)) { 4587c478bd9Sstevel@tonic-gate retval = errno; 4597c478bd9Sstevel@tonic-gate goto errout; 460505d05c7Sgtb } 461505d05c7Sgtb } else { 462505d05c7Sgtb /* Couldn't make the hard link, so there's going to be a 463505d05c7Sgtb small window where data->filespec does not refer to 464505d05c7Sgtb either version. */ 465505d05c7Sgtb #ifndef _WIN32 466505d05c7Sgtb sync(); 4677c478bd9Sstevel@tonic-gate #endif 468505d05c7Sgtb if (rename(outfile, old_file)) { 469505d05c7Sgtb retval = errno; 470505d05c7Sgtb goto errout; 471505d05c7Sgtb } 472505d05c7Sgtb if (rename(new_file, outfile)) { 473505d05c7Sgtb retval = errno; 474505d05c7Sgtb rename(old_file, outfile); /* back out... */ 475505d05c7Sgtb goto errout; 476505d05c7Sgtb } 477505d05c7Sgtb } 4787c478bd9Sstevel@tonic-gate 479505d05c7Sgtb data->flags = 0; 480505d05c7Sgtb if (rw_access(outfile)) 481505d05c7Sgtb data->flags |= PROFILE_FILE_RW; 4827c478bd9Sstevel@tonic-gate retval = 0; 483505d05c7Sgtb 4847c478bd9Sstevel@tonic-gate errout: 4857c478bd9Sstevel@tonic-gate if (new_file) 4867c478bd9Sstevel@tonic-gate free(new_file); 4877c478bd9Sstevel@tonic-gate if (old_file) 4887c478bd9Sstevel@tonic-gate free(old_file); 4897c478bd9Sstevel@tonic-gate return retval; 4907c478bd9Sstevel@tonic-gate } 4917c478bd9Sstevel@tonic-gate 492505d05c7Sgtb errcode_t profile_flush_file_data_to_buffer (prf_data_t data, char **bufp) 493505d05c7Sgtb { 494505d05c7Sgtb errcode_t retval; 495505d05c7Sgtb retval = k5_mutex_lock(&data->lock); 496505d05c7Sgtb if (retval) 497505d05c7Sgtb return retval; 498505d05c7Sgtb retval = profile_write_tree_to_buffer(data->root, bufp); 499505d05c7Sgtb k5_mutex_unlock(&data->lock); 500505d05c7Sgtb return retval; 501505d05c7Sgtb } 5027c478bd9Sstevel@tonic-gate 503505d05c7Sgtb errcode_t profile_flush_file_data(prf_data_t data) 5047c478bd9Sstevel@tonic-gate { 505505d05c7Sgtb errcode_t retval = 0; 506505d05c7Sgtb 507505d05c7Sgtb if (!data || data->magic != PROF_MAGIC_FILE_DATA) 508505d05c7Sgtb return PROF_MAGIC_FILE_DATA; 509505d05c7Sgtb 510505d05c7Sgtb retval = k5_mutex_lock(&data->lock); 511505d05c7Sgtb if (retval) 512505d05c7Sgtb return retval; 513505d05c7Sgtb 514505d05c7Sgtb if ((data->flags & PROFILE_FILE_DIRTY) == 0) { 515505d05c7Sgtb k5_mutex_unlock(&data->lock); 516505d05c7Sgtb return 0; 517505d05c7Sgtb } 518505d05c7Sgtb 519505d05c7Sgtb retval = write_data_to_file(data, data->filespec, 0); 520505d05c7Sgtb k5_mutex_unlock(&data->lock); 521505d05c7Sgtb return retval; 522505d05c7Sgtb } 523505d05c7Sgtb 524505d05c7Sgtb errcode_t profile_flush_file_data_to_file(prf_data_t data, const char *outfile) 525505d05c7Sgtb { 526505d05c7Sgtb errcode_t retval = 0; 527505d05c7Sgtb 528505d05c7Sgtb if (!data || data->magic != PROF_MAGIC_FILE_DATA) 529505d05c7Sgtb return PROF_MAGIC_FILE_DATA; 530505d05c7Sgtb 531505d05c7Sgtb retval = k5_mutex_lock(&data->lock); 532505d05c7Sgtb if (retval) 533505d05c7Sgtb return retval; 534505d05c7Sgtb retval = write_data_to_file(data, outfile, 1); 535505d05c7Sgtb k5_mutex_unlock(&data->lock); 536505d05c7Sgtb return retval; 537505d05c7Sgtb } 5387c478bd9Sstevel@tonic-gate 539505d05c7Sgtb 540505d05c7Sgtb 541505d05c7Sgtb void profile_dereference_data(prf_data_t data) 542505d05c7Sgtb { 543505d05c7Sgtb int err; 544505d05c7Sgtb err = k5_mutex_lock(&g_shared_trees_mutex); 545505d05c7Sgtb if (err) 5467c478bd9Sstevel@tonic-gate return; 547505d05c7Sgtb profile_dereference_data_locked(data); 548505d05c7Sgtb (void) k5_mutex_unlock(&g_shared_trees_mutex); 549505d05c7Sgtb } 550505d05c7Sgtb void profile_dereference_data_locked(prf_data_t data) 551505d05c7Sgtb { 552*159d09a2SMark Phalan scan_shared_trees_locked(); 553505d05c7Sgtb data->refcount--; 554505d05c7Sgtb if (data->refcount == 0) 555505d05c7Sgtb profile_free_file_data(data); 556*159d09a2SMark Phalan scan_shared_trees_locked(); 557505d05c7Sgtb } 558505d05c7Sgtb 559505d05c7Sgtb int profile_lock_global() 560505d05c7Sgtb { 561505d05c7Sgtb return k5_mutex_lock(&g_shared_trees_mutex); 562505d05c7Sgtb } 563505d05c7Sgtb int profile_unlock_global() 564505d05c7Sgtb { 565505d05c7Sgtb return k5_mutex_unlock(&g_shared_trees_mutex); 5667c478bd9Sstevel@tonic-gate } 5677c478bd9Sstevel@tonic-gate 568505d05c7Sgtb void profile_free_file(prf_file_t prf) 569505d05c7Sgtb { 570505d05c7Sgtb profile_dereference_data(prf->data); 571505d05c7Sgtb free(prf); 572505d05c7Sgtb } 573505d05c7Sgtb 574505d05c7Sgtb /* Call with mutex locked! */ 575505d05c7Sgtb static void profile_free_file_data(prf_data_t data) 576505d05c7Sgtb { 577505d05c7Sgtb scan_shared_trees_locked(); 578505d05c7Sgtb if (data->flags & PROFILE_FILE_SHARED) { 579505d05c7Sgtb /* Remove from linked list. */ 580505d05c7Sgtb if (g_shared_trees == data) 581505d05c7Sgtb g_shared_trees = data->next; 582505d05c7Sgtb else { 583505d05c7Sgtb prf_data_t prev, next; 584505d05c7Sgtb prev = g_shared_trees; 585505d05c7Sgtb next = prev->next; 586505d05c7Sgtb while (next) { 587505d05c7Sgtb if (next == data) { 588505d05c7Sgtb prev->next = next->next; 589505d05c7Sgtb break; 590505d05c7Sgtb } 591505d05c7Sgtb prev = next; 592505d05c7Sgtb next = next->next; 593505d05c7Sgtb } 594505d05c7Sgtb } 595505d05c7Sgtb } 596505d05c7Sgtb if (data->root) 597505d05c7Sgtb profile_free_node(data->root); 598505d05c7Sgtb if (data->comment) 599505d05c7Sgtb free(data->comment); 600505d05c7Sgtb data->magic = 0; 601505d05c7Sgtb k5_mutex_destroy(&data->lock); 602505d05c7Sgtb free(data); 603505d05c7Sgtb scan_shared_trees_locked(); 604505d05c7Sgtb } 605505d05c7Sgtb 606505d05c7Sgtb errcode_t profile_close_file(prf_file_t prf) 6077c478bd9Sstevel@tonic-gate { 6087c478bd9Sstevel@tonic-gate errcode_t retval; 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate retval = profile_flush_file(prf); 6117c478bd9Sstevel@tonic-gate if (retval) 6127c478bd9Sstevel@tonic-gate return retval; 6137c478bd9Sstevel@tonic-gate profile_free_file(prf); 6147c478bd9Sstevel@tonic-gate return 0; 6157c478bd9Sstevel@tonic-gate } 616