unix programming 2章_1

「Unix/Linuxプログラミング 理論と実践」読み進めています。

2章の課題を2つほど進めます。

(課題2.10)
whoコマンドを拡張してwho am iおよびwhoamiというシンタックスもサポートするように実装する。

who am iとwhoamiは何が違うのか。

whoamiのmanを引いてみよう

man whoami

説明
whoami は現在の実効ユーザー id に対応するユーザー名を表示する。 whoami は、コマンド ‘id -un’ と等価である。

実効ユーザidに対応するユーザ名を表示する点がことなりそうだ。
whoは実ユーザidに対応するユーザ名を表示する。

次にwhoを引いてみる

man who

名前

オプション以外の引数を 2 つ与えた場合、 who は who を起動したユーザ (標準入力から決定される) についての情報だけを表示する。このとき名前の前にホスト名が置かれる。普通は 2 つの引数には、‘am i’
が使われる。

要するにwho am iだろうがwho you areだろうがなんだって良いのである。
引数が2つ入力された場合は自分の情報だけ表示するようになる。

* who am iを実装する

起動したユーザの情報を比較するにはどうすればよいか。
実装としては、utmp->ut_userを現在のプロセスの実ユーザidを比較して一緒であれば表示するようにする。

* whoamiを実装する

対してwhoamiではut_pidからプロセスの情報を引っ張ってきて、そのユーザidと現在のプロセスの実効ユーザidを比較する。
調べたところuid -> user名への変換は難しい模様。代わりにgetloginやcuseridというライブラリ関数があるのでそれを用いる。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <utmp.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>

void showtime(long);
void show_info(struct utmp *, int ami);

int main(int argc, char * argv[])
{
  struct utmp utbuf;
  int utmpfd;
  int ami = 0;

  if (3 <= argc) {     ami = 1;   }   if ((utmpfd = open(UTMP_FILE, O_RDONLY)) == -1) {     perror(UTMP_FILE);     exit(1);   }   while(read(utmpfd, &utbuf, sizeof(utbuf)) == sizeof(utbuf))     show_info(&utbuf, ami);   close(utmpfd);   return 0; } void show_info(struct utmp *utbufp, int ami) {   if (utbufp->ut_type != USER_PROCESS)
    return;

  if ((ami == 1) && (strcmp(utbufp->ut_name, getlogin()) != 0)) {
    return;
  }
  printf("%-8.8s", utbufp->ut_name);
  printf(" ");
  printf("%-8.8s", utbufp->ut_line);
  printf(" ");
  showtime( utbufp->ut_time );
#ifdef SHOWHOST
  if (utbufp->ut_host[0] != '\0')
    printf(" (%s)", utbufp->ut_host);
#endif
  printf("\n");
}

void showtime(long timeval)
{
  char *cp;
  cp = ctime(&timeval);
  printf("%12.12s", cp+4);
}

(課題2.11)
自作したcp01.cは入力、出力を同じファイルに設定した時にどのように振る舞うか?
また本来はどのようにあるべきか、検討実装せよ。

cp01.cはファイル名の検証については全く実装されていない。
出力ファイルに関してはcreatシステムコールを利用することでファイルを作成している。
入力ファイルと出力ファイルの引数が同じに設定されていた際にはcreatがコールされた段階でファイルデータが削除される。
そのためファイルコンテンツが削除されるような挙動となる。

またこれに関しては検証を実装すべきだと考える。
入力ファイル名と出力ファイル名が同じファイルであればエラーとみなして動作を中止するようにする

そういうわけで下記のように仕上がった

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

#define BUFFERSIZE 4096
#define COPYMODE 0644

int main(int ac, char *av[])
{
  int in_fd, out_fd, len;
  char buf[BUFFERSIZE];

  struct stat *in_st;
  struct stat *out_st;

  if (ac < 3) {
    printf("usage -- cp01 <source> <destination>\n");
    exit(-1);
  }

  if (stat(av[1], in_st) == -1 || stat(av[2], out_st) == -1) {
    printf("error. failed to get stat info.");
    exit(-1);
  }

  if (in_st->st_ino == out_st->st_ino) {
    printf("error. input file and output file must be different.");
    exit(-1);
  }

  if ((in_fd = open(av[1], O_RDONLY)) == -1) {
    perror("failed to open source file.");
    exit(-1);
  }

  if ((out_fd = creat(av[2], COPYMODE)) == -1) {
    perror("failed to open destination file.");
    exit(-1);
  }


  while ((len = read(in_fd, buf, BUFFERSIZE)) > 0) {
    if (write(out_fd, buf, len) == -1) {
      perror("failed to write output file.");
      exit(-1);
    }
  }
}

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です