/* provide.c: provide status infos. Copyright (C) 2009 AVM This file is part of davfs2. davfs2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. davfs2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with davfs2; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include #include #include #ifdef HAVE_STDLIB_H #include #endif #include #ifdef HAVE_SYSLOG_H #include #endif #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include "defaults.h" #include "mount_davfs.h" #include "provide.h" #include "webdav_shm.h" /* These infos are stored in a shared memory to provide * them for other processes. */ static struct webdav_file_infos sinfos; static struct webdav_file_infos * infos = &sinfos; /* Debug-Level */ static int debug = 0; #define TRANS_SPEED_INTERVAL 60 #define TRANS_SPEED_SLOTS 5 struct trans_speed{ uint64_t bytes; double seconds; time_t start_time; struct trans_speed* next; }; static struct trans_speed* download_speed_values = 0; static struct trans_speed* upload_speed_values = 0; static int write_file_webdav(struct webdav_file_infos * webdav_infos); static int write_file_webdav_connection_state(struct webdav_file_infos * webdav_infos); void print_speed(void); void clear_speed_values(int type); void delete_speed_values(int type); void append_speed_value(int type, uint64_t bytes, double seconds); void calculate_avg_speed(int type); void is_low_upload_speed(void); static void shm_lock(int shmid); static void shm_unlock(int shmid); //----------------------------------------------------- void provide_print(void) { if(!debug || !infos) return; syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "current status"); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- connection state: %u", infos->connection_state); //info not longer here syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- cache speed: %u", infos->cache_speed); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- cache storage avail: %llu", infos->cache_storage_avail); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- cache storage used: %llu", infos->cache_storage_used); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- dirty files: %u", infos->dirty_files); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- running uploads: %u", infos->running_uploads); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- uploading file1: %s", infos->uploading_file1); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- uploading file2: %s", infos->uploading_file2); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- finished uploads: %llu", infos->finished_uploads); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- failed uploads: %llu", infos->failed_uploads); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- sum failed uploads: %llu", infos->sum_failed_uploads); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- running downloads: %u", infos->running_downloads); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- downloading file1: %s", infos->downloading_file1); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- downloading file2: %s", infos->downloading_file2); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- finished downloads: %llu", infos->finished_downloads); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- failed downloads: %llu", infos->failed_downloads); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- average upload speed: %llu", infos->avg_upload_speed); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- average download speed: %llu", infos->avg_download_speed); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- size uploads: %llu", infos->size_uploads); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- size downloads: %llu", infos->size_downloads); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- storage quota available: %llu", infos->storage_quota_avail); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- storage quota used: %llu", infos->storage_quota_used); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- upload quota avail: %llu", infos->upload_quota_avail); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- upload quota used: %llu", infos->upload_quota_used); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- download quota avail: %llu", infos->download_quota_avail); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- download quota used: %llu", infos->download_quota_used); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- traffic quota avail: %llu", infos->traffic_quota_avail); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "- traffic quota used: %llu", infos->traffic_quota_used); } int provide_init(int debug_val) { debug = debug_val; if(!infos) return -1; //cache speed is set in the start-script of davfs2 memset(infos, 0, sizeof(struct webdav_file_infos)); infos->is_running = 1; write_file_webdav (infos); return 0; } void provide_destroy(void) { if (infos) memset(infos, 0, sizeof(struct webdav_file_infos)); } void provide_set_uint(int type, unsigned int value, const char op) { if(!infos){ syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "set uint failed - shared memory missing"); return; } unsigned int *old_val = 0; if(type == DIRTY_FILES) old_val = &infos->dirty_files; else if(type == RUNNING_UPLOADS) old_val = &infos->running_uploads; else if(type == RUNNING_DOWNLOADS) old_val = &infos->running_downloads; else{ syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "set uint failed - invalid parameter: type (%d)", type); return; } if(op == '+') *old_val += value; else if(op == '-') *old_val -= value; else *old_val = value; write_file_webdav (infos); } void provide_set_uint64(int type, uint64_t value, const char op) { if(!infos){ syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "set uint64 failed - shared memory missing"); return; } uint64_t *old_val = 0; if(type == FINISHED_UPLOADS) old_val = &infos->finished_uploads; else if(type == FAILED_UPLOADS) old_val = &infos->failed_uploads; else if(type == SUM_FAILED_UPLOADS) old_val = &infos->sum_failed_uploads; else if(type == FINISHED_DOWNLOADS) old_val = &infos->finished_downloads; else if(type == FAILED_DOWNLOADS) old_val = &infos->failed_downloads; else if(type == SIZE_UPLOADS) old_val = &infos->size_uploads; else if(type == SIZE_DOWNLOADS) old_val = &infos->size_downloads; else if(type == CACHE_STORAGE_USED) old_val = &infos->cache_storage_used; else if(type == CACHE_STORAGE_AVAIL) old_val = &infos->cache_storage_avail; else{ syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "set uint64 failed - invalid parameter: type (%d)", type); return; } if(op == '+') *old_val += value; else if(op == '-') *old_val -= value; else *old_val = value; write_file_webdav (infos); } void provide_set_files(int type, const char* file1, const char* file2) { if(!infos){ syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "set files failed - shared memory missing"); return; } if(type == UPLOAD_FILES){ if(file1) snprintf(infos->uploading_file1, sizeof(infos->uploading_file1), "%s", file1); else memset(infos->uploading_file1, '\0', sizeof(infos->uploading_file1)); if(file2) snprintf(infos->uploading_file2, sizeof(infos->uploading_file2), "%s", file2); else memset(infos->uploading_file2, '\0', sizeof(infos->uploading_file2)); } else if(type == DOWNLOAD_FILES){ if(file1) snprintf(infos->downloading_file1, sizeof(infos->downloading_file1), "%s", file1); else memset(infos->downloading_file1, '\0', sizeof(infos->downloading_file1)); if(file2) snprintf(infos->downloading_file2, sizeof(infos->downloading_file2), "%s", file2); else memset(infos->downloading_file2, '\0', sizeof(infos->downloading_file2)); } else{ syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "set files failed - invalid parameter: type (%d)", type); } write_file_webdav (infos); } void provide_set_quota(quota_context value) { if(!infos){ syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "set quota failed - shared memory missing"); return; } infos->storage_quota_avail = value.storage_available; infos->storage_quota_used = value.storage_used; infos->upload_quota_avail = value.upload_avail; infos->upload_quota_used = value.upload_used; infos->download_quota_avail = value.download_avail; infos->download_quota_used = value.download_used; infos->traffic_quota_avail = value.traffic_avail; infos->traffic_quota_used = value.traffic_used; infos->storage_filecount = value.storage_filecount; infos->storage_maxfilecount = value.max_filecount; infos->storage_maxfilesperfolder = value.max_filesperfolder; infos->storage_maxfilenamelength = value.max_filenamelength; infos->storage_maxfilesize = value.max_filesize; if(debug) { syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "quota settings: " "st_av: %llu, st_us: %llu, up_av: %llu, up_us: %llu, dw_av: %llu, dw_us: %llu, tr_av: %llu, tr_us: %llu", value.storage_available, value.storage_used, value.upload_avail, value.upload_used, value.download_avail, value.download_used, value.traffic_avail, value.traffic_used); } write_file_webdav (infos); } void provide_get_quota(quota_context *quotas) { if(!infos){ syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "get quota failed - shared memory missing"); return; } quotas->storage_available = infos->storage_quota_avail; quotas->storage_used = infos->storage_quota_used; quotas->upload_avail = infos->upload_quota_avail; quotas->upload_used = infos->upload_quota_used; quotas->download_avail = infos->download_quota_avail; quotas->download_used = infos->download_quota_used; quotas->traffic_avail = infos->traffic_quota_avail; quotas->traffic_used = infos->traffic_quota_used; quotas->storage_filecount = infos->storage_filecount; quotas->max_filecount = infos->storage_maxfilecount; quotas->max_filesperfolder = infos->storage_maxfilesperfolder; quotas->max_filenamelength = infos->storage_maxfilenamelength; quotas->max_filesize = infos->storage_maxfilesize; } void provide_set_string(int type, const char* value) { if(!infos){ syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "set string failed - shared memory missing"); return; } if(type == CONNECTION_STATE){ if(!value) infos->connection_state = 0; else{ if(!strcmp(value, "connected")) infos->connection_state = 1; else if(!strcmp(value, "disconnected")) infos->connection_state = 0; else if(strstr(value, "Could not resolve hostname") || strstr(value, "server temporarily unreachable")) infos->connection_state = 2; else if(strstr(value, "Could not authenticate to server") || strstr(value, "Authorization Required")) infos->connection_state = 3; else if(strstr(value, "invalid URL")) infos->connection_state = 4; else if(strstr(value, "Traffic limit reached")) infos->connection_state = 10; else if(strstr(value, "403")) // Forbidden infos->connection_state = 8; // unknown error else //5 : readonly for usb activated //6 : no usb-mountpoint available for cache //7 : missing online connection infos->connection_state = 8; //unknown connection error } write_file_webdav_connection_state (infos); } } void print_speed(void) { struct trans_speed* tmp; int cnt = 0; syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "--uploads"); for(tmp = upload_speed_values; tmp; tmp = tmp->next){ syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "pos: %d-", cnt); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "start_time: %lu", tmp->start_time); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "bytes: %llu", tmp->bytes); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "seconds: %f", tmp->seconds); cnt++; } syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "--downloads"); cnt = 0; for(tmp = download_speed_values; tmp; tmp = tmp->next){ syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "pos: %d-", cnt); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "start_time: %lu", tmp->start_time); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "bytes: %llu", tmp->bytes); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "seconds: %f", tmp->seconds); cnt++; } } void clear_speed_values(int type) { struct trans_speed* p = 0; struct trans_speed**pp = 0; struct trans_speed** speed_values = 0; if(type == TRANSFER_UPLOAD) speed_values = &upload_speed_values; else speed_values = &download_speed_values; for(pp = speed_values; *pp;){ if((*pp)->start_time < time(NULL)-(TRANS_SPEED_INTERVAL*TRANS_SPEED_SLOTS)){ p = *pp; *pp = (*pp)->next; free(p); } else pp = &(*pp)->next; } } void delete_speed_values(int type) { struct trans_speed* p = 0; struct trans_speed**pp = 0; struct trans_speed** speed_values = 0; if(type == TRANSFER_UPLOAD) speed_values = &upload_speed_values; else speed_values = &download_speed_values; for(pp = speed_values; *pp;){ p = *pp; *pp = (*pp)->next; free(p); } } void append_speed_value(int type, uint64_t bytes, double seconds) { struct trans_speed** tmp; if(type == TRANSFER_UPLOAD) for(tmp = &upload_speed_values; *tmp; tmp = &((*tmp)->next)); else for(tmp = &download_speed_values; *tmp; tmp = &((*tmp)->next)); *tmp = (struct trans_speed*)calloc(1, sizeof(struct trans_speed)); if(!*tmp) return; (*tmp)->start_time = time(NULL); (*tmp)->bytes = bytes; (*tmp)->seconds = seconds; } void provide_set_transfer_speed(int type, uint64_t bytes, uint64_t duration) { if(!infos){ syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "set transfer speed failed - shared memory missing"); return; } double seconds = (double) duration / 1000000.0; if((type == TRANSFER_UPLOAD && !upload_speed_values) || (type == TRANSFER_DOWNLOAD && !download_speed_values)){ //no time slot available append_speed_value(type, bytes, seconds); } else{ struct trans_speed* last; if(type == TRANSFER_UPLOAD) for(last = upload_speed_values; last->next; last = last->next); else for(last = download_speed_values; last->next; last = last->next); //update last time slot if(time(NULL) < last->start_time+TRANS_SPEED_INTERVAL){ last->bytes += bytes; last->seconds += seconds; } else{ //last time slot too old, append a new one //and remove expired slots append_speed_value(type, bytes, seconds); } } write_file_webdav (infos); } void calculate_avg_speed(int type) { if(!infos){ syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "calculating avg speed failed - shared memory missing"); return; } struct trans_speed* tmp; struct trans_speed* speed_values; double total_seconds = 0; uint64_t total_bytes = 0; uint64_t bytes_per_seconds = 0; if(type == TRANSFER_UPLOAD) speed_values = upload_speed_values; else speed_values = download_speed_values; for(tmp = speed_values; tmp; tmp = tmp->next){ if(tmp->bytes > 0 && tmp->seconds > 0){ total_seconds += tmp->seconds; total_bytes += tmp->bytes; } } if(total_bytes == 0) bytes_per_seconds = 0; else bytes_per_seconds = (uint64_t) (total_bytes / total_seconds); if(type == TRANSFER_UPLOAD) infos->avg_upload_speed = bytes_per_seconds; else infos->avg_download_speed = bytes_per_seconds; write_file_webdav (infos); } void is_low_upload_speed(void) { if(!infos){ syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "checking low upload speed failed - shared memory missing"); return; } struct trans_speed* tmp; int slot_count = 0; int is_slow = 1; uint64_t bytes_per_seconds = 0; for(tmp = upload_speed_values; tmp; tmp = tmp->next){ if(tmp->bytes > 0 && tmp->seconds > 0){ slot_count++; bytes_per_seconds = (uint64_t) (tmp->bytes / tmp->seconds); if((bytes_per_seconds*8)/1024>64) //greater than 64 Kbit/s is_slow = 0; } } if(slot_count == TRANS_SPEED_SLOTS) //notify "is-slow", only if uploads are running in all time-slots infos->low_upload_speed = is_slow; else infos->low_upload_speed = 0; write_file_webdav (infos); } void provide_update_avg_speed(void) { clear_speed_values(TRANSFER_UPLOAD); clear_speed_values(TRANSFER_DOWNLOAD); calculate_avg_speed(TRANSFER_UPLOAD); calculate_avg_speed(TRANSFER_DOWNLOAD); is_low_upload_speed(); } void provide_clear_transfervalues(void) { if(!infos){ syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "clearing transfervalues failed - shared memory missing"); return; } infos->dirty_files = 0; infos->running_uploads = 0; infos->finished_uploads = 0; infos->failed_uploads = 0; infos->running_downloads = 0; infos->finished_downloads = 0; infos->failed_downloads = 0; infos->avg_upload_speed = 0; infos->avg_download_speed = 0; infos->low_upload_speed = 0; memset(infos->uploading_file1, '\0', sizeof(infos->uploading_file1)); memset(infos->uploading_file2, '\0', sizeof(infos->uploading_file2)); memset(infos->downloading_file1, '\0', sizeof(infos->downloading_file1)); memset(infos->downloading_file2, '\0', sizeof(infos->downloading_file2)); delete_speed_values(TRANSFER_UPLOAD); delete_speed_values(TRANSFER_DOWNLOAD); write_file_webdav (infos); } void provide_update_alivetime(void) { if(!infos){ syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "updating alivetime failed - shared memory missing"); return; } infos->alive_time = time(NULL); write_file_webdav (infos); } static int write_file_webdav(struct webdav_file_infos * webdav_infos) { FILE *file; int err = -3; if(!webdav_infos) return -1; if(!(file = fopen(WEBDAVINFO_FILEPATH "/" WEBDAVINFO_FILETMP, "w"))) { return -2; } if(fprintf(file, WEBDAVINFO_STR_IS_RUNNING ":%u\n", webdav_infos->is_running) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_CACHE_STORAGE_AVAIL ":%llu\n", (unsigned long long)webdav_infos->cache_storage_avail) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_CACHE_STORAGE_USED ":%llu\n", (unsigned long long)webdav_infos->cache_storage_used) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_DIRTY_FILES ":%u\n", webdav_infos->dirty_files) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_RUNNING_UPLOADS ":%u\n", webdav_infos->running_uploads) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_RUNNING_DONWLOADS ":%u\n", webdav_infos->running_downloads) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_FINISHED_UPLOADS ":%llu\n", (unsigned long long)webdav_infos->finished_uploads) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_FAILED_UPLOADS ":%llu\n", (unsigned long long)webdav_infos->failed_uploads) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_SUM_FAILED_UPLOADS ":%llu\n", (unsigned long long)webdav_infos->sum_failed_uploads) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_FINISHED_DOWNLOADS ":%llu\n", (unsigned long long)webdav_infos->finished_downloads) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_FAILED_DOWNLOADS ":%llu\n", (unsigned long long)webdav_infos->failed_downloads) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_STORAGE_QUOTA_AVAIL ":%llu\n", (unsigned long long)webdav_infos->storage_quota_avail) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_STORAGE_QUOTA_USED ":%llu\n", (unsigned long long)webdav_infos->storage_quota_used) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_STORAGE_QUOTA_FILECOUNT ":%u\n", webdav_infos->storage_filecount) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_STORAGE_MAXFILECOUNT ":%u\n", webdav_infos->storage_maxfilecount) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_STORAGE_MAXFILESPERFOLDER ":%u\n", webdav_infos->storage_maxfilesperfolder) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_STORAGE_MAXFILENAMELENGTH ":%u\n", webdav_infos->storage_maxfilenamelength) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_STORAGE_MAXFILESIZE ":%llu\n", (unsigned long long)webdav_infos->storage_maxfilesize) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_UPLOAD_QUOTA_AVAIL ":%llu\n", (unsigned long long)webdav_infos->upload_quota_avail) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_UPLOAD_QUOTA_USED ":%llu\n", (unsigned long long)webdav_infos->upload_quota_used) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_DOWNLOAD_QUOTA_AVAIL ":%llu\n", (unsigned long long)webdav_infos->download_quota_avail) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_DOWNLOAD_QUOTA_USED ":%llu\n", (unsigned long long)webdav_infos->download_quota_used) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_TRAFFIC_QUOTA_AVAIL ":%llu\n", (unsigned long long)webdav_infos->traffic_quota_avail) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_TRAFFIC_QUOTA_USED ":%llu\n", (unsigned long long)webdav_infos->traffic_quota_used) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_AVG_UPLOAD_SPEED ":%llu\n", (unsigned long long)webdav_infos->avg_upload_speed) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_AVM_DOWNSLOAD_SPEED ":%llu\n", (unsigned long long)webdav_infos->avg_download_speed) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_LOW_UPLOAD_SPEED ":%u\n", webdav_infos->low_upload_speed) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_SIZE_DOWNLOADS ":%llu\n", (unsigned long long)webdav_infos->size_downloads) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_SIZE_UPLOADS ":%llu\n", (unsigned long long)webdav_infos->size_uploads) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_UPLOADING_FILE1 ":%s\n", webdav_infos->uploading_file1) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_UPLOADING_FILE2 ":%s\n", webdav_infos->uploading_file2) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_DOWNLOADING_FILE1 ":%s\n", webdav_infos->downloading_file1) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_DOWNLOADING_FILE2 ":%s\n", webdav_infos->downloading_file2) < 0) goto error; if(fprintf(file, WEBDAVINFO_STR_ALIVE_TIME ":%llu\n", (unsigned long long)webdav_infos->alive_time) < 0) goto error; fclose(file); rename(WEBDAVINFO_FILEPATH "/" WEBDAVINFO_FILETMP, WEBDAVINFO_FILEPATH "/" WEBDAVINFO_FILE); return 0; error: fclose(file); syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "write webdavinfo file: error %i occurred", err); return err; } static int write_file_webdav_connection_state(struct webdav_file_infos * webdav_infos) { FILE *file; int err = 0; if(!webdav_infos) return -1; if(!(file = fopen(WEBDAVINFO_FILEPATH "/" WEBDAVINFO_FILETMP_CONNECTION_STATE, "w"))) { return -2; } if(fprintf(file, WEBDAVINFO_STR_CONNECTION_STATE ":%u\n", webdav_infos->connection_state) < 0) err = -3; fclose(file); rename(WEBDAVINFO_FILEPATH "/" WEBDAVINFO_FILETMP_CONNECTION_STATE, WEBDAVINFO_FILEPATH "/" WEBDAVINFO_FILE_CONNECTION_STATE); return err; } //************************ // Funktionen fuers das lesen aus dem Shared-Memory static void shm_lock(int shmid) { // Lock shared memory while updating infos. if(shmctl(shmid, SHM_LOCK, NULL)==-1) syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "locking shared memory failed"); } static void shm_unlock(int shmid) { // Unlock shared memory after updating infos. if(shmctl(shmid, SHM_UNLOCK, NULL)==-1) syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "unlocking shared memory failed"); } #define member_size(type, member) sizeof(((type *)0)->member) /** * Read values from USB configuration. * * @param debug_val enable/disable debug output * @param [in,out] args configuration values * * @retval 0 on success * @retval -1 on failure */ int provide_get_usb_cfg_infos(int debug_val, dav_args *args) { struct webdav_shm_usb_cfg_infos * usb_cfg_infos = 0; /* ID of the created shared memory. */ int shmid = 0; if (!args) return -1; debug = debug_val; shmid = shmget(WEBDAV_SHM_ID, sizeof(struct webdav_shm_usb_cfg_infos), 0666); if(shmid == -1){ //shared memory not available, create it shmid = shmget(WEBDAV_SHM_ID, sizeof(struct webdav_shm_usb_cfg_infos), IPC_CREAT | 0666); if(shmid == -1){ syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "creating shared memory failed: %s", strerror(errno)); return -1; } if(debug) syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "shared memory created"); } void* shm = shmat(shmid, 0, 0); if ((int)shm == -1) { syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "attaching shared memory failed: %s", strerror(errno)); return -1; } if(debug) syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "shared memory attached"); usb_cfg_infos = (struct webdav_shm_usb_cfg_infos*) shm; shm_lock(shmid); /* critical region - start */ if (args->username) free (args->username); args->username = strndup(usb_cfg_infos->username, USB_CFG_STRLEN); if (args->password) free (args->password); args->password = strndup(usb_cfg_infos->password, USB_CFG_STRLEN); /* critical region - end */ shm_unlock(shmid); if(shmid > 0){ //detaching shared memory if(shmdt((void *)usb_cfg_infos) == -1) syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "detaching shared memory failed"); else if(debug) syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_DEBUG), "shared memory detached"); } return 0; } /** * AVM provide_system_no_sh * Execute a programm with the given parameters. * Safer replacement of system() without a shell. * * @param prg programm to execute * @param para1 parameter for the programm, set NULL if not used * @param para2 parameter for the programm, set NULL if not used * @param para3 parameter for the programm, set NULL if not used * * @retval 0 success * @retval >0 child/execvp returned with an error (child exit with 1) * @retval -1 failure * - if prg is NULL or empty * - on fork() failure * - waitpid() failed * @retval -2 child/prg was killed by a signal * @retval -3 child/prg was stopped by a signal (should not happen) * @retval -4 child/prg was continued by a signal (should not happen) */ int provide_system_no_sh(const char *prg, const char * para1, const char * para2, const char * para3) { char *argv[5]; // letztes Platz als Abschluss immer auf NULL setzen int status = -1; pid_t pid; if (!prg || !*prg) return -1; argv[0] = (char*) prg; argv[1] = (char*) para1; argv[2] = (char*) para2; argv[3] = (char*) para3; argv[4] = NULL; // Wenn keine Argumente mehr kommen, Ende / nach dem letzten Parameter immer auf NULL setzten! pid = fork(); if (pid < 0) { syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "fork() failed"); return -1; } if (pid == 0) { /* child */ execvp(argv[0], argv); // return -1 bei Fehler, Grund in errno // hier nur bei einem Fehler, bei erfolgreicher Ausfuehrung von execvp kehrt er hier nicht zurueck, sondern ersetzt den Child-Prozess syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "provide_system_no_sh(\"%s\" \"%s\" \"%s\" \"%s\"): execvp() failed, errno %d", prg, para1?para1:"", para2?para2:"", para3?para3:"", errno); exit(1); // Fehler } /* parent */ if (waitpid(pid, &status, 0) < 0) { // wenn WNOHANG mit angegeben wird, kann der Return-Wert auch 0 sein syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "waitpid(%d) failed", pid); return -1; } else { if (WIFEXITED(status)) { syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "waitpid child exited, status=%d\n", WEXITSTATUS(status)); return WEXITSTATUS(status); // child sauber beendet, Exit code zurueckgeben 0 OK, 1 Fehler beim execvp oder Fehlercode vom Programm } else if (WIFSIGNALED(status)) { syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "waitpid child killed by signal %d\n", WTERMSIG(status)); return -2; } else if (WIFSTOPPED(status)) { // nur moeglich wenn beim Aufruf von waitpid WUNTRACED angegeben wird syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "waitpid child stopped by signal %d\n", WSTOPSIG(status)); return -3; } else if (WIFCONTINUED(status)) { syslog(LOG_MAKEPRI(LOG_DAEMON, LOG_ERR), "waitpid child continued\n"); return -4; } } return -1; }