CodeCompass
269 строк · 5.1 Кб
1#include <sys/types.h>2#include <sys/stat.h>3#include <sys/file.h>4#include <fcntl.h>5#include <unistd.h>6#include <stdio.h>7#include <stdint.h>8#include <string.h>9#include <stdlib.h>10#include <ctype.h>11
12#include "ldlogger-tool.h"13#include "ldlogger-util.h"14#include "ldlogger-hooks.h"15
16static char* createJsonCommandString(const LoggerVector* args_)17{
18size_t cmdSize = 0;19char* cmd;20char* currEnd;21size_t i;22
23/* Calculate */24for (i = 0; i < args_->size; ++i)25{26cmdSize += strlen((const char*) args_->data[i]);27}28
29/* The final size is:30The overall size of command * 2 for escaping +
31args_->size character for word separator +
32args_->size * 2 character for word escaping ('"'' chars) separator +
331 byte character trailing null
34*/
35cmdSize = (cmdSize * 2) + (args_->size * 3) + 1;36cmd = (char*) malloc(sizeof(char) * cmdSize);37if (!cmd)38{39return NULL;40}41
42currEnd = cmd;43currEnd += strlen(shellEscapeStr((const char*) args_->data[0], currEnd));44for (i = 1; i < args_->size; ++i)45{46*currEnd = ' ';47++currEnd;48currEnd += strlen(shellEscapeStr((const char*) args_->data[i], currEnd));49}50
51*currEnd = '\0';52return cmd;53}
54
55static void writeAction(56FILE* stream_,57char const* wd_,58const LoggerAction* action_,59int* entryCount_)60{
61size_t i;62char* command;63
64command = createJsonCommandString(&action_->arguments);65if (!command)66{67return;68}69
70for (i = 0; i < action_->sources.size; ++i)71{72if (++(*entryCount_) > 1)73{74fprintf(stream_, "\t,\n");75}76
77fprintf(stream_,78"\t{\n" \79"\t\t\"directory\": \"%s\",\n" \80"\t\t\"command\": \"%s\",\n" \81"\t\t\"file\": \"%s\"\n" \82"\t}\n",83wd_, /* directory */84command, /* command */85(const char*) action_->sources.data[i] /* file */86);87}88
89free(command);90}
91
92static void writeActions(FILE* stream_, char const* wd_, const LoggerVector* actions_)93{
94size_t i;95long fsize;96int entryCount = 0;97
98if (actions_->size <= 0)99{100return;101}102
103fseek(stream_, 0L, SEEK_END);104fsize = ftell(stream_);105if (fsize == 0)106{107/* This is a new file, should write a [ char */108fprintf(stream_, "[\n");109}110else111{112/* We should overwrite the ] character at the end to get a valid113json file at the end
114*/
115fseek(stream_, -1L, SEEK_END);116if (fsize > 5)117{118/* This json is not empty, we should write ',' characters */119++entryCount;120}121}122
123for (i = 0; i < actions_->size; ++i)124{125writeAction(stream_, wd_, (const LoggerAction*) actions_->data[i], &entryCount);126}127
128fprintf(stream_, "]");129
130/* An fclose also closes the file descriptor, so wo only call an fflush131* here */
132fflush(stream_);133}
134
135static int aquireLock(char const* logFile_)136{
137char lockFilePath[PATH_MAX];138int lockFile;139
140if (!loggerMakePathAbs(logFile_, lockFilePath, 0))141{142return -1;143}144
145strcat(lockFilePath, ".lock");146lockFile = open(lockFilePath, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);147if (lockFile == -1)148{149return -1;150}151
152if (flock(lockFile, LOCK_EX) == -1)153{154close(lockFile);155return -1;156}157
158return lockFile;159}
160
161static void freeLock(int lockFile_)162{
163if (lockFile_ != -1)164{165flock(lockFile_, LOCK_UN);166close(lockFile_);167}168}
169
170static void logProgramArgs(171FILE* stream_,172char const* prog_,173int argc_,174char const* argv_[])175{
176char const** argList;177LoggerVector actions;178char workingDir[PATH_MAX];179
180if (!loggerMakePathAbs(".", workingDir, 1))181{182return;183}184
185/* Convert argument vector to a NULL terminated list */186argList = (char const **) malloc(sizeof(char*) * (argc_ + 1));187if (argList)188{189memcpy(argList, argv_, sizeof(char*) * argc_);190argList[argc_] = NULL;191}192else193{194return;195}196
197loggerVectorInitAdv(&actions, 10, (LoggerFreeFuc) &loggerActionFree);198
199loggerCollectActionsByProgName(prog_, argList, &actions);200
201writeActions(stream_, workingDir, &actions);202
203loggerVectorClear(&actions);204free(argList);205}
206
207/**
208* Logger entry point.
209*
210* The first argument should be the first argument of the exec* call, the rest
211* is the argument vector.
212*
213* @param argc_ argument counter.
214* @param argv_ argument vector (see above).
215* @return see a UNIX book.
216*/
217int logExec(int argc_, char const* argv_[])218{
219int lockFd;220int logFd;221FILE* stream;222char const* logFileEnv;223
224if (argc_ < 2)225{226return -1;227}228
229logFileEnv = getenv("CC_LOGGER_FILE");230if (!logFileEnv)231{232return -3;233}234
235lockFd = aquireLock(logFileEnv);236if (lockFd == -1)237{238return -5;239}240
241logFd = open(logFileEnv, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);242if (logFd == -1)243{244freeLock(lockFd);245return -7;246}247
248stream = fdopen(logFd, "w+");249if (!stream)250{251close(logFd);252freeLock(lockFd);253return -9;254}255
256logProgramArgs(stream, argv_[0], argc_ - 1, argv_ + 1);257
258fclose(stream); /* fclose also calls close() */259freeLock(lockFd);260
261return 0;262}
263
264#ifdef __LOGGER_MAIN__265int main(int argc_, char const* argv_[])266{
267return logExec(argc_ - 1, argv_ + 1);268}
269#endif270