expanding a struct the right way - c

I wrote a program for an assignment I have, but I made a mistake and set as
constant the number of users that this program can work with because of that struct limitation. I tried to do some realloc to expand the struct but it didn't work, and I got:
gcc: error: O"SxW��D(/��A>A�0: No such file or directory
gcc: fatal error: no input files
compilation terminated.
Here is my code with todos near the relevant lines, I would appreciate very much a method that will help me to make that code less rigid with relation to the number of users. Thanks!
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <dirent.h>
#include <memory.h>
#include <unistd.h>
#include <wait.h>
#define MAX_LENGTH 160
#define STDERR_FILDES 2
#define OPERATION_FAILED (-1)
#define BUFFER_SIZE 512
#define CONFIG_PLACE 1
#define CORRECT_ARGS_NUM 2
#define WRONG_ARGS_NUM_MSG "Wrong number of program arguments. Please enter 2 arguments."
#define SPACE_CHAR ' '
#define NEW_LINE_CHAR '\n'
#define NULL_CHAR '\0'
#define NULL_STR "\0"
#define SLASH_CHAR '/'
#define SLASH_STR "/"
#define CURR_DIR "."
#define PAR_DIR ".."
#define C_EXTENT "c"
#define EXT_DOT '.'
#define NUM_OF_USERS 5 //todo: here I define the rigid number of users.
#define ZERO_SCORE "0"
#define SON 0
#define NO_FILE "NO_C_FILE"
#define TIMEOUT "TIMEOUT"
#define COMP_ERR "COMPILATION_ERROR"
#define SIXTY_SCORE "60"
#define BAD_OUT "BAD_OUTPUT"
#define EIGHTY_SCORE "80"
#define SIM_OUT "SIMILAR_OUTPUT"
#define HUNDRED_SCORE "100"
#define GREAT_OUT "GREAT_JOB"
#define EQUAL 0
#define EXE_FILE_NAME "temp.out"
#define RUN_FILE_NAME "./temp.out"
#define COMP_FILE_NAME "./comp.out"
#define RES_FILE_NAME "res.txt"
#define OPER "gcc"
#define OPT_FLAG "-o"
#define RESULTS_FILE_REL_PATH "results.csv"
#define RESULTS_FILE_PERMISSIONS 0644
#define CSV_LINE_MAX_LEN 500
#define CSV_SEPARATOR ","
#define CSV_END_LINE "\n"
#define SECONDS_TO_SLEEP 5
#define WAIT_FOR_ANY_CHILD 0
#define IDENTICAL 3
#define SIMILAR 2
#define DIFFERENT 1
enum Bool
{
false = 0,
true = 1
};
typedef struct User {
char name[MAX_LENGTH];
char filePath[MAX_LENGTH];
char dirPath[MAX_LENGTH];
char score[MAX_LENGTH];
char scoreInfo[MAX_LENGTH];
} User;
/**
* Prints an error message using write function to file descriptor
* number 2 (stderr), and exits with error status -1 (translates to 255).
*/
void sysCallFailureProcedure() {
char errorMsg[] = "Error in system call\n";
write(STDERR_FILDES, errorMsg, sizeof(errorMsg)-1);
exit(OPERATION_FAILED);
}
/**
* Get the file's extension.
* #param filename The filename.
* #return The file's extension.
*/
char *getFilenameExt(char *filename) {
char *dot = strrchr(filename, EXT_DOT);
if(!dot || dot == filename) return "";
return dot + 1;
}
/**
* Get the configurations from the configurations file.
* #param configfilePath The configurations file.
* #param mainDirPath The main directory path.
* #param inputFilePath The input file path.
* #param correctResFilePath The correct result file path.
*/
void getConfigFromFile(char* mainDirPath, char* inputFilePath, char* correctResFilePath, char* configfilePath){
int configFileDes = open(configfilePath, O_RDONLY);
if (configFileDes < 0){
sysCallFailureProcedure();
}
int retVal;
char buff[BUFFER_SIZE];
while ((retVal = read(configFileDes, buff, sizeof(buff))) > 0){
int lineNumber = 1;
int lineIdx = 0;
int i=0;
for (; i<retVal; i++) {
if (lineNumber == 1){
if (buff[i] == NEW_LINE_CHAR || buff[i] == SPACE_CHAR || buff[i] == NULL_CHAR) {
lineNumber = 2;
lineIdx = 0;
} else {
mainDirPath[lineIdx] = buff[i];
lineIdx++;
}
}
else if (lineNumber == 2){
if (buff[i] == NEW_LINE_CHAR || buff[i] == SPACE_CHAR || buff[i] == NULL_CHAR) {
lineNumber = 3;
lineIdx = 0;
} else {
inputFilePath[lineIdx] = buff[i];
lineIdx++;
}
}
else if (lineNumber == 3){
if (buff[i] != NEW_LINE_CHAR && buff[i] != SPACE_CHAR && buff[i] != NULL_CHAR) {
correctResFilePath[lineIdx] = buff[i];
lineIdx++;
}
}
}
}
if (retVal < 0){
sysCallFailureProcedure();
}
if (close(configFileDes) < 0){
sysCallFailureProcedure();
}
}
/**
* Get the C file.
* #param user The user.
* #param userNum The user Num.
* #param directory The directory.
* #param filePath The file path.
*/
void getCFile(User* user, int userNum, char* directory,char* filePath){
DIR* pDir = opendir(directory);
if (pDir == NULL){
sysCallFailureProcedure();
}
struct dirent* pDirent;
while((pDirent = readdir(pDir))!=NULL) {
if ((pDirent->d_type == DT_DIR) && (strcmp(pDirent->d_name, CURR_DIR) != 0)
&& (strcmp(pDirent->d_name, PAR_DIR) != 0)){
char dir[MAX_LENGTH]={};
strcpy(dir,directory);
int length = strlen(dir);
if (dir[length] != SLASH_CHAR) {
strcat(dir, SLASH_STR);
}
strcat(dir, pDirent->d_name);
getCFile(user, userNum, dir, filePath);
} else if (pDirent->d_type == DT_REG) {
char* extension = getFilenameExt(pDirent->d_name);
if(strcmp(extension,C_EXTENT) == 0) {
strcpy(filePath, pDirent->d_name);
strcpy(user[userNum].dirPath, directory);
break;
}
}
}
}
/**
* Process the main directory.
* #param users The users.
* #param userNum The user num.
* #param mainDirPath The main directory path.
*/
void processMainDir(User* users, int* userNum, char* mainDirPath){
DIR* pDir = opendir(mainDirPath);
if (pDir == NULL){
sysCallFailureProcedure();
}
struct dirent* pDirent;
int usersSize = NUM_OF_USERS; // todo: remove if may...
int userSize = sizeof(struct User);
while ((pDirent = readdir(pDir))!=NULL) {
if ((pDirent->d_type == DT_DIR) && (strcmp(pDirent->d_name, CURR_DIR) != 0)
&& (strcmp(pDirent->d_name, PAR_DIR) != 0)){
strcpy(users[*userNum].name, pDirent->d_name);
char path[MAX_LENGTH] = {};
char dir[MAX_LENGTH]={};
strcpy(dir, mainDirPath);
int length = strlen(dir);
if (dir[length] != SLASH_CHAR) {
strcat(dir, SLASH_STR);
}
strcat(dir, pDirent->d_name);
getCFile(users, *userNum, dir, path);
strcpy(users[*userNum].filePath, path);
(*userNum)++;
if ((*userNum) >= usersSize){
usersSize += NUM_OF_USERS;
users = (User*) realloc(users, usersSize * userSize); // todo: check it out. it doesn't work!
if (users == NULL){
sysCallFailureProcedure();
}
}
}
}
if (closedir(pDir) == OPERATION_FAILED){
sysCallFailureProcedure();
}
}
/*
* Return true if there is an executable file.
*/
enum Bool isThereExecutable(){
char workingDir[BUFFER_SIZE];
DIR* pDir;
struct dirent* pDirent;
getcwd(workingDir, sizeof(workingDir));
if ((pDir = opendir(workingDir)) == NULL){
sysCallFailureProcedure();
}
while ((pDirent = readdir(pDir)) != NULL){
if (strcmp(pDirent->d_name, EXE_FILE_NAME) == EQUAL){
return true;
}
}
return false;
}
/**
* Fill up the results file.
* #param resultsFilePath The path to the results file.
* #param userNum The number of users.
* #param users The users struct.
*/
void fillTheResultsFile(char* resultsFilePath, int userNum, User* users){
int resultsFileDes = open(resultsFilePath, O_WRONLY | O_CREAT | O_TRUNC, RESULTS_FILE_PERMISSIONS);
if (resultsFileDes < 0){
sysCallFailureProcedure();
}
int i;
for (i=0; i<userNum; i++) {
char line[CSV_LINE_MAX_LEN] = {};
strcpy(line, users[i].name);
strcat(line, CSV_SEPARATOR);
strcat(line, users[i].score);
strcat(line, CSV_SEPARATOR);
strcat(line, users[i].scoreInfo);
if (i < userNum -1){
strcat(line, CSV_END_LINE);
}
if (write(resultsFileDes, line, sizeof(line)-1) < 0){
sysCallFailureProcedure();
}
}
if (close(resultsFileDes) < 0){
sysCallFailureProcedure();
}
}
/**
* Execute a file.
* #param argv The file's args.
*/
void executeFile(char* argv[]){
pid_t pId = fork();
if (pId == SON) {
int retVal = execvp(argv[0], &argv[0]);
if (retVal == OPERATION_FAILED) {
sysCallFailureProcedure();
}
}else{
waitpid(pId, NULL, WCONTINUED);
}
}
void executeProg(User* users, int userNum, char* inputFilePath, char* correctResFilePath){
char* runArgs[] = {RUN_FILE_NAME, NULL};
int status;
pid_t pId = fork();
if (pId == SON){
int inputFileFileDes = open(inputFilePath, O_RDONLY);
if (inputFileFileDes < 0){
sysCallFailureProcedure();
}
int resFileFileDes = open(RES_FILE_NAME, O_WRONLY | O_CREAT | O_TRUNC, RESULTS_FILE_PERMISSIONS);
if (resFileFileDes < 0){
sysCallFailureProcedure();
}
if (dup2(inputFileFileDes, STDIN_FILENO) < 0){
sysCallFailureProcedure();
}
if (dup2(resFileFileDes, STDOUT_FILENO) < 0){
sysCallFailureProcedure();
}
if (execvp(runArgs[0], &runArgs[0]) < 0){
sysCallFailureProcedure();
}
if (close(inputFileFileDes) < 0){
sysCallFailureProcedure();
}
if (close(resFileFileDes) < 0){
sysCallFailureProcedure();
}
} else {
sleep(SECONDS_TO_SLEEP);
if (waitpid(pId, &status, WNOHANG) == 0){
strcpy(users[userNum].scoreInfo, TIMEOUT);
strcpy(users[userNum].score, ZERO_SCORE);
} else {
char* copmArguments[] = {COMP_FILE_NAME , RES_FILE_NAME, correctResFilePath, NULL};
pid_t pId2 = fork();
if (pId2 == SON){
if (execvp(copmArguments[0], &copmArguments[0]) < 0){
sysCallFailureProcedure();
}
} else{
waitpid(pId2, &status, WAIT_FOR_ANY_CHILD);
if (WIFEXITED(status)){
int compRes = WEXITSTATUS(status);
if (compRes == IDENTICAL){
strcpy(users[userNum].scoreInfo, GREAT_OUT);
strcpy(users[userNum].score, HUNDRED_SCORE);
} else if (compRes == SIMILAR){
strcpy(users[userNum].scoreInfo, SIM_OUT);
strcpy(users[userNum].score, EIGHTY_SCORE);
} else if (compRes == DIFFERENT){
strcpy(users[userNum].scoreInfo, BAD_OUT);
strcpy(users[userNum].score, SIXTY_SCORE);
}
}
if (unlink(EXE_FILE_NAME) < 0){
sysCallFailureProcedure();
}
if (unlink(RES_FILE_NAME) < 0){
sysCallFailureProcedure();
}
}
}
}
}
/**
* Get the scores and score info's.
* #param inputFilePath The input file path.
* #param correctResFilePath The correct result file path.
* #param users The users.
* #param userNum The user num.
*/
void getScoresAndInfo(char* inputFilePath, char* correctResFilePath, User* users, int userNum){
int i;
for (i=0; i<userNum; i++) {
if (strcmp(NULL_STR, users[i].filePath) == EQUAL){
strcpy(users[i].scoreInfo, NO_FILE);
strcpy(users[i].score, ZERO_SCORE);
} else {
char CompletePathToFile[MAX_LENGTH] = {};
strcpy(CompletePathToFile, users[i].dirPath);
strcat(CompletePathToFile, SLASH_STR);
strcat(CompletePathToFile, users[i].filePath);
char* executeArguments[] = {OPER, OPT_FLAG, EXE_FILE_NAME, CompletePathToFile, NULL};
executeFile(executeArguments);
if (!isThereExecutable()){
strcpy(users[i].scoreInfo, COMP_ERR);
strcpy(users[i].score, ZERO_SCORE);
} else {
executeProg(users, i, inputFilePath, correctResFilePath);
}
}
}
}
int main(int argc, char *argv[]) {
if (argc != CORRECT_ARGS_NUM) {
printf(WRONG_ARGS_NUM_MSG);
exit(OPERATION_FAILED);
}
char mainDirPath[MAX_LENGTH] = {};
char inputFilePath[MAX_LENGTH] = {};
char correctResFilePath[MAX_LENGTH] = {};
getConfigFromFile(mainDirPath, inputFilePath,correctResFilePath, argv[CONFIG_PLACE]);
User* users = (User*)malloc(sizeof(User) * NUM_OF_USERS); // todo: here I malloc the users struct
int idx = 0;
if (users == NULL){
sysCallFailureProcedure();
}
processMainDir(users, &idx, mainDirPath);
getScoresAndInfo(inputFilePath, correctResFilePath, users, idx);
fillTheResultsFile(RESULTS_FILE_REL_PATH, idx, users);
}

Related

Authentication error on pam application without asking password

I have an application running on an unprivileged user, but at some point this program needs to run another one as a root, would be nice if I can reuse a configured PAM module, like, su, sudo, login or anyone.
So I am trying to write some code to authenticate the root and run this program using PAM, like sudo does, but I cant ask for password, it needs to be automatic. This unprivileged program in a specific time will have the access to root password.
Tried this example here https://www.netbsd.org/docs/guide/en/chap-pam.html but on pam_authenticate, it always return PAM_AUTH_ERR, I have tried all configured modules on my ubuntu 18.04.
#include <security/pam_appl.h>
#include <security/pam_misc.h>
#include <stdio.h>
#include <sys/wait.h>
#include <err.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <grp.h>
#include <assert.h>
#include <string>
#include <vector>
int converse(int n, const struct pam_message **msg, struct pam_response **resp, void *data)
{
struct pam_response *aresp;
char buf[PAM_MAX_RESP_SIZE];
int i;
data = data;
if (n <= 0 || n > PAM_MAX_NUM_MSG)
return (PAM_CONV_ERR);
if ((aresp = (struct pam_response *) calloc(n, sizeof *aresp)) == NULL)
return (PAM_BUF_ERR);
for (i = 0; i < n; ++i) {
aresp[i].resp_retcode = 0;
aresp[i].resp = NULL;
switch (msg[i]->msg_style) {
case PAM_PROMPT_ECHO_OFF:
//aresp[i].resp = strdup(getpass(msg[i]->msg));
aresp[i].resp = strdup("mypass");
aresp[i].resp_retcode = 0;
if (aresp[i].resp == NULL)
goto fail;
break;
case PAM_PROMPT_ECHO_ON:
fputs(msg[i]->msg, stderr);
if (fgets(buf, sizeof buf, stdin) == NULL)
goto fail;
aresp[i].resp = strdup(buf);
if (aresp[i].resp == NULL)
goto fail;
break;
case PAM_ERROR_MSG:
fputs(msg[i]->msg, stderr);
if (strlen(msg[i]->msg) > 0 &&
msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
fputc('\n', stderr);
break;
case PAM_TEXT_INFO:
fputs(msg[i]->msg, stdout);
if (strlen(msg[i]->msg) > 0 &&
msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
fputc('\n', stdout);
break;
default:
goto fail;
}
}
*resp = aresp;
return (PAM_SUCCESS);
fail:
for (i = 0; i < n; ++i) {
if (aresp[i].resp != NULL) {
memset(aresp[i].resp, 0, strlen(aresp[i].resp));
free(aresp[i].resp);
}
}
memset(aresp, 0, n * sizeof *aresp);
*resp = NULL;
return (PAM_CONV_ERR);
}
static struct pam_conv conv = {
converse,
//misc_conv,
NULL
};
extern char **environ;
static pam_handle_t *pamh;
static struct pam_conv pamc;
static void
usage(void)
{
fprintf(stderr, "Usage: su [login [args]]\n");
exit(1);
}
int
main(int argc, char *argv[])
{
char hostname[64];
const char *user, *tty;
char **args, **pam_envlist, **pam_env;
struct passwd *pwd;
int o, pam_err, status;
pid_t pid;
while ((o = getopt(argc, argv, "h")) != -1)
switch (o) {
case 'h':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc > 0) {
user = *argv;
--argc;
++argv;
} else {
user = "root";
}
int pam_status = PAM_SUCCESS;
/* initialize PAM */
//pamc.conv = &openpam_ttyconv;
if ((pam_status = pam_start("passwd", user, &conv, &pamh)) != PAM_SUCCESS)
{
assert(false);
}
/* set some items */
gethostname(hostname, sizeof(hostname));
if ((pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS)
{
assert(false);
}
user = getlogin();
if ((pam_err = pam_set_item(pamh, PAM_RUSER, user)) != PAM_SUCCESS)
{
assert(false);
}
tty = ttyname(STDERR_FILENO);
if ((pam_err = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS)
{
assert(false);
}
/* authenticate the applicant */
pam_err = pam_authenticate(pamh, PAM_SILENT);
if (pam_err != PAM_SUCCESS)
{
printf("Pam Error (%d)\n", pam_err);
warn("pam_authenticate");
assert(false);
}
printf("AUTHENTICATED ;-)");
assert(false);
if ((pam_err = pam_acct_mgmt(pamh, 0)) == PAM_NEW_AUTHTOK_REQD)
pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
if (pam_err != PAM_SUCCESS)
{
assert(false);
}
/* establish the requested credentials */
if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
{
assert(false);
}
/* authentication succeeded; open a session */
if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS)
{
assert(false);
}
/* get mapped user name; PAM may have changed it */
pam_err = pam_get_item(pamh, PAM_USER, (const void **)&user);
if (pam_err != PAM_SUCCESS || (pwd = getpwnam(user)) == NULL)
{
assert(false);
}
/* export PAM environment */
if ((pam_envlist = pam_getenvlist(pamh)) != NULL) {
for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) {
putenv(*pam_env);
free(*pam_env);
}
free(pam_envlist);
}
std::vector<std::string> arguments;
arguments.resize(argc + 2);
char * args_ptr [arguments.size()];
arguments[0] = pwd->pw_shell;
args_ptr[argc +1] = NULL;
args_ptr[0] = (char *)arguments[0].c_str();
for (int i = 0; i < argc; i++)
{
arguments[i + 1] = argv[i];
args_ptr[i+1] = (char *)arguments[i+1].c_str();
}
/* set uid and groups */
if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
warn("initgroups()");
_exit(1);
}
if (setgid(pwd->pw_gid) == -1) {
warn("setgid()");
_exit(1);
}
if (setuid(pwd->pw_uid) == -1) {
warn("setuid()");
_exit(1);
}
execve(args_ptr[0], args_ptr, environ);
warn("execve()");
_exit(1);
pamerr:
fprintf(stderr, "Sorry\n");
err:
pam_end(pamh, pam_err);
exit(1);
}
I expect to fork in a elevated child and run my new program, without asking for password.

A C program that copies all the content a directory including files and folders

The last Code I just posted now works. That is, it is able to copy all files from one directory to another. But now, I wanted to update it in such a way that it copies also directories including it contents be it files or folders.
Here is what I did so far, but this has been unable to accomplish my dream.
I really don't know what is wrong with the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#define Max 8192
int copy_files(char *src, char *dest);
int copy_dir(char *srcpath, char *destpath);
int copy_dir(char *srcpath, char *destpath)
{
DIR *sdp = NULL;
DIR *ddp = NULL;
struct dirent *entry;
struct stat sb;
char tempsrc[strlen(srcpath)+1];
char tempdest[strlen(destpath)+1];
strcat(srcpath, "/");
strcat(destpath, "/");
strcpy(tempdest, destpath);
strcpy(tempsrc, srcpath);
if( (sdp = opendir(srcpath)) == NULL )
{
printf ("%s is not an existing directory\n", srcpath);
return 0;
}
else
{
while( (entry = readdir(sdp)) )
{
stat(entry->d_name, &sb);
// printf("Cannot open directory\n");
// exit(EXIT_FAILURE);
switch (sb.st_mode & S_IFMT)
{
case S_IFREG:
{
strcat(tempdest, entry->d_name);
strcat(tempsrc, entry->d_name);
copy_files(tempsrc, tempdest);
strcpy(tempdest, destpath);
strcpy(tempsrc, srcpath);
break;
}
case S_IFDIR:
{
strcat(tempsrc, entry->d_name);
strcat(tempdest, entry->d_name);
mkdir(tempdest, 0777);
ddp = opendir(tempdest);
copy_dir(tempsrc, tempdest);
strcpy(tempdest, destpath);
strcpy(tempsrc, srcpath);
break;
}
}
}
closedir(sdp);
closedir(ddp);
return 1;
}
}
int copy_files(char *src, char *dest)
{
int sfd, dfd, ret_in, ret_out;
char buff[Max];
if ( (sfd = open(src, O_RDONLY)) == -1 )
{
printf("Error while reading %s\n", src);
perror(src);
exit(1);
}
if ( (dfd = creat(dest, 0644)) == -1 )
{
printf("Error while creating %s\n", dest);
perror(dest);
exit(1);
}
while( (ret_in = read(sfd, &buff, Max)) > 0 )
{
ret_out = write (dfd, &buff, ret_in);
if (ret_out != ret_in)
{
printf("write error to %s", dest);
perror(dest);
exit(1);
}
if (ret_in == -1)
{
printf("read error from %s", src);
perror(src);
exit(1);
}
}
close(sfd);
close(dfd);
return 1;
}
int main(int argc, char *argv[])
{
int i;
if (argc != 3)
{
printf ("Usage: Programme_name src dest\n e.g. ./cp src dest\n");
exit(1);
}
char *srcp = argv[1];
char *destp = argv[2];
if (srcp[0] == '/' && destp[0] == '/')
{
for (i = 1; i <= strlen(destp); i++)
destp[(i-1)] = destp[i];
for (i = 1; i <= strlen(srcp); i++)
srcp[(i-1)] = srcp[i];
copy_dir(srcp, destp);
}
else if (srcp[0] != '/' && destp[0] == '/') //./ass1 test /t2
{
for (i = 1; i <= strlen(destp); i++)
destp[i-1] = destp[i];
strcat(destp, "/");
strcat(destp, srcp);
copy_files(srcp, destp);
}
else
{
printf ("Usage: Programme_name src dest\n e.g. ./cp src dest\n");
exit(1);
}
}
You are indefinitely adding /. to the temporary source and destination paths when the directory entry . is read, which is present in all directories. Instead, you should skip the . and .. entries.
Another error is the dimensioning of the temporary paths:
char tempsrc[strlen(srcpath)+1];
char tempdest[strlen(destpath)+1];
The arrays are made just long enough to hold the original paths, though sub-directory names are then appended, overflowing the arrays. Better:
char tempsrc[PATH_MAX];
char tempdest[PATH_MAX];

undefined reference to `round' - why?? I'm using math.h [duplicate]

This question already has answers here:
Undefined reference to `sin` [duplicate]
(4 answers)
Closed 7 years ago.
I have a little problem with my source code. gcc speak to me:
undefined reference to `round' but I don't know why because i'm using stdio.h, stdlib.h, math.h... :-( Can You help me with solve this problem?
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#include <math.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#define VERYBIG 200
int dir_size(const char* dirname)
{
int size = 0;
char path[VERYBIG];
struct stat tmp;
DIR* cat = opendir(dirname);
struct dirent* entry;
while ((entry = readdir(cat)))
{
if (!((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)))
{
path[0] = 0;
strcat(path, dirname);
strcat(path, "/");
strcat(path, entry->d_name);
if (lstat(path, &tmp) == -1)
perror("lstat");
if (S_ISDIR(tmp.st_mode))
{
size += round(tmp.st_blocks / 2);
size += dir_size(path);
}
else
{
size += round(tmp.st_blocks / 2);
}
}
}
return size;
}
void rozmiar(int blocks, int h)
{
if (h == 0)
printf("%d\t", blocks);
else
{
double newbl;
if (blocks < 1024)
printf("%dK\t", blocks);
else if (blocks < (1024 * 1024))
{
newbl = blocks / 1024;
printf("%0.1fM\t", round(newbl));
}
else
{
newbl = blocks / (1024 * 1024);
printf("%0.1fB\t", round(newbl));
}
}
}
void do_du(char dirname[], int s, int h)
{
DIR* kat;
struct dirent* wpis;
int sum = 0, dsize = 0;
if ((kat = opendir(dirname)) == NULL)
fprintf(stderr, "du2: cannot open %s\n", dirname);
struct stat info;
char path[VERYBIG];
while ((wpis = readdir(kat)) != NULL)
{
if (!((strcmp(wpis->d_name, ".") == 0) || (strcmp(wpis->d_name, "..") == 0)))
{
path[0] = 0;
strcat(path, dirname);
strcat(path, "/");
strcat(path, wpis->d_name);
if (lstat(path, &info) == -1)
perror("lstat");
if (S_ISDIR(info.st_mode))
{
dsize = dir_size(path) + round(info.st_blocks / 2);
sum += dsize;
if (s == 0)
{
rozmiar(dsize, h);
printf("%s\n", wpis->d_name);
}
}
else
{
sum += round(info.st_blocks / 2);
if (s == 0)
{
rozmiar(round(info.st_blocks / 2), h);
printf("%s\n", wpis->d_name);
}
}
}
}
if (stat(dirname, &info) == -1)
perror("stat");
sum += round(info.st_blocks / 2);
rozmiar(sum, h);
printf("%s\n", dirname);
}
int main(int ac, char* av[])
{
char optstring[] = "sh";
int opcja, human = 0, suma = 0;
while ((opcja = getopt(ac, av, optstring)) != -1)
{
switch (opcja)
{
case 's':
suma = 1;
break;
case 'h':
human = 1;
break;
case '?':
printf("Usage: du2 [-s] [-h] [KATALOG]\n\t-s\twyswietla wielkosc "
"katalogu\n\t-h\twysiwetla wielkosci plikow w kilo-/mega-/gigabajtach\n");
exit(1);
}
}
if (human != 0 || suma != 0)
{
av++;
ac--;
}
if (ac == 1)
do_du(".", suma, human);
else
do_du(*++av, suma, human);
return 0;
}
It must be a linker error.
Try compiling the program like this
gcc program.c -lm

Segmentation fault when running simple shell program

I am trying to make a simple shell program with the C language which have the options of redirecting stdin and stdout and making a pipe but it's giving me a segmentation fault error. Maybe the problem is in the getline but I'm not sure. Here is the code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#define R 0
#define W 1
#define LINE_LEN 25
struct Job {
char* command;
char** argv;
int stdin;
int stdout;
} typedef Job;
int tokens_number = 0;
int sign_place = 0;
int contain_left = 0;
int contain_right = 0;
int contain_line = 0;
char** parse_cmdline (char * cmdline ){
char** arg = calloc(15, sizeof(char*));
char temp_cmd[LINE_LEN*10];
strcpy(temp_cmd, cmdline);
char * tmp;
tmp = strtok(temp_cmd, " ");
while(tmp != NULL) {
arg[tokens_number] = (char*) malloc(LINE_LEN * sizeof(char*));
strcpy(arg[tokens_number],tmp);
tmp = strtok(NULL, " ");
tokens_number++;
}
//LAST ELEMENT IS NULL
arg[tokens_number+1] = NULL;
return arg;
}
void check_for_special_signs(char** argv){
int i;
for(i=0; i<tokens_number; i++){
if(strcmp(argv[i], "<") == 0){
contain_left = 1;
sign_place = i;
return;
}else if(strcmp(argv[i], ">") == 0){
contain_right = 1;
sign_place = i;
return;
}else if(strcmp(argv[i], "|") == 0){
contain_line = 1;
sign_place = i;
return;
}
}
}
void fork_child(Job* my_job) {
pid_t pid = fork();
if (pid == 0) {
execv(my_job -> command, my_job -> argv);
perror(my_job -> command);
} else if (pid > 0) {
int status;
wait(&status);
} else
perror("fork");
}
char** create_argv(char** argv){
int i;
int j = 0;
char** argvs = calloc(sign_place,sizeof(char*));
if(sign_place!=0){
for(i=0; i < sign_place ; i++){
argvs[i] = (char*) malloc(sizeof(char*));
strcpy(argvs[i],argv[i]);
}
return argvs;
}else{
return argv;
}
}
void close_job(Job* my_job) {
if (my_job -> stdin != STDIN_FILENO)
close(my_job -> stdin);
if (my_job -> stdout != STDOUT_FILENO)
close(my_job -> stdout);
free(my_job);
}
int main() {
size_t s = 512;
char* buffer = malloc(s * sizeof(char));
char** sep_cmd = malloc(s * sizeof(char));
while (getline(&buffer, &s, stdin) != EOF) {
Job* my_job;
int my_pipe[2];
int in = 0;
int out = 1;
sep_cmd = parse_cmdline(buffer);
my_job->command = sep_cmd[0];
my_job->argv = sep_cmd;
my_job->stdin = in;
my_job->stdout = out;
check_for_special_signs(my_job->argv);
pid_t pid = fork();
if (pid == 0) {
if(contain_left == 1){
in = open(my_job->argv[sign_place + 1], O_RDONLY);
if(in < 0){
perror("open()");
}
my_job->argv = create_argv(my_job->argv);
my_job->stdin = in;
}else if(contain_right == 1){
out = open(my_job->argv[sign_place + 1], O_WRONLY | O_CREAT,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (out < 0)
perror("open()");
my_job->argv = create_argv(my_job->argv);
my_job->stdout = out;
}else if(contain_line == 1){
pipe(my_pipe);
if (my_job -> stdin == my_pipe[R])
close(my_pipe[W]);
else
close(my_pipe[R]);
}
execv(my_job -> command, my_job -> argv);
perror(my_job -> command);
} else if (pid > 0) {
int status;
wait(&status);
} else{
perror("fork");
}
close_job(my_job);
free(buffer);
buffer = (char*) malloc(s * sizeof(char));
}
free(buffer);
return 0;
}
That way I can't see if there are more mistakes in the code. Please if you see more mistakes list them too.
Thank you.
You forgot to allocate memory for my_job in main function

Was given this code on SO, but how to make it output to stdout instead?

a kind user here gave me some code to work with for a command line shell, but I want it to output to stdout and stderr instead of using a screen or whatever it is doing right now. I am new to C so I don't know anything about converting it. I also need its ability to detect arrow keys preserved... I'm trying to make a simplistic bash clone. This is what I have right now, it's about 50% my code and 50% others'... yes, it is buggy. There are large sections commented out because they were no longer being used or because they were broken. Ignore them. :)
The particular difficulty is in the use of draw_frame() in main().
#include "os1shell.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h> /* standard unix functions, like getpid() */
#include <sys/types.h> /* various type definitions, like pid_t */
#include <signal.h> /* signal name macros, and the kill() prototype */
#include <ncurses/curses.h> /* a library for cursor-based programs */
#include <poll.h>
#include <termios.h>
#include <time.h>
/** VT100 command to clear the screen. Use puts(VT100_CLEAR_SCREEN) to clear
* the screen. */
#define VT100_CLEAR_SCREEN "\033[2J"
/** VT100 command to reset the cursor to the top left hand corner of the
* screen. */
#define VT100_CURSOR_TO_ORIGIN "\033[H"
struct frame_s {
int x;
int y;
char *data;
};
char* inputBuffer; /* the command input buffer, will be length 65 and null
* terminated. */
char** cmdHistory; /* the command history, will be no longer than 20
* elements and null terminated. */
int historySize = 0;
void addToHistory(char* newItem) {
char** h;
int historySize = 0;
for (historySize; historySize < 21; ++historySize) {
if (cmdHistory[historySize] == NULL) break;
}
if (historySize == 20) {
char** newPtr = cmdHistory + sizeof(char *);
free(cmdHistory[0]);
cmdHistory = newPtr;
h = (char**)realloc(cmdHistory,21*sizeof(char *));
cmdHistory = h;
cmdHistory[19] = newItem;
cmdHistory[20] = NULL;
} else {
h = (char**)realloc(cmdHistory,(historySize+2)*sizeof(char *));
cmdHistory = h;
cmdHistory[historySize] = newItem;
cmdHistory[historySize+1] = NULL;
}
}
/* Some help from http://stackoverflow.com/users/1491/judge-maygarden*/
char** getArguments(char* input) {
char** arguments;
int k = 0;
char* tokenized;
arguments = calloc(1, sizeof (char *));
tokenized = strtok(input, " &");
while (tokenized != NULL) {
arguments[k] = tokenized;
++k;
arguments = realloc(arguments, sizeof (char *) * (k + 1));
tokenized = strtok(NULL, " &");
}
// an extra NULL is required to terminate the array for execvp()
arguments[k] = NULL;
return arguments;
}
void printHistory(struct frame_s *frame) {
snprintf(frame->data, frame->x, "\n\n");
char** currCmd = cmdHistory;
while (*currCmd != NULL) {
snprintf(frame->data[(2*frame->x)], frame->x, "%s\n", *currCmd);
currCmd++;
}
snprintf(frame->data, frame->x, "\n\n");
}
/* Some help from http://stackoverflow.com/users/659981/ben*/
static int draw_frame(struct frame_s *frame) {
int row;
char *data;
int attrib;
puts(VT100_CLEAR_SCREEN);
puts(VT100_CURSOR_TO_ORIGIN);
for ( row = 0, data = frame->data;
row < frame->y;
row++, data += frame->x ) {
// 0 for normal, 1 for bold, 7 for reverse.
attrib = 0;
// The VT100 commands to move the cursor, set the attribute,
// and the actual frame line.
fprintf( stdout,
"\033[%d;%dH\033[0m\033[%dm%.*s",
row + 1,
0,
attrib, frame->x, data);
fflush(stdout);
}
return (0);
}
/* Some help from http://stackoverflow.com/users/659981/ben*/
int main(void) {
const struct timespec timeout = { .tv_sec = 1, .tv_nsec = 0 };
struct frame_s frame;
struct termios tty_old;
struct termios tty_new;
unsigned char line[65]; // the input buffer
unsigned int count = 0; // the count of characters in the buff
int ret;
struct pollfd fds[1];
sigset_t sigmask;
struct tm *tp;
time_t current_time;
cmdHistory = (char**)calloc(21,sizeof(char *)); // initialize the
// command history
cmdHistory[20] = NULL; // null terminate the history
int histInd = 0; // an index for the history for arrows
int t;
int r;
char** downTemp;
char** enterTemp;
// Set up a little frame.
frame.x = 80;
frame.y = 32;
frame.data = malloc(frame.x * frame.y);
if (frame.data == NULL) {
fprintf(stderr, "No memory\n");
exit (1);
}
memset(frame.data, ' ', frame.x * frame.y);
// Get the terminal state.
tcgetattr(STDIN_FILENO, &tty_old);
tty_new = tty_old;
// Turn off "cooked" mode (line buffering) and set minimum characters
// to zero (i.e. non-blocking).
tty_new.c_lflag &= ~ICANON;
tty_new.c_cc[VMIN] = 0;
// Set the terminal attributes.
tcsetattr(STDIN_FILENO, TCSANOW, &tty_new);
// Un-mask all signals while in ppoll() so any signal will cause
// ppoll() to return prematurely.
sigemptyset(&sigmask);
fds[0].events = POLLIN;
fds[0].fd = STDIN_FILENO;
// Loop forever waiting for key presses. Update the output on every key
// press and every 1.0s (when ppoll() times out).
do {
fd_set rdset;
int nfds = STDIN_FILENO + 1;
FD_ZERO(&rdset);
FD_SET(STDIN_FILENO, &rdset);
ret = pselect(nfds, &rdset, NULL, NULL, &timeout, &sigmask);
if (ret < 0) { // check for pselect() error.
if (errno == EINTR) {
continue;
} else {
break;
}
}
if (FD_ISSET(STDIN_FILENO, &rdset)) {
ret = read(STDIN_FILENO,&line[count],sizeof(line)-count);
// do {
// fds[0].revents = 0;
// ret = poll(fds, sizeof(fds) / sizeof(struct pollfd), 1000);
//
// if (fds[0].revents & POLLIN) {
// ret = read(STDIN_FILENO,&line[count],sizeof(line)-count);
if (ret > 0) {
line[count + ret] = '\0';
if (strcmp(&line[count], "\033[A") == 0) {
if (histInd > 0) {
--histInd;
}
count = 0;
if(cmdHistory[histInd]!=NULL) {
snprintf(&frame.data[(2*frame.x)],
frame.x,
"hist: %s",
cmdHistory[histInd]);
strcpy(line, cmdHistory[histInd]);
}
} else if (strcmp(&line[count],"\033[B")==0) {
char** downTemp = cmdHistory;
r = 0;
while (*downTemp != NULL) {
++downTemp;
++r;
}
if (histInd < r-1 && r!= 0) {
++histInd;
}
count = 0;
if(cmdHistory[histInd]!=NULL) {
snprintf(&frame.data[(2*frame.x)],
frame.x,
"hist: %s",
cmdHistory[histInd]);
strcpy(line, cmdHistory[histInd]);
}
} else if (line[count] == 127) {
if (count != 0) {
line[count] = '\0';
count -= ret;
}
snprintf(&frame.data[(2*frame.x)], frame.x, "backspace");
} else if (line[count] == '\n') {
char** arguments = getArguments(line);
snprintf( &frame.data[(2*frame.x)],
frame.x,
"entered: %s",
line);
if (count > 0) {
int hasAmpersand = 0;
char* cmd = (char*)
malloc(65*sizeof(char));
strcpy(cmd, line);
addToHistory(cmd);
/*
char* temp = cmd;
while (*temp != '\0') {
if (*temp == '&') {
hasAmpersand = 1;
}
++temp;
}
pid_t pid;
pid = fork();
if (pid == 0) {
int exeret;
exeret = execvp(*arguments,
arguments);
if (exeret < 0) {
snprintf(
&frame.data[
(2*frame.x)],
frame.x,
"Exec failed.\n\n");
exit(1);
}
} else if (pid < 0) {
snprintf(
&frame.data[
(2*frame.x)],
frame.x,
"Fork failed.\n\n");
exit(1);
} else if (pid > 0) {
if (!hasAmpersand) {
wait(NULL);
}
free(arguments);
snprintf(frame.data,
frame.x,
"\n\n");
}*/
} else {
free(arguments);
}
enterTemp = cmdHistory;
t = 0;
while (*enterTemp != NULL) {
++enterTemp;
++t;
}
if (t > histInd) histInd = t;
count = 0;
} else {
//snprintf( frame.data,
// frame.x,
// "char: %c",
// line[count]);
count += ret;
}
}
}
// Print the current time to the output buffer.
//current_time = time(NULL);
//tp = localtime(&current_time);
//strftime( &frame.data[1 * frame.x],
// frame.x,
// "%Y/%m/%d %H:%M:%S",
// tp);
// Print the command line.
line[count] = '\0';
snprintf( frame.data,
frame.x,
"OS1Shell -> %s",
line);
draw_frame(&frame);
} while (1);
// Restore terminal and free resources.
tcsetattr(STDIN_FILENO, TCSANOW, &tty_old);
free(frame.data);
int n = 0;
while (n < 21) {
free(cmdHistory[n]);
++n;
}
free(cmdHistory);
return (0);
}
Any help getting it to act more like bash would be highly appreciated! Part of the credit is for using stderr correctly anyways, so it would definitely help to take the stdin/stdout/stderr approach.
It looks to me it already is going to STDOUT
fprintf( stdout,
"\033[%d;%dH\033[0m\033[%dm%.*s",
row + 1,
0,
attrib, frame->x, data);
fflush(stdout);

Resources