Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
I am working on a school project which is basically creating a simple shell in UNIX.
But I'm stuck with history part of my project.The explanation which is about history part is explained below:
history – This command is for maintaining a history of commands previously issued.
o history - print up to the 10 most recently entered commands in your shell.
o ! number - A user should be able to repeat a previously issued command by
typing ! number, where number indicates which command to repeat.
Note that ! 1 is for repeating the command numbered 1 in the list of commands returned by
history, and ! -1 is for repeating the last command.
And my code till history part is here :
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <limits.h>
#include <malloc.h>
#include <string.h>
#include <termios.h>
#include <errno.h>
#define CREATE_FLAGS (O_WRONLY | O_CREAT | O_APPEND)
#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
#define CREATE_FLAG (O_WRONLY| O_CREAT| O_TRUNC)
#define MAXCHARNUM 128
#define MAXARGNUM 32
char *argsexec[MAXARGNUM];
char str[MAXCHARNUM];
char *path;
char *name;
struct Node
{
pid_t pid;
char *pname;
int index;
struct Node *nextPtr;
};
typedef struct Node Node;
typedef struct Node *NodePtr;
NodePtr list = NULL;
void addJob(NodePtr *currentPtr, pid_t pid, char *name, int indx)
{
NodePtr newPtr, prePtr, curPtr;
newPtr = malloc(sizeof(Node));
if (newPtr != NULL )
{
newPtr->pid = pid;
newPtr->pname = name;
newPtr->index = indx;
newPtr->nextPtr = NULL;
prePtr = NULL;
curPtr = *currentPtr;
while (curPtr != NULL )
{
prePtr = curPtr;
curPtr = curPtr->nextPtr;
}
if (prePtr == NULL )
{
newPtr->nextPtr = *currentPtr;
*currentPtr = newPtr;
}
else
{
prePtr->nextPtr = newPtr;
newPtr->nextPtr = curPtr;
}
}
}
void printJob(NodePtr curPtr)
{
if (curPtr == NULL )
{
printf("Running: List is empty.\n");
printf("Terminated: List is empty.\n");
}
else
{
printf("Running:\n");
while (curPtr != NULL )
{
printf("[%d] --> %s\n", curPtr->index, curPtr->pname);
curPtr = curPtr->nextPtr;
}
printf("Finished:\n");
while (curPtr != NULL )
{
printf("[%d] --> %s (pid = %d)\n", curPtr->index, curPtr->pname,
curPtr->pid);
curPtr = curPtr->nextPtr;
}
}
}
void ioredirection()
{
int input = -1, output = -1, append = -1;
int k, d, fdinput, fdoutput;
for (k = 0; argsexec[k] != NULL ; k++)
{
if (strcmp(argsexec[k], "<") == 0)
{
argsexec[k] = NULL;
input = k;
d = 1;
}
else if (strcmp(argsexec[k], ">") == 0)
{
argsexec[k] = NULL;
output = k;
d = 2;
}
else if (strcmp(argsexec[k], ">>") == 0)
{
argsexec[k] = NULL;
append = k;
d = 3;
}
if (d == 1)
{
fdinput = open(argsexec[input + 1], O_RDONLY, 0);
dup2(fdinput, STDIN_FILENO);
close(fdinput);
execvp(argsexec[0], argsexec);
}
if (d == 2)
{
int x, y;
char buffer[1024];
fdinput = open(argsexec[output - 1], O_RDONLY);
fdoutput = open(argsexec[output + 1], CREATE_FLAG, CREATE_MODE);
dup2(fdoutput, STDOUT_FILENO);
x = read(fdinput, buffer, 1024);
write(fdoutput, buffer, x);
close(fdinput);
close(fdoutput);
for (y = output; y < MAXARGNUM - 2; y++)
argsexec[y] = argsexec[y + 2];
argsexec[MAXARGNUM - 2] = NULL;
}
if (d == 3)
{
int x, y;
char buffer[1024];
fdinput = open(argsexec[output - 1], O_RDONLY);
fdoutput = open(argsexec[output + 1], CREATE_FLAGS, CREATE_MODE);
x = read(fdinput, buffer, 1024);
write(fdoutput, buffer, x);
close(fdinput);
close(fdoutput);
}
}
}
void add_path(char **dir, const char *begin, const char *end) //do the memory allocations, and add to the specified arrays.
{
if (end == begin)
{
begin = " ";
end = begin + 1;
}
size_t len = end - begin;
*dir = malloc(len + 1);
memmove(*dir, begin, len);
(*dir)[len] = '\0';
}
size_t tokenize(const char *path, char **dirs, size_t max_dirs, char delim) //tokenize the given input, with the given delimiter
{ //returns the size of the splitted parts of the string.
const char *begin = path;
const char *end;
size_t num_dirs = 0;
while (num_dirs < max_dirs && (end = strchr(begin, delim)) != 0)
{
add_path(&dirs[num_dirs++], begin, end);
begin = end + 1;
}
if (num_dirs < max_dirs && *begin != '\0')
add_path(&dirs[num_dirs++], begin, begin + strlen(begin));
return num_dirs;
}
void clearArgs()
{
int i;
for (i = 0; i < MAXARGNUM; ++i)
{
argsexec[i] = NULL;
}
}
int Ampersand()
{
int i;
for (i = 0; argsexec[i] != NULL ; i++)
{
if (strcmp(argsexec[i], "&") == 0)
{
return 1;
}
else
{
return 0;
}
}
}
void Setup()
{
while (1)
{
path = malloc((MAXCHARNUM + 1) * sizeof(char));
clearArgs();
fprintf(stderr, "333sh: ", NULL );
gets(str); //get the next commands
while (strlen(str) == 0)
{ //if the user enters empty string or space, ignore this input, read again.
fprintf(stderr, "333sh: ", NULL );
gets(str);
}
size_t commands = tokenize(str, argsexec, MAXARGNUM, ' ');
const char *path = getenv("PATH"); //get the system's path
ioredirection();
char * const arguments[] =
{ argsexec[0], argsexec[1], argsexec[2], argsexec[3], argsexec[4],
argsexec[5], argsexec[6], argsexec[7], (void*) NULL };
name = argsexec[0];
pid_t pid = fork();
wait(NULL );
if (Ampersand())
{
if (pid == 0)
{
int in = 1;
addJob(&list, pid, name, in);
}
}
if (pid == 0)
{
if (!Ampersand())
{
if (path == NULL )
{ //execl part
execl(path, argsexec[0], argsexec[1], argsexec[2], argsexec[3],
argsexec[4], argsexec[5], argsexec[6], argsexec[7], NULL );
}
else if (strcmp(argsexec[0], "dir") == 0 && argsexec[1] == NULL )
{
system("ls");
}
else if (strcmp(argsexec[0], "clr") == 0)
{
system("clear");
}
else if (strcmp(argsexec[0], "cd") == 0 && argsexec[1] == NULL )
{
system("pwd");
}
else if (strcmp(argsexec[0], "list_jobs") == 0 && argsexec[1] == NULL )
{
printJob(list);
}
else
{ //execvp part
execvp(argsexec[0], arguments);
}
}
}
}
}
int main(int argc, char const *argv[])
{
Setup();
return 0;
}
So how can i design a history part of this project ? Any idea would be appreciated.And sorry for asking that much long code.
Thanks
One way would be to create an array of 10 pointers to NULL initially. Add a routine update_history(<cmd issued>) or such that you call after every command you allow in your shell. It should:
(1) 1st call: malloc() space for the first command issued, and store the pointer to the
heap area in the array's first position
(2) Later calls: check the array for the first position with a NULL pointer, and store a pointer to the command there (using malloc() again). If you find no NULL pointer in the array (history is 10 commands long), go to (3)
(3) execute another new routine move_history(cmd issued). It moves the second array position (pointer) to the first, the 3rd to the 2nd, ..., the 10th to the 9th, and inserts a pointer to where <cmd_issued> is stored on the heap (using another malloc()) into the last array position. Don't forget to free() the heap memory that was allocated for the formerly first element that is no longer tracked.
You could then very easily print out the entire history (print through the array of pointers until you find a NULL pointer, but no more than 10 p/os; and print the command history numbers 1-10 (or 0-9) before the strings); and to print a particular command, you know in which array row the pointer to it is (if 1-based numbering, in row i-1). You can then read it and re-issue the command (don't forget to make that part of your history too).
Related
I am working on a program written in C that recursively walks a given directory in order to print out the Nth largest files and their sizes in bytes. I am using two arrays to account for the filesystem entry names and filesystem entry sizes respectively.
EDIT: I have updated my program to implement the suggestions shared in the comment section. My focus now is on correctly implementing a swap operation within my iSort function.
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
// number of files to display size information for
const int N = 10;
// a struct used to hold filesystem entry names and corresponding sizes in bytes
struct info {
char name[1024];
int size;
};
/* A simple implementation of insertion sort that will operate upon
an array of info structs, sorting them by their member size in
ascending order */
void iSort(struct info *fs_info[], int size, int info_size)
{
int i, j, key;
for (i = 1; i < size; i++)
{
key = fs_info[i]->size;
j = i - 1;
while (j >= 0 && fs_info[j]->size > key)
{
printf("info_size: %d\n", info_size);
// TODO complete a swap operation
memmove(fs_info[j + 1], fs_info[j], info_size);
j = j - 1;
}
fs_info[j + 1]->size = key;
}
}
void get_size(char *path, struct info fs_info[N], int info_size)
{
static int items_added = 0;
static int max_size = 0;
struct stat st;
if (stat(path, &st) == 0)
{
if (items_added < N) // if array capacity will not be exceeded
{
strcpy(fs_info[items_added].name, path);
fs_info[items_added].size = st.st_size;
if (st.st_size > max_size)
max_size = st.st_size;
items_added++;
}
else
{
// do a comparison to determine where to insert
// sort first
iSort(&fs_info, 10, info_size); // this function call results in a seqfault
}
}
else
{
printf("Error getting stat for entry %s: %d\n", path, stat(path, &st));
}
}
void walk(const char *currDir, struct info fs_info[N], int info_size)
{
DIR *dir = opendir(currDir);
struct dirent *entry;
if (dir == NULL)
{
// directory could not be opened
return;
}
while ((entry = readdir(dir)) != NULL)
{
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
{
// if directory is current dir or parent dir
continue;
}
char path_to_entry[1024];
snprintf(path_to_entry, sizeof(path_to_entry), "%s/%s", currDir, entry->d_name);
// use path_to_entry to call stats on the entry
get_size(path_to_entry, fs_info, info_size);
if (entry->d_type == DT_DIR)
{
// recursively visit subdirectories
walk(path_to_entry, fs_info, info_size);
}
}
closedir(dir);
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Usage: %s <target directory>\n", argv[0]);
}
const char *target_dir = argv[1];
struct info fs_entries[N];
const int info_size = sizeof(struct info);
for (int i = 0; i < N; i++)
{
strcpy(fs_entries[i].name, "");
fs_entries[i].size = 0;
}
printf("Finding %d largest files in: %s\n", N, target_dir);
walk(target_dir, fs_entries, info_size);
for (int i = 0; i < N; i++)
{
printf("%s : %d\n", fs_entries[i].name, fs_entries[i].size);
}
return 0;
}
Currently, the memmove() invocation in iSot() results in a EXC_BAD_ACCESS error, I am working on improving this function now. Any suggestions in the interim are appreciated. Thanks also to those who commented on this question earlier.
This is not so much an answer as it is an example of how one might code this with a bit less fiddling about with every bit/byte.
I don't run a flavour of UNIX, so this offering is untested and may contain typos and even bugs. I hope not.
#include <stdio.h> // From 'generic' to 'specific'
#include <string.h>
#include <sys/stat.h>
#include <dirent.h>
const int N = 10;
// Global array holding names and sizes
struct {
char name[ MAX_PATH ];
size_t size;
} biggies[ N ], wrk; // and a working buffer.
/* "Global" is bad for large projects.
* In this 'utility' program, global saves a LOT of typing/reading.
* Seek clarity, not conformity,
*
* "wrk" is used to buffer ALL paths encountered.
* Notice that each recursion is an EXTENSION of its parent.
* ONE working buffer to deal with.
*/
void walk() {
size_t len = strlen( wrk.name ); // The path so far...
DIR *dir;
if( ( dir = opendir( wrk.name ) ) == NULL )
return;
wrk.name[ len++ ] = '/'; // append a slash ahead of strcpy() below
struct dirent *entry;
while( ( entry = readdir( dir ) ) != NULL ) {
if( strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0 )
continue;
// Notice how each 'local' name is written to "the right spot" in one buffer
strcpy( wrk.name + len, entry->d_name );
if( entry->d_type == DT_DIR ) // directory, so recursion...
walk();
else {
struct stat st;
if( stat( wrk.name, &st ) != 0 ) {
fprintf( stderr, "Error stat'ing '%s'\n", wrk.name );
exit( EXIT_FAILURE );
}
// Add this info to working buffer.
wrk.size = st.st_size;
// Find where to 'insert' this (if it is larger than descending ordered list
for( int i = 0; i < N && biggies[i].size > wrk.size; i++ ) {} // loop
if( i < N ) {
// Slide smaller ones down (don't go out of bounds)
memmove( biggies[i + 1], biggies[i], (N-i-1) * sizeof biggies[0] );
// Copy this one in place.
memcpy( biggies[i], &wrk, sizeof biggies[0] );
}
}
}
closedir(dir);
}
int main( int argc, char *argv[]) {
char *target_dir = argv[1]; // This is okay, so far...
if( argc != 2 ) {
printf( "Usage: %s <target directory>\n", argv[0] );
puts( "Using current directory..." );
target_dir = ".";
}
strcpy( wrk.name, target_dir );
printf( "Finding %d largest files in: %s\n", N, wrk.name );
walk();
for( size_t i = 0; i < N && biggies[i].size != 0; i++ )
printf( "%s : %d\n", biggies[i].name, biggies[i].size);
return 0;
}
You don't need to pass the address of fs_info to iSort() function. fs_info is a pointer to first element of fs_entries array, which is enough to sort the array if the size of array is known. Also, you don't need to pass the size of element of array to iSort().
iSort() function implementation:
void iSort(struct info *fs_info, int size) {
for (int i = 1; i < size; ++i) {
int key = fs_info[i].size;
struct info x = fs_info[i];
int j = i - 1;
while (j >= 0 && fs_info[j].size > key) {
fs_info[j + 1] = fs_info[j];
j--;
}
fs_info[j + 1] = x;
}
}
Use memmove() in iSort():
void iSort (struct info *fs_info, int size) {
for (int i = 1; i < size; ++i) {
int key = fs_info[i].size;
struct info x = fs_info[i];
int j = i - 1;
while (j >= 0 && fs_info[j].size > key) {
j--;
}
if (j != i - 1) {
memmove (&fs_info[j + 2], &fs_info[j + 1], sizeof(*fs_info) * (i - j - 1));
}
memmove (&fs_info[j + 1], &x, sizeof(*fs_info));
}
}
Call iSort() function like this:
iSort(fs_info, N);
There is a lot of scope of improvement in your code, like, it would be good to have array of pointers to struct info instead of array of struct info, so that, during sort simply swapping the pointers required instead of swapping whole structure. Leaving it up to you to identify the improvements and implement them.
iv tried a lot of solutions to try to get this working (i.e using memcpy etc) I cant seem to find the issue, depending on what I try I either end up with gibberish or SEGV
iv spent a lot of time already googling and trying different ways, i still cant figure out why the arrays won't combine successfully
#include <stdio.h>
#include <stdint.h>
#include <dirent.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <unistd.h>
#define log_info printf
typedef struct
{
char* name;
//size_t size;
} entry_t;
/* qsort struct comparison function (C-string field) */
static int struct_cmp_by_name(const void* a, const void* b)
{
entry_t* ia = (entry_t*)a;
entry_t* ib = (entry_t*)b;
return strcmp(ia->name, ib->name);
/* strcmp functions works exactly as expected from comparison function */
}
entry_t* get_item_entries(const char* dirpath, int* count)
{
struct dirent* dent;
char buffer[512]; // fixed buffer
int dfd = 0,
n, r = 1; // item counter, rounds to loop
entry_t* p = NULL; // we fill this struct with items
loop:
n = 0;
printf("loop: %d, count:%d\n", r, *count);
// try to open dir
dfd = open(dirpath, O_RDONLY, 0);
if (dfd < 0)
{
printf("Invalid directory. (%s)\n", dirpath);
*count = -1;
return NULL;
}
else
{
printf("open(%s)\n", dirpath);
}
memset(buffer, 0, sizeof(buffer));
while (syscall(SYS_getdents, dfd, buffer, sizeof(buffer)) != 0)
{
dent = (struct dirent*)buffer;
while (dent->d_fileno)
{ // skip `.` and `..`
if (!strncmp(dent->d_name, "..", 2)
|| !strncmp(dent->d_name, ".", 1)) goto skip_dent;
// deal with filtering outside of this function, we just skip .., .
switch (r)
{ // first round: just count items
case 1:
{
// skip special cases
if (dent->d_fileno == 0) goto skip_dent;
break;
}
// second round: store filenames
case 0: p[n].name = strdup(dent->d_name); break;
}
n++;
skip_dent:
dent = (struct dirent*)((void*)dent + dent->d_reclen);
if (dent == (void*)&buffer[512]) break; // refill buffer
}
memset(buffer, 0, sizeof(buffer));
}
close(dfd);
// on first round, calloc for our list
if (!p)
{ // now n holds total item count, note it
p = calloc(n, sizeof(entry_t));
*count = n;
}
// first round passed, loop
r--; if (!r) goto loop;
// report count
printf("%d items at %p, from 1-%d\n", *count, (void*)p, *count);
/* resort using custom comparision function */
qsort(p, *count, sizeof(entry_t), struct_cmp_by_name);
// report items
//for (int i = 0; i < num; ++i) log_error( "%s", p[i].name);
return p;
}
int main(int argc, char* argv[])
{
int HDD_count = -1;
uint32_t total = -1;
int ext_count = -1;
entry_t* e = NULL;
entry_t *HDD = get_item_entries("/mnt/f/n", &HDD_count);
entry_t* ext = get_item_entries("/mnt/f/dls", &ext_count);
total = ext_count + HDD_count;
e = (entry_t*)malloc(sizeof *e * total);
if (e != NULL)
{
for (int i = 1; i < HDD_count; i++)
{
log_info("HDD[%i].name %s\n", i, HDD[i].name);
e[i].name = strdup(HDD[i].name);
}
for (int i = 1; i < ext_count; i++)
{
log_info("ext[%i].name %s\n", i, ext[i].name);
e[i + HDD_count].name = strdup(ext[i].name);
}
}
else
printf("Failed to Allocate the Array");
char tmp[256];
int i = 1, j;
for(j = 1; j <= total; j++)
{
snprintf(&tmp[0], 255, "%s", e[ j].name);
log_info("%i:%s\n", j , tmp);
}
return 0;
}
Here is a rewrite of a snippet of main() that I mentioned in my comment above:
#define CHECK(p, msg) if(!(p)) { printf("%s:%d: %s", __FILE__, __LINE__, msg); return 1;}
...
entry_t *HDD = get_item_entries("/mnt/f/n", &HDD_count);
CHECK(HDD, "HDD failed to get entries");
entry_t *ext = get_item_entries("/mnt/f/dls", &ext_count);
CHECK(ext, "ext failed to get entries");
uint32_t total = HDD_count + ext_count;
entry_t *e = malloc(total * sizeof(*e));
CHECK(e, "malloc failed");
for(int i = 0; i < HDD_count; i++) {
log_info("HDD[%i].name %s\n", i, HDD[i].name);
e[i].name = strdup(HDD[i].name);
}
// write a function instead of duplicating code?
for (int i = 0; i < ext_count; i++) {
log_info("ext[%i].name %s\n", i, ext[i].name);
e[HDD_count + i].name = strdup(ext[i].name);
}
It looks like a short lived program, but I would still free the values from strdup() and e itself.
This program tries to simulate FIFO and LRU page replacement. I am trying to implement a simple queue using a dynamically allocated array for the FIFO queue. I want the "page" to be stored in the array.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/*
* Some compile-time constants.
*/
#define REPLACE_NONE 0
#define REPLACE_FIFO 1
#define REPLACE_LRU 2
#define REPLACE_SECONDCHANCE 3
#define REPLACE_OPTIMAL 4
#define TRUE 1
#define FALSE 0
#define PROGRESS_BAR_WIDTH 60
#define MAX_LINE_LEN 100
/*
* Some function prototypes to keep the compiler happy.
*/
int setup(void);
int teardown(void);
int output_report(void);
long resolve_address(long, int);
void error_resolve_address(long, int);
/*
* Variables used to keep track of the number of memory-system events
* that are simulated.
*/
int page_faults = 0;
int mem_refs = 0;
int swap_outs = 0;
int swap_ins = 0;
/*
* Page-table information. You may want to modify this in order to
* implement schemes such as SECONDCHANCE. However, you are not required
* to do so.
*/
struct page_table_entry *page_table = NULL;
struct page_table_entry {
long page_num;
int dirty;
int free;
};
/*
* These global variables will be set in the main() function. The default
* values here are non-sensical, but it is safer to zero out a variable
* rather than trust to random data that might be stored in it -- this
* helps with debugging (i.e., eliminates a possible source of randomness
* in misbehaving programs).
*/
int size_of_frame = 0; /* power of 2 */
int size_of_memory = 0; /* number of frames */
int page_replacement_scheme = REPLACE_NONE;
long *queue;
void add_end(long page_num){
for(int i=0; i<size_of_memory; i++){
if(queue[i] == NULL){
queue[i] = page_num;
break;
}
}
}
long peek_front(){
return queue[0];
}
void remove_front(){
for(int i=0; i<size_of_memory; i++){
queue[i] = queue[i+1];
}
}
// typedef struct page_in_queue page_in_queue;
// struct page_in_queue {
// long page_num;
// page_in_queue *next;
// };
// page_in_queue *new_page(){
// page_in_queue *new_page;
// new_page = (page_in_queue *) malloc(sizeof(page_in_queue));
// new_page->next = NULL;
// return new_page;
// }
// page_in_queue *add_end(page_in_queue *queue, page_in_queue *page){
// page_in_queue *curr;
// if (queue == NULL) {
// page->next = NULL;
// return page;
// }
// for (curr = queue; curr->next != NULL; curr = curr->next);
// curr->next = page;
// page->next = NULL;
// return queue;
// }
// page_in_queue *peek_front(page_in_queue *queue) {
// return queue;
// }
// page_in_queue *remove_front(page_in_queue *queue){
// if (queue == NULL) {
// return NULL;
// }
// page_in_queue *new_front_page = queue->next;
// free(queue);
// return new_front_page;
// }
long *list;
void add(long page_num){
int i;
for (i=0; i<size_of_memory; i++){
list[i] = list[i+1];
}
list[i] = page_num;
}
long peek_least_used(){
return list[0];
}
/*
* Function to convert a logical address into its corresponding
* physical address. The value returned by this function is the
* physical address (or -1 if no physical address can exist for
* the logical address given the current page-allocation state.
*/
long resolve_address(long logical, int memwrite)
{
int i;
long page, frame;
long offset;
long mask = 0;
long effective;
/* Get the page and offset */
page = (logical >> size_of_frame);
for (i=0; i<size_of_frame; i++) {
mask = mask << 1;
mask |= 1;
}
offset = logical & mask;
if (page_replacement_scheme == 2){
add(page);
}
/* Find page in the inverted page table. */
frame = -1;
for ( i = 0; i < size_of_memory; i++ ) {
if (!page_table[i].free && page_table[i].page_num == page) {
frame = i;
break;
}
}
/* If frame is not -1, then we can successfully resolve the
* address and return the result. */
if (frame != -1) {
effective = (frame << size_of_frame) | offset;
return effective;
}
/* If we reach this point, there was a page fault. Find
* a free frame. */
page_faults++;
for ( i = 0; i < size_of_memory; i++) {
if (page_table[i].free) {
frame = i;
break;
}
}
// page_in_queue *temp_page;
// page_in_queue *queue;
long rem_page;
/* If we found a free frame, then patch up the
* page table entry and compute the effective
* address. Otherwise return -1.
*/
if (frame != -1) {
page_table[frame].page_num = page;
page_table[i].free = FALSE;
swap_ins++;
if (page_replacement_scheme == 1){
// temp_page = new_page();
// temp_page->page_num = page;
add_end(page);
}
effective = (frame << size_of_frame) | offset;
return effective;
}
else {
if (page_replacement_scheme == 1){
rem_page = peek_front();
for ( i = 0; i < size_of_memory; i++){
if(page_table[i].page_num == rem_page){
page_table[i].page_num = page;
page_table[i].free = FALSE;
page_table[i].dirty = memwrite;
swap_ins++;
if(page_table[i].dirty == 1){
swap_outs++;
}
frame = i;
break;
}
}
remove_front();
effective = (frame << size_of_frame) | offset;
return effective;
}
if (page_replacement_scheme == 2){
long temp = peek_least_used();
for ( i = 0; i < size_of_memory; i++){
if(page_table[i].page_num == temp){
page_table[i].page_num = page;
page_table[i].free = FALSE;
page_table[i].dirty = memwrite;
swap_ins++;
if(page_table[i].dirty == 1){
swap_outs++;
}
frame = i;
break;
}
}
effective = (frame << size_of_frame) | offset;
return effective;
}
if (page_replacement_scheme == 3){
}
}
}
/*
* Super-simple progress bar.
*/
void display_progress(int percent)
{
int to_date = PROGRESS_BAR_WIDTH * percent / 100;
static int last_to_date = 0;
int i;
if (last_to_date < to_date) {
last_to_date = to_date;
} else {
return;
}
printf("Progress [");
for (i=0; i<to_date; i++) {
printf(".");
}
for (; i<PROGRESS_BAR_WIDTH; i++) {
printf(" ");
}
printf("] %3d%%", percent);
printf("\r");
fflush(stdout);
}
int setup()
{
int i;
page_table = (struct page_table_entry *)malloc(
sizeof(struct page_table_entry) * size_of_memory
);
if (page_table == NULL) {
fprintf(stderr,
"Simulator error: cannot allocate memory for page table.\n");
exit(1);
}
for (i=0; i<size_of_memory; i++) {
page_table[i].free = TRUE;
}
return -1;
}
int teardown()
{
return -1;
}
void error_resolve_address(long a, int l)
{
fprintf(stderr, "\n");
fprintf(stderr,
"Simulator error: cannot resolve address 0x%lx at line %d\n",
a, l
);
exit(1);
}
int output_report()
{
printf("\n");
printf("Memory references: %d\n", mem_refs);
printf("Page faults: %d\n", page_faults);
printf("Swap ins: %d\n", swap_ins);
printf("Swap outs: %d\n", swap_outs);
return -1;
}
int main(int argc, char **argv)
{
/* For working with command-line arguments. */
int i;
char *s;
/* For working with input file. */
FILE *infile = NULL;
char *infile_name = NULL;
struct stat infile_stat;
int line_num = 0;
int infile_size = 0;
/* For processing each individual line in the input file. */
char buffer[MAX_LINE_LEN];
long addr;
char addr_type;
int is_write;
/* For making visible the work being done by the simulator. */
int show_progress = FALSE;
/* Process the command-line parameters. Note that the
* REPLACE_OPTIMAL scheme is not required for A#3.
*/
for (i=1; i < argc; i++) {
if (strncmp(argv[i], "--replace=", 9) == 0) {
s = strstr(argv[i], "=") + 1;
if (strcmp(s, "fifo") == 0) {
page_replacement_scheme = REPLACE_FIFO;
} else if (strcmp(s, "lru") == 0) {
page_replacement_scheme = REPLACE_LRU;
} else if (strcmp(s, "secondchance") == 0) {
page_replacement_scheme = REPLACE_SECONDCHANCE;
} else if (strcmp(s, "optimal") == 0) {
page_replacement_scheme = REPLACE_OPTIMAL;
} else {
page_replacement_scheme = REPLACE_NONE;
}
} else if (strncmp(argv[i], "--file=", 7) == 0) {
infile_name = strstr(argv[i], "=") + 1;
} else if (strncmp(argv[i], "--framesize=", 12) == 0) {
s = strstr(argv[i], "=") + 1;
size_of_frame = atoi(s);
} else if (strncmp(argv[i], "--numframes=", 12) == 0) {
s = strstr(argv[i], "=") + 1;
size_of_memory = atoi(s);
if (page_replacement_scheme == 1){
queue = (long *)malloc(sizeof(long)*size_of_memory);
}
if (page_replacement_scheme == 2){
list = (long *)malloc(sizeof(long)*size_of_memory);
}
} else if (strcmp(argv[i], "--progress") == 0) {
show_progress = TRUE;
}
}
if (infile_name == NULL) {
infile = stdin;
} else if (stat(infile_name, &infile_stat) == 0) {
infile_size = (int)(infile_stat.st_size);
/* If this fails, infile will be null */
infile = fopen(infile_name, "r");
}
if (page_replacement_scheme == REPLACE_NONE ||
size_of_frame <= 0 ||
size_of_memory <= 0 ||
infile == NULL)
{
fprintf(stderr,
"usage: %s --framesize=<m> --numframes=<n>", argv[0]);
fprintf(stderr,
" --replace={fifo|lru|optimal} [--file=<filename>]\n");
exit(1);
}
setup();
while (fgets(buffer, MAX_LINE_LEN-1, infile)) {
line_num++;
if (strstr(buffer, ":")) {
sscanf(buffer, "%c: %lx", &addr_type, &addr);
if (addr_type == 'W') {
is_write = TRUE;
} else {
is_write = FALSE;
}
if (resolve_address(addr, is_write) == -1) {
error_resolve_address(addr, line_num);
}
mem_refs++;
}
if (show_progress) {
display_progress(ftell(infile) * 100 / infile_size);
}
}
teardown();
output_report();
fclose(infile);
exit(0);
}
The file is saved as virtmem.c. This is the makefile:
#
# "makefile" for the virtual-memory simulation.
#
CC=gcc
CFLAGS=-c -Wall -g
all: virtmem
virtmem.o: virtmem.c
$(CC) $(CFLAGS) virtmem.c
virtmem: virtmem.o
$(CC) virtmem.o -o virtmem
clean:
rm -rf *.o virtmem
After running the "make" command, I run the executable with these inputs
./virtmem --framesize=12 --numframes=100 --replace=fifo --file=traces/ls_out.txt --progress
But it is giving a segmentation fault at the conditional "if(queue[i] == NULL)", saying the memory location cannot be accessed. The gdb output is as follows:
Program received signal SIGSEGV, Segmentation fault.
0x0000555555554bea in add_end (page_num=34158723704) at virtmem.c:80
80 if(queue[i] == (long)0){
(gdb) print queue[i]
Cannot access memory at address 0x0
(gdb)
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
struct configurations *read_file(char * file_name)
{
FILE *f = fopen(file_name ,"r");
if(!f)
{
printf("**********Unable to open config.txt*********");
return NULL;
}
int i, prev, count;
char *line = NULL, buff[480] = {'\0'};
size_t len;
struct configurations *config = (struct configurations *) malloc(sizeof(struct configurations));
while (getline(&line,&len,f) != -1)
{
if(!strncmp("SERVERPORT = ",line,strlen("SERVERPORT = "))){
config->server_Port = atoi(strstr(line, " = ")+3);
}
else if(!strncmp("SCHEDULING = ",line,strlen("SCHEDULING = "))){
strcpy(config->sched,strstr(line, " = ") + 3);
}
By subctracting 1 from the length.
There are multiple simple and obvious improvements to your code
You should always check the return value before using from strstr().
strlen("SERVERPORT = ") is a very ugly way of writing 12, inefficient too.
You should use a little bit more white spaces to make the code readable.
Don't cast the return value of malloc() it only makes it more difficult to read and might hide a bug if you forget to include stdlib.h.
ALWAYS check if malloc() returned NULL before dereferencing the pointer.
Split every line at =, remove all surrounding white spaces from the 2 resulting values and then check which variable it is and assign the corresponding value.
As it is your code will fail if SERVERPORT=1234 for example, and even if it's ugly and spaces around the = operator are better, both should be valid unless of course you explicitly want the spaces.
Also by removing surrounding white spaces you ensure that any '\n' that was read by getline() will be removed from the value.
This is a quick API a wrote just now to show you how I would do it, of course every one has their own taste and ways to do things, but I hope it helps figuring out your mistakes
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
struct KeyValue {
char *key;
char *value;
};
struct KeyFile {
size_t size;
struct KeyValue *entries;
size_t count;
};
static struct KeyFile *
keyfile_new(void)
{
struct KeyFile *kf;
kf = malloc(sizeof(*kf));
if (kf == NULL)
return NULL;
kf->entries = malloc(10 * sizeof(*kf->entries));
if (kf->entries == NULL) {
kf->size = 0;
} else {
kf->size = 10;
}
kf->count = 0;
return kf;
}
static int
keyfile_add_value(struct KeyFile *kf, const char *const key, const char *const value)
{
struct KeyValue *entry;
if (kf->count + 1 >= kf->size) {
void *pointer;
pointer = realloc(kf->entries, (kf->size + 10) * sizeof(*kf->entries));
if (pointer == NULL)
return -1;
kf->entries = pointer;
kf->size += 10;
}
entry = &kf->entries[kf->count++];
entry->key = strdup(key);
entry->value = strdup(value);
return 0;
}
static void
keyfile_free(struct KeyFile *kf)
{
for (size_t i = 0 ; i < kf->count ; ++i) {
struct KeyValue *entry;
entry = &kf->entries[i];
free(entry->key);
free(entry->value);
}
free(kf->entries);
free(kf);
}
static struct KeyFile *
keyfile_read(const char *const path)
{
FILE *file;
struct KeyFile *kf;
size_t length;
char *line;
line = NULL;
length = 0;
file = fopen(path, "r");
if (file == NULL)
return NULL;
kf = keyfile_new();
if (kf == NULL)
return NULL;
while (getline(&line, &length, file) > 0) {
char *op;
char *key;
char *value;
op = strchr(line, '=');
if (op == NULL) {
fprintf(stderr, "malformed line!\n");
} else {
*op = '\0';
key = line;
while (isspace((unsigned char) *key) != 0)
++key;
value = op + 1;
op -= 1;
while (isspace((unsigned char) *op) != 0)
*(op--) = '\0';
while (isspace((unsigned char) *value) != 0)
value += 1;
op = value + strlen(value) - 1;
while (isspace((unsigned char) *op) != 0)
*(op--) = '\0';
if (keyfile_add_value(kf, key, value) != 0)
goto error;
}
}
fclose(file);
free(line);
return kf;
error:
keyfile_free(kf);
fclose(file);
free(line);
return NULL;
}
static void
keyfile_display(const struct KeyFile *const kf)
{
for (size_t i = 0 ; i < kf->count ; ++i) {
const struct KeyValue *entry;
entry = &kf->entries[i];
fprintf(stdout, "/%s/ => /%s/\n", entry->key, entry->value);
}
}
You could improve this to add lookup functions, to find specific values in the settings file. And you can make it a standalone library to use it in many projects too.
I am trying to make a suid application that will only execute ruby scripts located in a restricted folder. I have tried to do this using realpath(3) but it is only returning the first segment of the path. Below is my code...
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#define SUEXEC_STR_LEN 2048
#define RUBY_APP "/usr/bin/ruby"
#define DIRECTORY_SEPARATOR "/"
static void safepath(const char *path_in, char * path_out, int outlen) {
realpath(path_in, path_out);
}
int main ( int argc, char *argv[] )
{
char cmd[SUEXEC_STR_LEN];
char path_out[SUEXEC_STR_LEN];
char path_in[SUEXEC_STR_LEN];
char *cp = &cmd[0];
strncpy(cp, RUBY_APP, SUEXEC_STR_LEN - 1);
strncpy(path_in, DIRECTORY_SEPARATOR, SUEXEC_STR_LEN - 1);
strncat(path_in,argv[1],SUEXEC_STR_LEN - 1);
safepath(path_in,path_out,SUEXEC_STR_LEN - 1);
printf("path_in=%s path_out=%s\n",path_in,path_out);
setuid( 0 );
// system( cmd );
return 0;
}
This is an example of the result I'm getting
root#server01:/root/src# ./a.out foo/bar/../test
path_in=/foo/bar/../test path_out=/foo
This is the result I want
root#server01:/root/src# ./a.out foo/bar/../test
path_in=/foo/bar/../test path_out=/foo/test
You should check for realpath()'s return value. As described in its man page,
RETURN VALUE
If there is no error, realpath() returns a pointer to the resolved_path.
Otherwise it returns a NULL pointer, and the contents of the array resolved_path are undefined. The global variable errno is set to indicate the error.
Also in ERRORS section of its man page,
ENOENT The named file does not exist.
Thus, if there is indeed no /foo/test in your file system, realpath() should return NULL and the output is undefined.
So, here's a working sketch of how you might go about it in C on Linux. This is a quick hack that I do not represent as being exemplary code, efficient, etc. It (ab)uses PATH_MAX, uses “bad” string functions, and may leak memory, eat your cat, and have corner cases that segfault, etc. When it breaks, you get to keep both parts.
The basic idea is to go through the given path, breaking it up into “words” using “/” as the delimiter. Then, go through the list, pushing the “words” onto a stack, but ignoring if empty or “.”, and popping if “..”, then serializing the stack by starting at the bottom and accumulating a string with slashes in between.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <linux/limits.h>
typedef struct stack_s {
char *data[PATH_MAX];
int top;
} stack_s;
void stack_push(stack_s *s, char *c) {
s->data[s->top++] = c;
}
char *stack_pop(stack_s *s) {
if( s->top <= 0 ) {
return NULL;
}
s->top--;
return s->data[s->top];
}
// DANGER! DANGER! Returns malloc()ed pointer that you must free()
char *stack_serialize(stack_s *s) {
int i;
char *buf;
int len=1;
for(i=0; i<s->top; i++) {
len += strlen(s->data[i]);
len++; // For a slash
}
buf = malloc(len);
*buf = '\0';
for(i=0; i<s->top-1; i++) {
strcat(buf, s->data[i]);
strcat(buf, "/");
}
strcat(buf, s->data[i]);
return buf;
}
// DANGER! DANGER! Returns malloc()ed pointer that you must free()
char *semicanonicalize(char *src) {
char *word[PATH_MAX] = {NULL};
int w=0;
int n_words;
char *buf;
int len;
char *p, *q;
stack_s dir_stack = {{NULL},0};
// Make a copy of the input string:
len = strlen(src);
buf = strdup(src);
// Replace slashes with NULs and record the start of each "word"
q = buf+len;
word[0]=buf;
for(p=buf,w=0; p<q; p++) {
if(*p=='/') {
*p = '\0';
word[++w] = p+1;
}
}
n_words=w+1;
// We push w[0] unconditionally to preserve slashes and dots at the
// start of the source path:
stack_push(&dir_stack, word[0]);
for(w=1; w<n_words; w++) {
len = strlen(word[w]);
if( len == 0 ) {
// Must've hit a double slash
continue;
}
if( *word[w] == '.' ) {
if( len == 1 ) {
// Must've hit a dot
continue;
}
if( len == 2 && *(word[w]+1)=='.' ) {
// Must've hit a '..'
(void)stack_pop(&dir_stack);
continue;
}
}
// If we get to here, the current "word" isn't "", ".", or "..", so
// we push it on the stack:
stack_push(&dir_stack, word[w]);
}
p = stack_serialize(&dir_stack);
free(buf);
return p;
}
int main(void)
{
char *in[] = { "/home/emmet/../foo//./bar/quux/../.",
"../home/emmet/../foo//./bar/quux/../.",
"./home/emmet/../foo//./bar/quux/../.",
"home/emmet/../foo//./bar/quux/../."
};
char *out;
for(int i=0; i<4; i++) {
out = semicanonicalize(in[i]);
printf("%s \t->\t %s\n", in[i], out);
free(out);
}
return 0;
}
This is the code which I used as a solution to the problem. It may have some bugs remaining in it, and it isn't checking the outlen argument to avoid segfaults and other uglyness but it seems to get the job done.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <linux/limits.h>
#define SUEXEC_STR_LEN 2048
#define RUBY_APP "/usr/bin/ruby"
#define DIRECTORY_SEPARATOR "/"
#define RUBY_EXT ".rb"
#define SERVICES_BASE_PATH "/path/to/ruby/services"
static inline int isDirSeparator(const char c) { return (c == '/' || c == '\\'); }
static void safepath(const char *path_in, char * path_out, int outlen)
{
char *dirs[PATH_MAX];
int depth = 0;
char *dstptr = path_out;
const char *srcptr = path_in;
*dstptr++ = DIRECTORY_SEPARATOR[0];
dirs[0] = dstptr;
dirs[1] = NULL;
depth++;
while (1) {
if ((srcptr[0] == '.') && isDirSeparator(srcptr[1])) {
srcptr += 2;
} else if (srcptr[0] == '.' && srcptr[1] == '.' && isDirSeparator(srcptr[2])) {
if (depth > 1) {
dirs[depth] = NULL;
depth--;
dstptr = dirs[depth-1];
} else {
dstptr = dirs[0];
}
srcptr += 3;
} else if (srcptr[0] == '.' && srcptr[1] == '.' && srcptr[2] == 0) {
if (depth == 1) {
srcptr += 2;
} else {
depth--;
dstptr = dirs[depth-1];
srcptr += 2;
}
} else {
while (!isDirSeparator(srcptr[0]) && srcptr[0]) {
*dstptr++ = *srcptr++;
}
if (srcptr[0] == 0) {
if (dstptr != dirs[0] && isDirSeparator(dstptr[-1])) {
dstptr[-1] = 0;
}
dstptr[0] = 0;
return;
} else if (isDirSeparator(srcptr[0])) {
if (dstptr == dirs[0]) {
srcptr++;
} else {
*dstptr++ = *srcptr++;
dirs[depth] = dstptr;
depth++;
}
while (isDirSeparator(srcptr[0]) && srcptr[0]) {
srcptr++;
}
} else {
path_out[0] = 0;
return;
}
}
}
}
int main ( int argc, char *argv[] )
{
int ret;
char cmd[SUEXEC_STR_LEN];
char path_out[SUEXEC_STR_LEN];
char path_in[SUEXEC_STR_LEN];
char *cp = &cmd[0];
if (argc < 2) {
fprintf(stderr,"usage: %s <service>\n",argv[0]);
return 1;
}
strncpy(cp, RUBY_APP, SUEXEC_STR_LEN - 1);
strncpy(path_in, DIRECTORY_SEPARATOR, SUEXEC_STR_LEN - 1);
strncat(path_in,argv[1],SUEXEC_STR_LEN - 1);
safepath(path_in,path_out,SUEXEC_STR_LEN - 1);
//printf("path_in=%s path_out=%s\n",path_in,path_out);
strncat(cmd," ",SUEXEC_STR_LEN - (1+sizeof(RUBY_EXT)));
strncat(cmd,SERVICES_BASE_PATH,SUEXEC_STR_LEN - (1+sizeof(RUBY_EXT)));
strncat(cmd,path_out,SUEXEC_STR_LEN - (1+sizeof(RUBY_EXT)));
strncat(cmd,RUBY_EXT,SUEXEC_STR_LEN - 1);
setuid( 0 );
ret = system( cmd );
if (ret == -1) {
return ret;
}
ret = WEXITSTATUS(ret);
return ret;
}