17c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 27c478bd9Sstevel@tonic-gate /* 37c478bd9Sstevel@tonic-gate * prof_file.c ---- routines that manipulate an individual profile file. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate #include <autoconf.h> 7*505d05c7Sgtb #include "prof_int.h" 87c478bd9Sstevel@tonic-gate 97c478bd9Sstevel@tonic-gate #include <stdio.h> 107c478bd9Sstevel@tonic-gate #ifdef HAVE_STDLIB_H 117c478bd9Sstevel@tonic-gate #include <stdlib.h> 127c478bd9Sstevel@tonic-gate #endif 137c478bd9Sstevel@tonic-gate #ifdef HAVE_UNISTD_H 147c478bd9Sstevel@tonic-gate #include <unistd.h> 157c478bd9Sstevel@tonic-gate #endif 167c478bd9Sstevel@tonic-gate #include <string.h> 17*505d05c7Sgtb #include <stddef.h> 187c478bd9Sstevel@tonic-gate 197c478bd9Sstevel@tonic-gate #include <sys/types.h> 207c478bd9Sstevel@tonic-gate #include <sys/stat.h> 217c478bd9Sstevel@tonic-gate #include <errno.h> 227c478bd9Sstevel@tonic-gate 23*505d05c7Sgtb #ifdef HAVE_PWD_H 24*505d05c7Sgtb #include <pwd.h> 25*505d05c7Sgtb #endif 267c478bd9Sstevel@tonic-gate 27*505d05c7Sgtb #if defined(_WIN32) 287c478bd9Sstevel@tonic-gate #include <io.h> 297c478bd9Sstevel@tonic-gate #define HAVE_STAT 307c478bd9Sstevel@tonic-gate #define stat _stat 317c478bd9Sstevel@tonic-gate #endif 327c478bd9Sstevel@tonic-gate 33*505d05c7Sgtb #include "k5-platform.h" 34*505d05c7Sgtb 35*505d05c7Sgtb struct global_shared_profile_data { 36*505d05c7Sgtb /* This is the head of the global list of shared trees */ 37*505d05c7Sgtb prf_data_t trees; 38*505d05c7Sgtb /* Lock for above list. */ 39*505d05c7Sgtb k5_mutex_t mutex; 40*505d05c7Sgtb }; 41*505d05c7Sgtb #define g_shared_trees (krb5int_profile_shared_data.trees) 42*505d05c7Sgtb #define g_shared_trees_mutex (krb5int_profile_shared_data.mutex) 43*505d05c7Sgtb 44*505d05c7Sgtb static struct global_shared_profile_data krb5int_profile_shared_data = { 45*505d05c7Sgtb 0, 46*505d05c7Sgtb K5_MUTEX_PARTIAL_INITIALIZER 47*505d05c7Sgtb }; 48*505d05c7Sgtb 49*505d05c7Sgtb MAKE_INIT_FUNCTION(profile_library_initializer); 50*505d05c7Sgtb MAKE_FINI_FUNCTION(profile_library_finalizer); 51*505d05c7Sgtb 52*505d05c7Sgtb int profile_library_initializer(void) 53*505d05c7Sgtb { 54*505d05c7Sgtb #if !USE_BUNDLE_ERROR_STRINGS 55*505d05c7Sgtb add_error_table(&et_prof_error_table); 56*505d05c7Sgtb #endif 57*505d05c7Sgtb return k5_mutex_finish_init(&g_shared_trees_mutex); 58*505d05c7Sgtb } 59*505d05c7Sgtb void profile_library_finalizer(void) 60*505d05c7Sgtb { 61*505d05c7Sgtb if (! INITIALIZER_RAN(profile_library_initializer) || PROGRAM_EXITING()) 62*505d05c7Sgtb return; 63*505d05c7Sgtb k5_mutex_destroy(&g_shared_trees_mutex); 64*505d05c7Sgtb #if !USE_BUNDLE_ERROR_STRINGS 65*505d05c7Sgtb remove_error_table(&et_prof_error_table); 66*505d05c7Sgtb #endif 67*505d05c7Sgtb } 68*505d05c7Sgtb 69*505d05c7Sgtb static void profile_free_file_data(prf_data_t); 70*505d05c7Sgtb 71*505d05c7Sgtb #if 0 72*505d05c7Sgtb 73*505d05c7Sgtb #define scan_shared_trees_locked() \ 74*505d05c7Sgtb { \ 75*505d05c7Sgtb prf_data_t d; \ 76*505d05c7Sgtb k5_mutex_assert_locked(&g_shared_trees_mutex); \ 77*505d05c7Sgtb for (d = g_shared_trees; d; d = d->next) { \ 78*505d05c7Sgtb assert(d->magic == PROF_MAGIC_FILE_DATA); \ 79*505d05c7Sgtb assert((d->flags & PROFILE_FILE_SHARED) != 0); \ 80*505d05c7Sgtb assert(d->filespec[0] != 0); \ 81*505d05c7Sgtb assert(d->fslen <= 1000); /* XXX */ \ 82*505d05c7Sgtb assert(d->filespec[d->fslen] == 0); \ 83*505d05c7Sgtb assert(d->fslen = strlen(d->filespec)); \ 84*505d05c7Sgtb } \ 85*505d05c7Sgtb } 86*505d05c7Sgtb 87*505d05c7Sgtb #define scan_shared_trees_unlocked() \ 88*505d05c7Sgtb { \ 89*505d05c7Sgtb int r; \ 90*505d05c7Sgtb r = k5_mutex_lock(&g_shared_trees_mutex); \ 91*505d05c7Sgtb assert (r == 0); \ 92*505d05c7Sgtb scan_shared_trees_locked(); \ 93*505d05c7Sgtb k5_mutex_unlock(&g_shared_trees_mutex); \ 94*505d05c7Sgtb } 95*505d05c7Sgtb 96*505d05c7Sgtb #else 977c478bd9Sstevel@tonic-gate 98*505d05c7Sgtb #define scan_shared_trees_locked() { ; } 99*505d05c7Sgtb #define scan_shared_trees_unlocked() { ; } 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate #endif 1027c478bd9Sstevel@tonic-gate 103*505d05c7Sgtb static int rw_access(const_profile_filespec_t filespec) 1047c478bd9Sstevel@tonic-gate { 1057c478bd9Sstevel@tonic-gate #ifdef HAVE_ACCESS 1067c478bd9Sstevel@tonic-gate if (access(filespec, W_OK) == 0) 1077c478bd9Sstevel@tonic-gate return 1; 1087c478bd9Sstevel@tonic-gate else 1097c478bd9Sstevel@tonic-gate return 0; 1107c478bd9Sstevel@tonic-gate #else 1117c478bd9Sstevel@tonic-gate /* 1127c478bd9Sstevel@tonic-gate * We're on a substandard OS that doesn't support access. So 1137c478bd9Sstevel@tonic-gate * we kludge a test using stdio routines, and hope fopen 1147c478bd9Sstevel@tonic-gate * checks the r/w permissions. 1157c478bd9Sstevel@tonic-gate */ 1167c478bd9Sstevel@tonic-gate FILE *f; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate f = fopen(filespec, "r+"); 119*505d05c7Sgtb if (f) { 120*505d05c7Sgtb fclose(f); 121*505d05c7Sgtb return 1; 122*505d05c7Sgtb } 123*505d05c7Sgtb return 0; 1247c478bd9Sstevel@tonic-gate #endif 125*505d05c7Sgtb } 126*505d05c7Sgtb 127*505d05c7Sgtb static int r_access(const_profile_filespec_t filespec) 128*505d05c7Sgtb { 129*505d05c7Sgtb #ifdef HAVE_ACCESS 130*505d05c7Sgtb if (access(filespec, R_OK) == 0) 131*505d05c7Sgtb return 1; 132*505d05c7Sgtb else 133*505d05c7Sgtb return 0; 134*505d05c7Sgtb #else 135*505d05c7Sgtb /* 136*505d05c7Sgtb * We're on a substandard OS that doesn't support access. So 137*505d05c7Sgtb * we kludge a test using stdio routines, and hope fopen 138*505d05c7Sgtb * checks the r/w permissions. 139*505d05c7Sgtb */ 140*505d05c7Sgtb FILE *f; 141*505d05c7Sgtb 142*505d05c7Sgtb f = fopen(filespec, "r"); 1437c478bd9Sstevel@tonic-gate if (f) { 1447c478bd9Sstevel@tonic-gate fclose(f); 1457c478bd9Sstevel@tonic-gate return 1; 1467c478bd9Sstevel@tonic-gate } 1477c478bd9Sstevel@tonic-gate return 0; 1487c478bd9Sstevel@tonic-gate #endif 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate 151*505d05c7Sgtb prf_data_t 152*505d05c7Sgtb profile_make_prf_data(const char *filename) 153*505d05c7Sgtb { 154*505d05c7Sgtb prf_data_t d; 155*505d05c7Sgtb size_t len, flen, slen; 156*505d05c7Sgtb char *fcopy; 157*505d05c7Sgtb 158*505d05c7Sgtb flen = strlen(filename); 159*505d05c7Sgtb slen = offsetof(struct _prf_data_t, filespec); 160*505d05c7Sgtb len = slen + flen + 1; 161*505d05c7Sgtb if (len < sizeof(struct _prf_data_t)) 162*505d05c7Sgtb len = sizeof(struct _prf_data_t); 163*505d05c7Sgtb d = malloc(len); 164*505d05c7Sgtb if (d == NULL) 165*505d05c7Sgtb return NULL; 166*505d05c7Sgtb memset(d, 0, len); 167*505d05c7Sgtb fcopy = (char *) d + slen; 168*505d05c7Sgtb assert(fcopy == d->filespec); 169*505d05c7Sgtb strcpy(fcopy, filename); 170*505d05c7Sgtb d->refcount = 1; 171*505d05c7Sgtb d->comment = NULL; 172*505d05c7Sgtb d->magic = PROF_MAGIC_FILE_DATA; 173*505d05c7Sgtb d->root = NULL; 174*505d05c7Sgtb d->next = NULL; 175*505d05c7Sgtb d->fslen = flen; 176*505d05c7Sgtb return d; 177*505d05c7Sgtb } 178*505d05c7Sgtb 179*505d05c7Sgtb errcode_t profile_open_file(const_profile_filespec_t filespec, 180*505d05c7Sgtb prf_file_t *ret_prof) 1817c478bd9Sstevel@tonic-gate { 1827c478bd9Sstevel@tonic-gate prf_file_t prf; 1837c478bd9Sstevel@tonic-gate errcode_t retval; 1847c478bd9Sstevel@tonic-gate char *home_env = 0; 185*505d05c7Sgtb unsigned int len; 186*505d05c7Sgtb prf_data_t data; 187*505d05c7Sgtb char *expanded_filename; 188*505d05c7Sgtb 189*505d05c7Sgtb retval = CALL_INIT_FUNCTION(profile_library_initializer); 190*505d05c7Sgtb if (retval) 191*505d05c7Sgtb return retval; 192*505d05c7Sgtb 193*505d05c7Sgtb scan_shared_trees_unlocked(); 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate prf = (prf_file_t) malloc(sizeof(struct _prf_file_t)); 1967c478bd9Sstevel@tonic-gate if (!prf) 1977c478bd9Sstevel@tonic-gate return ENOMEM; 1987c478bd9Sstevel@tonic-gate memset(prf, 0, sizeof(struct _prf_file_t)); 199*505d05c7Sgtb prf->magic = PROF_MAGIC_FILE; 200*505d05c7Sgtb 2017c478bd9Sstevel@tonic-gate len = strlen(filespec)+1; 2027c478bd9Sstevel@tonic-gate if (filespec[0] == '~' && filespec[1] == '/') { 2037c478bd9Sstevel@tonic-gate home_env = getenv("HOME"); 204*505d05c7Sgtb #ifdef HAVE_PWD_H 205*505d05c7Sgtb if (home_env == NULL) { 206*505d05c7Sgtb uid_t uid; 207*505d05c7Sgtb struct passwd *pw; 208*505d05c7Sgtb #ifdef HAVE_GETPWUID_R 209*505d05c7Sgtb struct passwd pwx; 210*505d05c7Sgtb char pwbuf[BUFSIZ]; 211*505d05c7Sgtb #endif 212*505d05c7Sgtb 213*505d05c7Sgtb uid = getuid(); 214*505d05c7Sgtb #ifndef HAVE_GETPWUID_R 215*505d05c7Sgtb pw = getpwuid(uid); 216*505d05c7Sgtb #elif defined(GETPWUID_R_4_ARGS) 217*505d05c7Sgtb /* earlier POSIX drafts */ 218*505d05c7Sgtb pw = getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf)); 219*505d05c7Sgtb #else 220*505d05c7Sgtb /* POSIX */ 221*505d05c7Sgtb if (getpwuid_r(uid, &pwx, pwbuf, sizeof(pwbuf), &pw) != 0) 222*505d05c7Sgtb /* Probably already null, but let's make sure. */ 223*505d05c7Sgtb pw = NULL; 224*505d05c7Sgtb #endif /* getpwuid variants */ 225*505d05c7Sgtb if (pw != NULL && pw->pw_dir[0] != 0) 226*505d05c7Sgtb home_env = pw->pw_dir; 227*505d05c7Sgtb } 228*505d05c7Sgtb #endif 2297c478bd9Sstevel@tonic-gate if (home_env) 2307c478bd9Sstevel@tonic-gate len += strlen(home_env); 2317c478bd9Sstevel@tonic-gate } 232*505d05c7Sgtb expanded_filename = malloc(len); 233*505d05c7Sgtb if (expanded_filename == 0) 234*505d05c7Sgtb return errno; 2357c478bd9Sstevel@tonic-gate if (home_env) { 236*505d05c7Sgtb strcpy(expanded_filename, home_env); 237*505d05c7Sgtb strcat(expanded_filename, filespec+1); 2387c478bd9Sstevel@tonic-gate } else 239*505d05c7Sgtb memcpy(expanded_filename, filespec, len); 240*505d05c7Sgtb 241*505d05c7Sgtb retval = k5_mutex_lock(&g_shared_trees_mutex); 242*505d05c7Sgtb if (retval) { 243*505d05c7Sgtb free(expanded_filename); 244*505d05c7Sgtb free(prf); 245*505d05c7Sgtb scan_shared_trees_unlocked(); 246*505d05c7Sgtb return retval; 247*505d05c7Sgtb } 248*505d05c7Sgtb scan_shared_trees_locked(); 249*505d05c7Sgtb for (data = g_shared_trees; data; data = data->next) { 250*505d05c7Sgtb if (!strcmp(data->filespec, expanded_filename) 251*505d05c7Sgtb /* Check that current uid has read access. */ 252*505d05c7Sgtb && r_access(data->filespec)) 253*505d05c7Sgtb break; 254*505d05c7Sgtb } 255*505d05c7Sgtb if (data) { 256*505d05c7Sgtb retval = profile_update_file_data(data); 257*505d05c7Sgtb data->refcount++; 258*505d05c7Sgtb (void) k5_mutex_unlock(&g_shared_trees_mutex); 259*505d05c7Sgtb free(expanded_filename); 260*505d05c7Sgtb prf->data = data; 261*505d05c7Sgtb *ret_prof = prf; 262*505d05c7Sgtb scan_shared_trees_unlocked(); 263*505d05c7Sgtb return retval; 264*505d05c7Sgtb } 265*505d05c7Sgtb (void) k5_mutex_unlock(&g_shared_trees_mutex); 266*505d05c7Sgtb data = profile_make_prf_data(expanded_filename); 267*505d05c7Sgtb if (data == NULL) { 268*505d05c7Sgtb free(prf); 269*505d05c7Sgtb free(expanded_filename); 270*505d05c7Sgtb return ENOMEM; 271*505d05c7Sgtb } 272*505d05c7Sgtb free(expanded_filename); 273*505d05c7Sgtb prf->data = data; 274*505d05c7Sgtb 275*505d05c7Sgtb retval = k5_mutex_init(&data->lock); 276*505d05c7Sgtb if (retval) { 277*505d05c7Sgtb free(data); 278*505d05c7Sgtb free(prf); 279*505d05c7Sgtb return retval; 280*505d05c7Sgtb } 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate retval = profile_update_file(prf); 2837c478bd9Sstevel@tonic-gate if (retval) { 2847c478bd9Sstevel@tonic-gate profile_close_file(prf); 2857c478bd9Sstevel@tonic-gate return retval; 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate 288*505d05c7Sgtb retval = k5_mutex_lock(&g_shared_trees_mutex); 289*505d05c7Sgtb if (retval) { 290*505d05c7Sgtb profile_close_file(prf); 291*505d05c7Sgtb scan_shared_trees_unlocked(); 292*505d05c7Sgtb return retval; 293*505d05c7Sgtb } 294*505d05c7Sgtb scan_shared_trees_locked(); 295*505d05c7Sgtb data->flags |= PROFILE_FILE_SHARED; 296*505d05c7Sgtb data->next = g_shared_trees; 297*505d05c7Sgtb g_shared_trees = data; 298*505d05c7Sgtb scan_shared_trees_locked(); 299*505d05c7Sgtb (void) k5_mutex_unlock(&g_shared_trees_mutex); 300*505d05c7Sgtb 3017c478bd9Sstevel@tonic-gate *ret_prof = prf; 3027c478bd9Sstevel@tonic-gate return 0; 3037c478bd9Sstevel@tonic-gate } 3047c478bd9Sstevel@tonic-gate 305*505d05c7Sgtb errcode_t profile_update_file_data(prf_data_t data) 3067c478bd9Sstevel@tonic-gate { 3077c478bd9Sstevel@tonic-gate errcode_t retval; 3087c478bd9Sstevel@tonic-gate #ifdef HAVE_STAT 3097c478bd9Sstevel@tonic-gate struct stat st; 310*505d05c7Sgtb #ifdef STAT_ONCE_PER_SECOND 311*505d05c7Sgtb time_t now; 312*505d05c7Sgtb #endif 3137c478bd9Sstevel@tonic-gate #endif 3147c478bd9Sstevel@tonic-gate FILE *f; 3157c478bd9Sstevel@tonic-gate 316*505d05c7Sgtb retval = k5_mutex_lock(&data->lock); 317*505d05c7Sgtb if (retval) 318*505d05c7Sgtb return retval; 319*505d05c7Sgtb 3207c478bd9Sstevel@tonic-gate #ifdef HAVE_STAT 321*505d05c7Sgtb #ifdef STAT_ONCE_PER_SECOND 322*505d05c7Sgtb now = time(0); 323*505d05c7Sgtb if (now == data->last_stat) { 324*505d05c7Sgtb k5_mutex_unlock(&data->lock); 325*505d05c7Sgtb return 0; 3267c478bd9Sstevel@tonic-gate } 327*505d05c7Sgtb #endif 328*505d05c7Sgtb if (stat(data->filespec, &st)) { 329*505d05c7Sgtb retval = errno; 330*505d05c7Sgtb k5_mutex_unlock(&data->lock); 331*505d05c7Sgtb return retval; 332*505d05c7Sgtb } 333*505d05c7Sgtb #ifdef STAT_ONCE_PER_SECOND 334*505d05c7Sgtb data->last_stat = now; 335*505d05c7Sgtb #endif 336*505d05c7Sgtb if (st.st_mtime == data->timestamp) { 337*505d05c7Sgtb k5_mutex_unlock(&data->lock); 338*505d05c7Sgtb return 0; 339*505d05c7Sgtb } 340*505d05c7Sgtb if (data->root) { 341*505d05c7Sgtb profile_free_node(data->root); 342*505d05c7Sgtb data->root = 0; 343*505d05c7Sgtb } 344*505d05c7Sgtb if (data->comment) { 345*505d05c7Sgtb free(data->comment); 346*505d05c7Sgtb data->comment = 0; 3477c478bd9Sstevel@tonic-gate } 3487c478bd9Sstevel@tonic-gate #else 3497c478bd9Sstevel@tonic-gate /* 3507c478bd9Sstevel@tonic-gate * If we don't have the stat() call, assume that our in-core 3517c478bd9Sstevel@tonic-gate * memory image is correct. That is, we won't reread the 3527c478bd9Sstevel@tonic-gate * profile file if it changes. 3537c478bd9Sstevel@tonic-gate */ 354*505d05c7Sgtb if (data->root) { 355*505d05c7Sgtb k5_mutex_unlock(&data->lock); 356*505d05c7Sgtb return 0; 357*505d05c7Sgtb } 3587c478bd9Sstevel@tonic-gate #endif 3597c478bd9Sstevel@tonic-gate errno = 0; 360*505d05c7Sgtb f = fopen(data->filespec, "r"); 3617c478bd9Sstevel@tonic-gate if (f == NULL) { 3627c478bd9Sstevel@tonic-gate retval = errno; 363*505d05c7Sgtb k5_mutex_unlock(&data->lock); 3647c478bd9Sstevel@tonic-gate if (retval == 0) 3657c478bd9Sstevel@tonic-gate retval = ENOENT; 3667c478bd9Sstevel@tonic-gate return retval; 3677c478bd9Sstevel@tonic-gate } 368*505d05c7Sgtb data->upd_serial++; 369*505d05c7Sgtb data->flags &= PROFILE_FILE_SHARED; 370*505d05c7Sgtb if (rw_access(data->filespec)) 371*505d05c7Sgtb data->flags |= PROFILE_FILE_RW; 372*505d05c7Sgtb retval = profile_parse_file(f, &data->root); 3737c478bd9Sstevel@tonic-gate fclose(f); 374*505d05c7Sgtb if (retval) { 375*505d05c7Sgtb k5_mutex_unlock(&data->lock); 376*505d05c7Sgtb return retval; 377*505d05c7Sgtb } 3787c478bd9Sstevel@tonic-gate #ifdef HAVE_STAT 379*505d05c7Sgtb data->timestamp = st.st_mtime; 3807c478bd9Sstevel@tonic-gate #endif 381*505d05c7Sgtb k5_mutex_unlock(&data->lock); 3827c478bd9Sstevel@tonic-gate return 0; 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate 385*505d05c7Sgtb static int 386*505d05c7Sgtb make_hard_link(const char *oldpath, const char *newpath) 3877c478bd9Sstevel@tonic-gate { 388*505d05c7Sgtb #ifdef _WIN32 389*505d05c7Sgtb return -1; 390*505d05c7Sgtb #else 391*505d05c7Sgtb return link(oldpath, newpath); 3927c478bd9Sstevel@tonic-gate #endif 393*505d05c7Sgtb } 3947c478bd9Sstevel@tonic-gate 395*505d05c7Sgtb static errcode_t write_data_to_file(prf_data_t data, const char *outfile, 396*505d05c7Sgtb int can_create) 3977c478bd9Sstevel@tonic-gate { 3987c478bd9Sstevel@tonic-gate FILE *f; 3997c478bd9Sstevel@tonic-gate profile_filespec_t new_file; 4007c478bd9Sstevel@tonic-gate profile_filespec_t old_file; 4017c478bd9Sstevel@tonic-gate errcode_t retval = 0; 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate retval = ENOMEM; 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate new_file = old_file = 0; 406*505d05c7Sgtb new_file = (char *) malloc(strlen(outfile) + 5); 4077c478bd9Sstevel@tonic-gate if (!new_file) 4087c478bd9Sstevel@tonic-gate goto errout; 409*505d05c7Sgtb old_file = (char *) malloc(strlen(outfile) + 5); 4107c478bd9Sstevel@tonic-gate if (!old_file) 4117c478bd9Sstevel@tonic-gate goto errout; 4127c478bd9Sstevel@tonic-gate 413*505d05c7Sgtb sprintf(new_file, "%s.$$$", outfile); 414*505d05c7Sgtb sprintf(old_file, "%s.bak", outfile); 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate errno = 0; 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate f = fopen(new_file, "w"); 4197c478bd9Sstevel@tonic-gate if (!f) { 4207c478bd9Sstevel@tonic-gate retval = errno; 4217c478bd9Sstevel@tonic-gate if (retval == 0) 4227c478bd9Sstevel@tonic-gate retval = PROF_FAIL_OPEN; 4237c478bd9Sstevel@tonic-gate goto errout; 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate 426*505d05c7Sgtb profile_write_tree_file(data->root, f); 4277c478bd9Sstevel@tonic-gate if (fclose(f) != 0) { 4287c478bd9Sstevel@tonic-gate retval = errno; 4297c478bd9Sstevel@tonic-gate goto errout; 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate unlink(old_file); 433*505d05c7Sgtb if (make_hard_link(outfile, old_file) == 0) { 434*505d05c7Sgtb /* Okay, got the hard link. Yay. Now we've got our 435*505d05c7Sgtb backup version, so just put the new version in 436*505d05c7Sgtb place. */ 437*505d05c7Sgtb if (rename(new_file, outfile)) { 438*505d05c7Sgtb /* Weird, the rename didn't work. But the old version 439*505d05c7Sgtb should still be in place, so no special cleanup is 440*505d05c7Sgtb needed. */ 4417c478bd9Sstevel@tonic-gate retval = errno; 4427c478bd9Sstevel@tonic-gate goto errout; 443*505d05c7Sgtb } 444*505d05c7Sgtb } else if (errno == ENOENT && can_create) { 445*505d05c7Sgtb if (rename(new_file, outfile)) { 4467c478bd9Sstevel@tonic-gate retval = errno; 4477c478bd9Sstevel@tonic-gate goto errout; 448*505d05c7Sgtb } 449*505d05c7Sgtb } else { 450*505d05c7Sgtb /* Couldn't make the hard link, so there's going to be a 451*505d05c7Sgtb small window where data->filespec does not refer to 452*505d05c7Sgtb either version. */ 453*505d05c7Sgtb #ifndef _WIN32 454*505d05c7Sgtb sync(); 4557c478bd9Sstevel@tonic-gate #endif 456*505d05c7Sgtb if (rename(outfile, old_file)) { 457*505d05c7Sgtb retval = errno; 458*505d05c7Sgtb goto errout; 459*505d05c7Sgtb } 460*505d05c7Sgtb if (rename(new_file, outfile)) { 461*505d05c7Sgtb retval = errno; 462*505d05c7Sgtb rename(old_file, outfile); /* back out... */ 463*505d05c7Sgtb goto errout; 464*505d05c7Sgtb } 465*505d05c7Sgtb } 4667c478bd9Sstevel@tonic-gate 467*505d05c7Sgtb data->flags = 0; 468*505d05c7Sgtb if (rw_access(outfile)) 469*505d05c7Sgtb data->flags |= PROFILE_FILE_RW; 4707c478bd9Sstevel@tonic-gate retval = 0; 471*505d05c7Sgtb 4727c478bd9Sstevel@tonic-gate errout: 4737c478bd9Sstevel@tonic-gate if (new_file) 4747c478bd9Sstevel@tonic-gate free(new_file); 4757c478bd9Sstevel@tonic-gate if (old_file) 4767c478bd9Sstevel@tonic-gate free(old_file); 4777c478bd9Sstevel@tonic-gate return retval; 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate 480*505d05c7Sgtb errcode_t profile_flush_file_data_to_buffer (prf_data_t data, char **bufp) 481*505d05c7Sgtb { 482*505d05c7Sgtb errcode_t retval; 483*505d05c7Sgtb retval = k5_mutex_lock(&data->lock); 484*505d05c7Sgtb if (retval) 485*505d05c7Sgtb return retval; 486*505d05c7Sgtb retval = profile_write_tree_to_buffer(data->root, bufp); 487*505d05c7Sgtb k5_mutex_unlock(&data->lock); 488*505d05c7Sgtb return retval; 489*505d05c7Sgtb } 4907c478bd9Sstevel@tonic-gate 491*505d05c7Sgtb errcode_t profile_flush_file_data(prf_data_t data) 4927c478bd9Sstevel@tonic-gate { 493*505d05c7Sgtb errcode_t retval = 0; 494*505d05c7Sgtb 495*505d05c7Sgtb if (!data || data->magic != PROF_MAGIC_FILE_DATA) 496*505d05c7Sgtb return PROF_MAGIC_FILE_DATA; 497*505d05c7Sgtb 498*505d05c7Sgtb retval = k5_mutex_lock(&data->lock); 499*505d05c7Sgtb if (retval) 500*505d05c7Sgtb return retval; 501*505d05c7Sgtb 502*505d05c7Sgtb if ((data->flags & PROFILE_FILE_DIRTY) == 0) { 503*505d05c7Sgtb k5_mutex_unlock(&data->lock); 504*505d05c7Sgtb return 0; 505*505d05c7Sgtb } 506*505d05c7Sgtb 507*505d05c7Sgtb retval = write_data_to_file(data, data->filespec, 0); 508*505d05c7Sgtb k5_mutex_unlock(&data->lock); 509*505d05c7Sgtb return retval; 510*505d05c7Sgtb } 511*505d05c7Sgtb 512*505d05c7Sgtb errcode_t profile_flush_file_data_to_file(prf_data_t data, const char *outfile) 513*505d05c7Sgtb { 514*505d05c7Sgtb errcode_t retval = 0; 515*505d05c7Sgtb 516*505d05c7Sgtb if (!data || data->magic != PROF_MAGIC_FILE_DATA) 517*505d05c7Sgtb return PROF_MAGIC_FILE_DATA; 518*505d05c7Sgtb 519*505d05c7Sgtb retval = k5_mutex_lock(&data->lock); 520*505d05c7Sgtb if (retval) 521*505d05c7Sgtb return retval; 522*505d05c7Sgtb retval = write_data_to_file(data, outfile, 1); 523*505d05c7Sgtb k5_mutex_unlock(&data->lock); 524*505d05c7Sgtb return retval; 525*505d05c7Sgtb } 5267c478bd9Sstevel@tonic-gate 527*505d05c7Sgtb 528*505d05c7Sgtb 529*505d05c7Sgtb void profile_dereference_data(prf_data_t data) 530*505d05c7Sgtb { 531*505d05c7Sgtb int err; 532*505d05c7Sgtb scan_shared_trees_unlocked(); 533*505d05c7Sgtb err = k5_mutex_lock(&g_shared_trees_mutex); 534*505d05c7Sgtb if (err) 5357c478bd9Sstevel@tonic-gate return; 536*505d05c7Sgtb profile_dereference_data_locked(data); 537*505d05c7Sgtb (void) k5_mutex_unlock(&g_shared_trees_mutex); 538*505d05c7Sgtb scan_shared_trees_unlocked(); 539*505d05c7Sgtb } 540*505d05c7Sgtb void profile_dereference_data_locked(prf_data_t data) 541*505d05c7Sgtb { 542*505d05c7Sgtb data->refcount--; 543*505d05c7Sgtb if (data->refcount == 0) 544*505d05c7Sgtb profile_free_file_data(data); 545*505d05c7Sgtb } 546*505d05c7Sgtb 547*505d05c7Sgtb int profile_lock_global() 548*505d05c7Sgtb { 549*505d05c7Sgtb return k5_mutex_lock(&g_shared_trees_mutex); 550*505d05c7Sgtb } 551*505d05c7Sgtb int profile_unlock_global() 552*505d05c7Sgtb { 553*505d05c7Sgtb return k5_mutex_unlock(&g_shared_trees_mutex); 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate 556*505d05c7Sgtb void profile_free_file(prf_file_t prf) 557*505d05c7Sgtb { 558*505d05c7Sgtb profile_dereference_data(prf->data); 559*505d05c7Sgtb free(prf); 560*505d05c7Sgtb } 561*505d05c7Sgtb 562*505d05c7Sgtb /* Call with mutex locked! */ 563*505d05c7Sgtb static void profile_free_file_data(prf_data_t data) 564*505d05c7Sgtb { 565*505d05c7Sgtb scan_shared_trees_locked(); 566*505d05c7Sgtb if (data->flags & PROFILE_FILE_SHARED) { 567*505d05c7Sgtb /* Remove from linked list. */ 568*505d05c7Sgtb if (g_shared_trees == data) 569*505d05c7Sgtb g_shared_trees = data->next; 570*505d05c7Sgtb else { 571*505d05c7Sgtb prf_data_t prev, next; 572*505d05c7Sgtb prev = g_shared_trees; 573*505d05c7Sgtb next = prev->next; 574*505d05c7Sgtb while (next) { 575*505d05c7Sgtb if (next == data) { 576*505d05c7Sgtb prev->next = next->next; 577*505d05c7Sgtb break; 578*505d05c7Sgtb } 579*505d05c7Sgtb prev = next; 580*505d05c7Sgtb next = next->next; 581*505d05c7Sgtb } 582*505d05c7Sgtb } 583*505d05c7Sgtb } 584*505d05c7Sgtb if (data->root) 585*505d05c7Sgtb profile_free_node(data->root); 586*505d05c7Sgtb if (data->comment) 587*505d05c7Sgtb free(data->comment); 588*505d05c7Sgtb data->magic = 0; 589*505d05c7Sgtb k5_mutex_destroy(&data->lock); 590*505d05c7Sgtb free(data); 591*505d05c7Sgtb scan_shared_trees_locked(); 592*505d05c7Sgtb } 593*505d05c7Sgtb 594*505d05c7Sgtb errcode_t profile_close_file(prf_file_t prf) 5957c478bd9Sstevel@tonic-gate { 5967c478bd9Sstevel@tonic-gate errcode_t retval; 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate retval = profile_flush_file(prf); 5997c478bd9Sstevel@tonic-gate if (retval) 6007c478bd9Sstevel@tonic-gate return retval; 6017c478bd9Sstevel@tonic-gate profile_free_file(prf); 6027c478bd9Sstevel@tonic-gate return 0; 6037c478bd9Sstevel@tonic-gate } 604