I'm trying to call execv after manually saerching for the program to execute.
In my case,
c is a struct which has args as an array of strings having the arguments passed while receiving input. nargs is the number of arguments.
c->args[0] would contain "ls","cat" etc.
I tried printing the value of the args[0], fullPath etc. in my child process. They all show values like "/bin/ls","/bin/cat" etc. But when I call execv, it returns -1 with an errno of 2, which I understand is the error for "No such file or directory". But I'm sure the file is there because thats what my PathResolver is returning after checking all permissions.
Can anyone point where I might have made a mistake.
//The part happening inside child
char *fullPath = PathResolver(c->args[0],1,&permission);
printf("FullPath: %s -- Permission: %d\n",fullPath,permission);
if(permission==0)
{
fprintf(stderr, "%s: Command not found\n",c->args[0]);
}
else if(permission==-1)
{
fprintf(stderr, "%s: Permission denied\n",c->args[0]);
}
else
{
char* args[c->nargs+1];
int m=0;
for(m=0;m<c->nargs;m++)
{
strcpy(args[m],c->args[m]);
}
args[c->nargs] = NULL;
printf("%d\n",execv(args[0], args));
printf("errno: %d\n",errno);
}
PathResolver function
char* PathResolver(char *command, int ResolverMode, int *Permission)
{
*Permission = 0;
char *returnString;
returnString = malloc((sizeof(char)));
char *strPath = getenv("PATH");
char *del = ":";
char *strToken = strtok(strPath,del);
FILE *f;
while(strToken)
{
char filePath[100];
sprintf(filePath,"%s/%s",strToken,command);
if(access(filePath,F_OK)>=0)
{
if(access(filePath,X_OK)>=0)
{
*Permission = 1;
sprintf(returnString,"%s%s ",returnString,filePath);
if(ResolverMode == 1)
break;
}
else
{
*Permission = -1;
}
}
strToken = strtok(NULL,del);
}
sprintf(returnString,"%s\b",returnString);
return returnString;
}
strcpy(args[m],c->args[m]); is undefined behaviour, because args[m] is not a pointer to valid memory.
The following might be simpler:
char * args[c->nargs + 1];
for (size_t m = 0; m != c->nargs; ++m)
{
args[m] = c->args[m];
}
args[c->nargs] = NULL;
There's no need to copy the strings.
(This may not be your actual problem, but it certainly prevents your program from being correct.)
execv() expects the program name to be prefixed by a full path as 1st parameter.
To have PATH searched instead of providing a path use execvp().
Update:
Also this line
returnString = malloc((sizeof(char)));
does only allocate 1 byte to returnString, which is way to few for how you use returnString.
Related
I am trying to find the file(say marks.txt) in the particular path passed as argument to a function. Is it possible to give the filename and path as arguments to a function which checks if the file exists and prints out the path?
The below function only takes path as argument.
int fileexists(const char *path){
File *ptr = fopen(path, "r");
if (fptr == NULL)
return 0;
fclose(fptr);
return 1;
}
The required function prototype :
int fileexists(const char *path, const char *filename)
There are two parts to this question, and the right answers to them depend on what you're trying to do.
Concatenate a directory name and a file name to form a full path name.
Determine whether a file (referred to by a full path name) exists or not.
Concatenating a directory name and a file name is straightforward. Your friendsstrcpy and strcat will do most of the work. There are a few minor details to be careful of: (a) You'll need a big enough buffer for the full pathname, and you'll need to decide whether to use a fixed-size array (perhaps of size MAX_PATH), or a malloc'ed buffer; (b) you might need to insert an explicit '/' character (and it usually doesn't hurt to stick one in even if the directory string already ends in one); (c) under Windows you might want to use '\\' instead of '/'.
And then determining whether a file named by a full pathname exists is already well answered over at What's the best way to check if a file exists in C?. The big question to ask here is, are you asking whether the file exists in preparation to doing something with the file? If so, you have a serious vulnerability if you check for the file's existence, but then before you do the other thing, something else happens to cause the file to appear or disappear. So rather than checking-and-then-doing, it's usually better to just try doing the other thing, and deal gracefully with any errors.
The function you have checks if the file can be opened, but it will fail for some files that exist but you have no rights to open. I'd use stat instead. To concatenate the path and filename you can use string functions.
The usual Unix C APIs are dismal. It takes lots of effort to do the simplest of things correctly - and even then I'm not sure that I didn't forget some Unix-ism like signal handling or some obscure error cases. I.e. stuff that's rather trivial to get right in modern C++.
I wish someone designed a modern C system API and implemented it for at least Linux, so that our suffering would end...
Usually, string concatenation requires some higher level API to be done while maintaining a modicum of sanity. Thus, the example below uses a strbuilder class to build the string. This makes things vaguely readable and avoids most common mistakes.
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
struct strbuilder {
unsigned items, item;
size_t length, *lengths;
char *str, *dst;
};
bool strbuilder_pass(struct strbuilder *builder, int *rc);
void strcat_str(struct strbuilder *builder, const char *src);
void strcat_c_ifnone(struct strbuilder *builder, char c);
bool strbuilder_is_freed(const struct strbuilder *builder);
int fileExists(const char *path, const char *filename)
{
const char pathSep = '/';
int rc;
struct strbuilder bld = {0};
while (strbuilder_pass(&bld, &rc))
{
strcat_str(&bld, path);
strcat_c_ifnone(&bld, pathSep);
strcat_str(&bld, filename);
if (!rc)
{
struct stat statbuf;
printf("path = %s\n", bld.str);
rc = stat(bld.str, &statbuf);
}
}
assert(strbuilder_is_freed(&bld));
return rc;
}
int main()
{
int rc = fileExists("/", "dev");
assert(rc == 0);
return 0;
}
The string building is controlled by a strbuilder_pass function, which advances the string builder's state through five passes of operation:
Determine the number of items whose width has to be stored (avoids the need to call strlen twice).
Prepare the length storage vector. Determine the length of the buffer needed.
Prepare the output string buffer. Concatenate the elements into the buffer.
Use the output string buffer.
Free the output string buffer.
This API is not particularly special, but fits this use case. Some other ad-hoc approach would work too, but this is IMHO a bit more elegant.
void strbuilder_free(struct strbuilder *builder)
{
free(builder->lengths);
free(builder->str);
memset(builder, 0, sizeof(*builder));
}
bool strbuilder_pass(struct strbuilder *builder, int *rc)
{
if (!builder->length) {// start of pass 1
builder->length = 1; /*term*/
*rc = EAGAIN;
return true;
}
else if (!builder->lengths) // end of pass 1
{
builder->lengths = malloc(sizeof(*builder->lengths) * builder->items);
if (builder->lengths)
return true;
*rc = ENOMEM;
}
else if (!builder->str) // end of pass 2
{
builder->dst = (builder->str = malloc(builder->length));
builder->item = 0;
builder->length = 0;
if (builder->dst) {
*builder->dst = '\0';
return true;
}
*rc = ENOMEM;
}
else if (builder->dst) // end of pass 3
{
while (*builder->dst) { // include optional content
builder->dst++; // skip
builder->length++;
}
builder->dst = NULL;
*rc = 0;
return true;
}
else if (!builder->dst) // end of pass 4 (if any)
{}
else {
*rc = EINVAL;
}
strbuilder_free(builder);
return false;
}
void strcat_str(struct strbuilder *builder, const char *src)
{
if (!src)
return;
if (!builder->lengths) // pass 1
builder->items ++;
else if (!builder->str) // pass 2
{
size_t len = strlen(src);
builder->lengths[builder->item++] = len;
builder->length += len;
}
else if (builder->dst) // pass 3
{
size_t len = builder->lengths[builder->item++];
if (*builder->dst && (!len || *builder->dst != *src))
{
builder->dst++;
builder->length++;
}
memcpy(builder->dst, src, len);
builder->dst += len;
builder->length += len;
*builder->dst = '\0';
}
}
void strcat_c_ifnone(struct strbuilder *builder, char c)
{
if (!builder->lengths) {} // pass 1
else if (!builder->str) // pass 2
{
if (c) builder->length ++;
}
else if (builder->dst) // pass 3
{
if (!builder->length || builder->dst[-1] != c)
*(builder->dst) = c;
}
}
bool strbuilder_is_freed(const struct strbuilder *builder)
{
return !builder || (!builder->lengths && !builder->str);
}
You probably want something like this (no error checking for brevity):
...
#include <string.h> // for str* functions
#include <unistd.h> // for access
#include <stdlib.h> // for malloc
...
int fileexists(const char *path, const char *filename)
{
char *name= malloc(strlen(path) + strlen(filename) + 1);
strcpy(name, path);
strcat(name, filename);
int retval = access(name, F_OK) == 0;
free(name);
return retval;
}
Call like this:
if (fileexists("/some/path/", "somefilename.txt")) ...
I think this is written in C, honestly don't know how to identify (if someone could give some tips it would be great). When the command rpt dumpvars 1234 is run in the console it returns the variables of machine/node 1234 to the screen. I want the same data output to a variables.txt file. Is there a simple one liner that I can add to do this?
The file is located here.
The portion of the data I am trying to get can be found on lines 7590-7623 as pasted here:
/*
* Display a node's main channel variables from the command line
*/
static int rpt_do_showvars(int fd, int argc, char *argv[])
{
int i,thisRpt = -1;
struct ast_var_t *newvariable;
if (argc != 3) return RESULT_SHOWUSAGE;
for(i = 0; i < nrpts; i++)
{
if(!strcmp(argv[2], rpt_vars[i].name))
{
thisRpt = i;
break;
}
}
if (thisRpt < 0)
{
ast_cli(fd, "Unknown node number %s.\n", argv[2]);
return RESULT_FAILURE;
}
i = 0;
ast_cli(fd,"Variable listing for node %s:\n",argv[2]);
ast_channel_lock(rpt_vars[thisRpt].rxchannel);
AST_LIST_TRAVERSE (&rpt_vars[thisRpt].rxchannel->varshead, newvariable,
entries) {
i++;
ast_cli(fd," %s=%s\n", ast_var_name(newvariable),
ast_var_value(newvariable));
}
ast_channel_unlock(rpt_vars[thisRpt].rxchannel);
ast_cli(fd," -- %d variables\n", i);
return(0);
}
The following code doesn't behave as expected ..
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
struct dest
{
char filename[20], keyword[20];
bool opened;
FILE * file;
};
void display_data(const struct dest p) {
printf("Keyword: %s, Filename: %s, Used: %s\n", p.keyword, p.filename, p.opened ? "Yes" : "No");
}
int main(int argc, char const *argv[])
{
// declaring variables
float lon, lat;
char info[80];
FILE *reader;
// checking required arguments
if ((argc+1) % 2 || argc < 2) {
fprintf(stderr, "Usage: %s file_to_read file_for_unknown type file type file ...\n", argv[0]);
return 2;
}
// opening the reader
if (!(reader = fopen(argv[1], "r"))) {
fprintf(stderr, "File can't be accessed: %s\n", argv[1]);
return 2;
}
// creating important globals
const short pairs = (argc-3)/2;
struct dest data[pairs];
struct dest other;
strcpy(other.filename, argv[2]);
other.opened = false;
// gathering data
short times = 4;
for(short i = 4; i < argc; i += 2) {
data[i-times].opened = false;
strcpy(data[i-times].keyword, argv[i-1]);
strcpy(data[i-times].filename, argv[i]);
times += 1;
}
// finally, scanning the file ..
struct dest *use_f; // pointer for the wanted destination ..
bool known;
while (fscanf(reader, "%f,%f,%79[^\n]", &lat, &lon, info)) {
// deciding which file to use ..
known = false;
for(short i=0; i < pairs; ++i) {
if (strstr(info, data[i].keyword)) {
known = true;
use_f = &data[i];
}
}
if (!(known)) {
use_f = &other;
}
// checking the file ..
if (!((*use_f).opened)) {
(*use_f).file = fopen((*use_f).filename, "w");
(*use_f).opened = true;
}
// writing to the file ..
fprintf((*use_f).file, "%f,%f,%s\n", lat, lon, info);
}
// closing all data streams, and informing user ..
for (short i=0; i < pairs; ++i) {
display_data(data[i]);
if (data[i].opened) {
fclose(data[i].file);
data[i].opened = false;
}
}
fclose(reader);
fclose(other.file);
return 0;
}
The command used to run it is this ..
./categorize spooky.csv other.csv UFO UFOS.csv # I get no output at all
It seems that the while loop doesn't actually end, which is mysterious, because the file (spooky.csv) is only 11 lines !
30.685163,-68.137207,Type=Yeti
28.304380,-74.575195,Type=UFO
29.132971,-71.136475,Type=Ship
28.343065,-62.753906,Type=Elvis
27.868217,-68.005371,Type=Goatsucker
30.496017,-73.333740,Type=Disappearance
26.224447,-71.477051,Type=UFO
29.401320,-66.027832,Type=Ship
37.879536,-69.477539,Type=Elvis
22.705256,-68.192139,Type=Elvis
27.166695,-87.484131,Type=Elvis
It just keeps writing to other.file, yet I don't know why ..
The program simply doesn't end, can anybody explain things to me ?
From the fscanf() manpage: "The value EOF is returned if an input failure occurs before any conversion (such as an end-of-file) occurs."
Here's a hint... EOF isn't equal to 0. Your while-loop never terminates.
Guys so I'm working on the web service assignment and I have the server dishing out random stuff and reading the uri but now i want to have the server run a different function depending on what it reads in the uri. I understand that we can do this with function pointers but i'm not exactly sure how to read char* and assign it to a function pointer and have it invoke that function.
Example of what I'm trying to do: http://pastebin.com/FadCVH0h
I could use a switch statement i believe but wondering if there's a better way.
For such a thing, you will need a table that maps char * strings to function pointers. The program segfaults when you assign a function pointer to string because technically, a function pointer is not a string.
Note: the following program is for demonstration purpose only. No bounds checking is involved, and it contains hard-coded values and magic numbers
Now:
void print1()
{
printf("here");
}
void print2()
{
printf("Hello world");
}
struct Table {
char ptr[100];
void (*funcptr)(void)
}table[100] = {
{"here", print1},
{"hw", helloWorld}
};
int main(int argc, char *argv[])
{
int i = 0;
for(i = 0; i < 2; i++){
if(!strcmp(argv[1],table[i].ptr) { table[i].funcptr(); return 0;}
}
return 0;
}
I'm gonna give you a quite simple example, that I think, is useful to understand how good can be functions pointers in C. (If for example you would like to make a shell)
For example if you had a struct like this:
typedef struct s_function_pointer
{
char* cmp_string;
int (*function)(char* line);
} t_function_pointer;
Then, you could set up a t_function_pointer array which you'll browse:
int ls_function(char* line)
{
// do whatever you want with your ls function to parse line
return 0;
}
int echo_function(char* line)
{
// do whatever you want with your echo function to parse line
return 0;
}
void treat_input(t_function_pointer* functions, char* line)
{
int counter;
int builtin_size;
builtin_size = 0;
counter = 0;
while (functions[counter].cmp_string != NULL)
{
builtin_size = strlen(functions[counter].cmp_string);
if (strncmp(functions[counter].cmp_string, line, builtin_size) == 0)
{
if (functions[counter].function(line + builtin_size) < 0)
printf("An error has occured\n");
}
counter = counter + 1;
}
}
int main(void)
{
t_function_pointer functions[] = {{"ls", &ls_function},
{"echo", &echo_function},
{NULL, NULL}};
// Of course i'm not gonna do the input treatment part, but just guess it was here, and you'd call treat_input with each line you receive.
treat_input(functions, "ls -laR");
treat_input(functions, "echo helloworld");
return 0;
}
Hope this helps !
I have been beating my head on a wall over this fts_children() question. In the man page, http://www.kernel.org/doc/man-pages/online/pages/man3/fts.3.html, it clearly states As a special case, if fts_read() has not yet been called for a hierarchy,
fts_children() will return a pointer to the files in the logical directory
specified to fts_open(), that is, the arguments specified to fts_open().
Which I take to mean that a linked list of all the files in the current directory are returned. Well, I am finding that not to be the case and I would really appreciate some help in the matter. I expected a linked list to be returned and then I would iterate through it to find the file with the matching file name (the end goal). However, right now, I am just trying to iterate through the linked list (baby steps). Right now, it will return one file and then exit the loop. This does not make sense to me. Any help would very much appreciated!!!
Opening of file system:
char* const path[PATH_MAX] = {directory_name(argv[argc-index]), NULL};
char* name = file_name(argv[argc-index]);
if ((file_system = fts_open(path, FTS_COMFOLLOW, NULL)) == NULL){
fprintf(stderr,"%s:%s\n", strerror(errno), getprogname());
exit(EXIT_FAILURE);
}/*Ends the files system check if statement*/
/*Displays the information about the specified file.*/
file_ls(file_system,name, flags);
For clarification, the directory_name parses the inputted path from the user and returns something like /home/tpar44. That directory is then opened.
Searching within the file system:
void
file_ls(FTS* file_system, char* file_name, int* flags){
FTSENT* parent = NULL;
//dint stop = 0;
parent = fts_children(file_system, 0);
while( parent != NULL ){
printf("parent = %s\n", parent->fts_name);
parent = parent->fts_link;
}
}
Thanks!
I think this is entirely by design.
...that is, the arguments specified to fts_open()...
What it says is that it will list the root elements in the path_argv parameters for your convenenience. It treats the path_argv array as a logical directory itself.
In other words this:
int main(int argc, char* const argv[])
{
char* const path[] = { ".", "/home", "more/root/paths", NULL };
FTS* file_system = fts_open(path, FTS_COMFOLLOW | FTS_NOCHDIR, &compare);
if (file_system)
{
file_ls(file_system, "", 0);
fts_close(file_system);
}
return 0;
}
Will output
parent = .
parent = /home
parent = more/root/paths
Which, in fact, it does (see http://liveworkspace.org/code/c2d794117eae2d8af1166ccd620d29eb).
Here is a more complete sample that shows complete directory traversal:
#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fts.h>
#include<string.h>
#include<errno.h>
int compare (const FTSENT**, const FTSENT**);
void file_ls(FTS* file_system, const char* file_name, int* flags)
{
FTSENT* node = fts_children(file_system, 0);
if (errno != 0)
perror("fts_children");
while (node != NULL)
{
// TODO use file_name and flags
printf("found: %s%s\n", node->fts_path, node->fts_name);
node = node->fts_link;
}
}
int main(int argc, char* const argv[])
{
FTS* file_system = NULL;
FTSENT* node = NULL;
if (argc<2)
{
printf("Usage: %s <path-spec>\n", argv[0]);
exit(255);
}
char* const path[] = { argv[1], NULL };
const char* name = "some_name";
file_system = fts_open(path, FTS_COMFOLLOW | FTS_NOCHDIR, &compare);
if (file_system)
{
file_ls(file_system, name, 0); // shows roots
while( (node = fts_read(file_system)) != NULL)
file_ls(file_system, name, 0); // shows child elements
fts_close(file_system);
}
return 0;
}
int compare(const FTSENT** one, const FTSENT** two)
{
return (strcmp((*one)->fts_name, (*two)->fts_name));
}