Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

Why aren't you using Plan 9?

Name: Anonymous 2012-04-13 18:21


      __
     (  \
 __   \  '\
(  "-_ \ .-'----._
 '-_  "v"         "-
    "Y'             ".
     |                |
     |        o     o |
     |          .<>.  |
      \         "Ll"  |
       |             .'
       |             |
       (             /
      /'\         . \
      "--^--.__,\_)-'


The only thing it's missing is drivers for modern hardware, but it will run great on a VM or a free computer found on the side of the road.

The GUI is simple and beautiful, and once you get over the fact that it's NOT UNIX it's really nice to use.

Name: Anonymous 2012-04-13 18:26

so it's GNU?

Name: Anonymous 2012-04-13 18:28

I had a Plan 9 file server for years, running on an old Thinkpad, but nowadays the closest I get is using a Suckless WM.

Name: Anonymous 2012-04-13 18:29

>>2

GNU is NOW UNIX

Name: Anonymous 2012-04-13 18:30

Because I have to learn that it's NOT UNIX, meaning, I have to learn Plan 9. Laziness, and not having some WALKTHROUGHS are barriers to entry.

Name: Anonymous 2012-04-13 18:36

>>5
Investment

Name: Anonymous 2012-04-13 18:37

>>3

I have a SheevaPlug on which I intend to install the ARM port of Plan 9, but I haven't got around to it yet.

I used to run it on my old Acer laptop, but now the disk controller is fucked up and I can't into hardware.

It's still pretty nice under Qemu+Drawterm, but I wish I had it running on real hardware.

>>5

Yeah, it took me several years of poking around at it and then giving up before I got used to it.

Now I really enjoy the Acme interface (although I'm still far more productive in Emacs), but I'm still not particularly fluent at the command line.

Name: Anonymous 2012-04-13 19:14


      __    /---------------------\    __
     (  \   \  install plan nine  /   /  )
 __   \  '\  \______ ..... ______/  /'  /   __
(  "-_ \ .-'----._  \_____/  _.----'-. / _-"  )
 '-_  "v"         "-  /    \  -"         "v"  _-'
    "Y'             ".     ."             'Y"
     |                |    |                |
     |        o     o |    | o     o        |
     |          .<>.  |    |  .<>.          |
      \         "Ll"  |    |  "jJ"         /
       |             .'    '.             |
       |             |     |             |
       (             /     \             )
      /'\         . \      / .         /'\
      "--^--.__,\_)-'      '-(_/,__.--^--"

Name: Anonymous 2012-04-13 19:17

>>8

Why would it eat some spaces but not others?

Bleh.

Name: Anonymous 2012-04-13 19:19

ANUS

Name: Anonymous 2012-04-13 19:25


      __    /---------------------\    __     
     (  \   \  install plan nine  /   /  )    
 __   \  '\  \______ ..... ______/  /'  /   __
(  "-_ \ .-'----._  \_____/  _.----'-. / _-"  )
 '-_  "v"         "-  / \  -"         "v"  _-'
    "Y'             ".  ."             'Y"    
     |                | |                |    
     |        o     o | | o     o        |    
     |          .<>.  | |  .<>.          |    
      \         "Ll"  | |  "jJ"         /     
       |             .' '.             |      
       |             |   |             |      
       (             /   \             )      
      /'\         . \    / .         /'\      
      "--^--.__,\_)-'    '-(_/,__.--^--"


>>9

[quote]
     The paste utility concatenates the corresponding lines of the given input
     files, replacing all but the last file's newline characters with a single
     tab character,
[/quote]

tab

Oh.

Name: Anonymous 2012-04-13 19:49

Why should I use Plan 9 if I have Haiku?

Name: Anonymous 2012-04-13 20:13

I'm using open genera, a LISP OS made for programming

Name: Anonymous 2012-04-13 20:24

>>13

Emacs is a great operating system; too bad it doesn't have a decent text editor!

Name: Anonymous 2012-04-13 20:25

>>14
Your post is correct, which is why i use Zmacs with open genera. A combination that no other can beat.

Name: Anonymous 2012-04-13 20:27

Dead people are supposed to stay dead. You're not supposed to bring them back to life. Those aliens were silly.

Name: Anonymous 2012-04-13 20:29

Use gosmacs and FLABBERGAST your opponents. BRRRRGBRRRRRGBRRRRRRRRGBRRRRRRRRGBRRRRRRR. Introducing: James "The Father of Java" Gosling!

Name: Anonymous 2012-04-13 21:20

I use Inferno OS. It's quite a system. It's a better Unix than Unix.

Name: Anonymous 2012-04-13 21:54

>>18
Inferno is coded in Limbo, the successor to Alef. Would any self-respecting goy want to use an OS named after Satanic Kabbalistic Jew worship?

Name: Anonymous 2012-04-13 22:02

>>1
But UNIX is kawaii as fuck.

Fuck off, ``faggot".

Name: Anonymous 2012-04-13 23:42

>>19
That doesn't matter. The language and the programs either performs its job at controlling the computer or it doesn't. Limbo works and Inferno works.

Name: Anonymous 2012-04-14 2:46

Name: Anonymous 2012-04-14 2:48

Is there any effort for Inferno to be on some embedded thing from this decade? like that raspberry pi thing.

Name: Anonymous 2012-04-14 2:51

>>23
I'm working on a private project to get Inferno on an Openpandora device.

Name: Anonymous 2012-04-14 3:36

>>20

But EUNUCHS is kawaii as fuck.

Then you'll really like Plan 9!

>>23

http://youtu.be/dF_-jQc53jw

It's running on top of the Android Loonix kernel because of PROPRIETARY DRIVERS THAT DO NOT RESPECT YOUR FREEDOM, but Inferno was always meant to run virtually on many different platforms.

Name: Anonymous 2012-04-14 5:33

The GUI is simple and beautiful

Ha-ha. No. It's uglier than xterm. Also it lacks software.

Name: Anonymous 2012-04-15 10:02

If you make a gentoo fork for it I will try it.

I promise!

Name: Anonymous 2012-04-15 10:53

Why though?

Name: Anonymous 2012-04-15 19:37

>>26

At first I found it a bit confusing but I've always thought it was very pretty.

The nice simple pastel colours are pleasing to the eye.

Shiny glass effects and transparency and whooshing windows are just clutter.

>>27

Wat?

>>28

Because Plan 9 is a great environment for programmers to learn and explore, and is not diluted by attempts to make it practical for or popular with lay users.

Name: surrealdeal 2012-04-15 20:30

It's benefits aren't all that compelling, and anyone that would be interested in it is already fluent enough in *nix not to give a fuck about it

Name: Anonymous 2012-04-15 20:57

The GUI is a good idea, it's just too much of a paradigm shift from the WIMP stuff we're all used to. And that's a bad thing.

It is kind of cool as an historic interest though, much like the Blit.

Name: Anonymous 2012-04-16 5:57

>>28
Literally any resource you can access in a Plan 9 system is a file. Network resources can be easily accessed by mounting the remote system into an empty directory. These two powerful features means that Plan 9 systems are very flexible and yet, easy to use for a huge number of modern use cases.

Name: Anonymous 2012-04-16 5:59

Name: Anonymous 2012-04-16 9:07

>>32
Literally any resource you can access in a Plan 9 system is a file. Network resources can be easily accessed by mounting the remote system into an empty directory.
So how do I mount /prague/ somewhere?

Name: Anonymous 2012-04-16 10:50

>>34
Actually, I don't know how to do that. I'll need to look into that.

Name: Anonymous 2012-04-16 11:04

Because I can install GNU/Linux on any computer on the side of the road too.

Name: Anonymous 2012-04-16 12:45

Name: Anonymous 2012-04-16 19:31

>>37
Doing it the Plan 9 way is a matter of implementing a progscrape filesystem (or a more general httpfs).

Name: Anonymous 2012-04-16 20:10

>>38

webfs[1] already exists; writing a progfs on top of it would be trivial.

One might use it like this:
% progfs
% ls /mnt/prog/frontpage
free programming classes
why arent you using plan 9
sepples
jews enslave us
aaa penis
excel function
multithreading for fagstorms
anus
% ls '/mnt/prog/frontpage/why arent you using plan 9'
date
count
posts
% cat '/mnt/prog/frontpage/why arent you using plan 9/count'
39
% cat '/mnt/prog/frontpage/why arent you using plan 9/posts/38'
38 Name: Anonymous : 2012-04-16 19:31

>>37
Doing it the Plan 9 way is a matter of implementing a progscrape filesystem (or a more general httpfs).

%

Now that I wrote all this I think I want to go implement it!

[1]: http://plan9.bell-labs.com/magic/man2html/4/webfs

Name: Anonymous 2012-04-16 21:30

Not really what we were talking about, but here's a FUSE progfs. You'll need http://code.google.com/p/fusepy/.
It's twice as slow as balls and it doesn't properly set mtime/ctime/atime because it does very little caching and I don't want getattr to instigate a web request every time, but it kind of works. Someone else can figure out how to export it over 9P.

#!/usr/bin/python

import argparse
import errno
import json
import os
import re
import stat
import sys
import time
import urllib2

import fuse


unix_time = lambda s: \
    int(time.mktime(time.strptime(s, '%a, %d %b %Y %H:%M:%S %Z')))

def parse_path(path):
    """
    Paths are at most three levels deep. This always returns a three-member
    list and fills the blanks with None.
    """
    path = filter(None, path.split('/'))
    if len(path) > 3:
        raise fuse.FuseOSError(errno.ENOENT)
    while len(path) < 3:
        path.append(None)
    return path

def parse_name(name):
    """
    Takes the contents of the name field and returns ['name!trip', 'email'].
    """
    m = re.match(name,
                 '^([^<]*)<a href="mailto:([^"]*)">([^<]*)</a>(.*)$',
                 re.DOTALL)
    if m is None:
        return '', ''
    else:
        return ''.join(m.group(1), m.group(3), m.group(4)), m.group(2)


class HeadRequest(urllib2.Request):
    """Makes a HEAD request rather than GET."""
    get_method = lambda self: 'HEAD'


class ProgFS(fuse.LoggingMixIn, fuse.Operations):
    def __init__(self, board='prog', tmpdir=None):
        self.board = board
        self.subject_url = 'http://dis.4chan.org/%s/subject.txt' % self.board
        self.thread_url = 'http://dis.4chan.org/json/%s/%%s/' % self.board
        self.post_url = 'http://dis.4chan.org/json/%s/%%s/%%s' % self.board

        self.files = {}

        self.last_modified = 0
        self.threads = {}
        self._get_subject_txt()

    def _get_subject_txt(self):
        """
        Checks if subject.txt has changed, and if so, fetches the new file
        and updates the threads table.
        """
        r = urllib2.urlopen(HeadRequest(self.subject_url))
        if self.last_modified >= unix_time(r.headers.getheader('last-modified')):
            # No change. Stop now.
            r.close()
            return
        r.close()

        r = urllib2.urlopen(self.subject_url)
        self.last_modified = unix_time(r.headers.getheader('last-modified'))

        regex = re.compile(u"""
            ^(?P<subject>.*)    # Subject
            <>
            .*?                 # Creator's name
            <>
            .*?                 # Thread icon
            <>
            (?P<id>-?\d*)       # Time posted/thread ID
            <>
            (?P<replies>\d*)    # Number of replies
            <>
            .*?                 # ???
            <>
            (?P<last_post>\d*)  # Time of last post
            \\n$""", re.VERBOSE)

        for line in r.readlines():
            # FIXME this loop is slow as balls
            # Replacing the regex with split('<>') is faster, but Shiichan is
            # full of corner cases and that loses /prog/ threads.
            thread = regex.match(line).groupdict()
            if thread['id'] not in self.threads:
                self.threads[thread['id']] = {}
                self.threads[thread['id']]['title'] = thread['subject']
            self.threads[thread['id']]['last_modified'] = \
                float(thread['last_post'])
            self.threads[thread['id']]['posts'] = \
                int(thread['replies'])
        r.close()

    def getattr(self, path, fh=None):
        path = parse_path(path)

        if not path[0]:
            return {'st_mode': (stat.S_IFDIR | 0555),
                    'st_ctime': self.last_modified,
                    'st_mtime': self.last_modified,
                    'st_atime': time.time(),
                    'st_uid': os.getuid(),
                    'st_gid': os.getgid()}

        if path[0] not in self.threads:
            raise fuse.FuseOSError(errno.ENOENT)

        if not path[1]:
            # Thread folder
            return {'st_mode': (stat.S_IFDIR | 0555),
                    'st_ctime': self.threads[path[0]]['last_modified'],
                    'st_mtime': self.threads[path[0]]['last_modified'],
                    'st_atime': self.threads[path[0]]['last_modified'],
                    'st_uid': os.getuid(),
                    'st_gid': os.getgid()}

        if path[1] == 'title' and not path[2]:
            # Thread title file
            return {'st_mode': (stat.S_IFREG | 0444),
                    'st_ctime': float(path[0]),
                    'st_mtime': float(path[0]),
                    'st_atime': float(path[0]),
                    'st_size': 1024,
                    'st_uid': os.getuid(),
                    'st_gid': os.getgid()}

        try:
            path[1] = int(path[1])
        except ValueError:
            # Not a post folder
            raise fuse.FuseOSError(errno.ENOENT)

        if path[1] < 1 or path[1] > self.threads[path[0]]['posts']:
            # Post index out of range
            raise fuse.FuseOSError(errno.ENOENT)

        if not path[2]:
            # Post folder
            # TODO fetch post for accurate times
            return {'st_mode': (stat.S_IFDIR | 0555),
                    'st_ctime': self.threads[path[0]]['last_modified'],
                    'st_mtime': self.threads[path[0]]['last_modified'],
                    'st_atime': self.threads[path[0]]['last_modified'],
                    'st_uid': os.getuid(),
                    'st_gid': os.getgid()}

        if path[2] not in ('poster', 'email', 'body'):
            raise fuse.FuseOSError(errno.ENOENT)

        # Post data file
        # TODO fetch post for accurate times
        return {'st_mode': (stat.S_IFREG | 0444),
                'st_ctime': self.threads[path[0]]['last_modified'],
                'st_mtime': self.threads[path[0]]['last_modified'],
                'st_atime': self.threads[path[0]]['last_modified'],
                'st_size': 1024 * 1024,
                'st_uid': os.getuid(),
                'st_gid': os.getgid()}
   
    def read(self, path, size, offset, fh):
        path = parse_path(path)

        if path[0] not in self.threads or not path[1]:
            raise fuse.FuseOSError(errno.ENOENT)

        if path[1] == 'title':
            return self.threads[path[0]]['title'][offset : offset + size]

        if path[2] not in ('poster', 'email', 'body'):
            raise fuse.FuseOSError(errno.ENOENT)

        try:
            int(path[1])
        except ValueError:
            raise fuse.FuseOSError(errno.ENOENT)

        r = urllib2.urlopen(self.post_url % (path[0], path[1]))
        post = json.loads(r.read())[path[1]]
        r.close()

        if path[2] == 'body':
            body = post['com'] + '\n'
            return body[offset : offset + size]
       
        name, email = parse_name(post['name'])
        if path[2] == 'name':
            if name:
                name = name + '\n'
            return name[offset : offset + size]
        else:
            if email:
                email = email + '\n'
            return email[offset : offset + size]
   
    def readdir(self, path, fh):
        self._get_subject_txt()
        path = parse_path(path)

        if not path[0]:
            # Contents of the board directory
            return ['.', '..'] + self.threads.keys()

        if path[0] not in self.threads:
            raise fuse.FuseOSError(errno.ENOENT)

        if not path[1]:
            # Contents of a thread directory
            return ['.', '..', 'title'] + \
                   [str(i + 1) for i in range(self.threads[path[0]]['posts'])]

        if path[1] == 'title':
            raise fuse.FuseOSError(errno.ENOTDIR)

        try:
            path[1] = int(path[1])
        except ValueError:
            raise fuse.FuseOSError(errno.ENOENT)

        if path[1] < 0 or path[1] > self.threads[path[0]]['posts']:
            raise fuse.FuseOSError(errno.ENOENT)

        return ['.', '..', 'poster', 'email', 'body']


if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('-b', '--board', action='store',
                        help='board')
    parser.add_argument('mountpoint', action='store',
                        help='mount point')
    parser.add_argument('-f', '--foreground', action='store_true',
                        help='run in the foreground (useful for debugging)')
    args = parser.parse_args()

    fuse = fuse.FUSE(ProgFS(args.board or 'prog'),
                     args.mountpoint,
                     foreground=args.foreground)

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List